@catbee/utils 2.0.0-next.0 → 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/LICENSE +1 -1
- package/README.md +102 -52
- package/array/index.cjs +215 -74
- package/array/index.d.ts +345 -2
- package/array/index.mjs +201 -74
- package/async/index.cjs +116 -39
- package/async/index.d.ts +292 -2
- package/async/index.mjs +116 -40
- package/cache/index.cjs +2 -2
- package/cache/index.d.ts +156 -2
- package/cache/index.mjs +3 -3
- package/config/index.cjs +80 -66
- package/config/index.d.ts +65 -3
- package/config/index.mjs +77 -65
- package/context-store/index.cjs +2 -3
- package/context-store/index.d.ts +193 -2
- package/context-store/index.mjs +2 -3
- package/crypto/index.cjs +55 -5
- package/crypto/index.d.ts +225 -2
- package/crypto/index.mjs +52 -7
- package/date/index.cjs +676 -2
- package/date/index.d.ts +676 -2
- package/date/index.mjs +665 -3
- package/decorator/index.cjs +2172 -0
- package/{decorators/decorators.utils.d.ts → decorator/index.d.ts} +58 -54
- package/decorator/index.mjs +2131 -0
- package/{dir → directory}/index.cjs +5 -4
- package/{dir/dir.utils.d.ts → directory/index.d.ts} +24 -21
- package/{dir → directory}/index.mjs +5 -4
- package/env/index.cjs +100 -68
- package/env/index.d.ts +391 -2
- package/env/index.mjs +100 -68
- package/exception/index.cjs +1 -1
- package/exception/index.d.ts +233 -2
- package/exception/index.mjs +1 -1
- package/fs/index.cjs +71 -37
- package/fs/index.d.ts +206 -2
- package/fs/index.mjs +65 -35
- package/http-status-codes/index.cjs +1 -1
- package/http-status-codes/index.d.ts +268 -2
- package/http-status-codes/index.mjs +1 -1
- package/id/index.cjs +1 -1
- package/id/index.d.ts +38 -2
- package/id/index.mjs +1 -1
- package/index.cjs +13 -13
- package/index.d.ts +5 -5
- package/index.mjs +5 -5
- package/logger/index.cjs +13 -15
- package/logger/index.d.ts +190 -2
- package/logger/index.mjs +14 -16
- package/middleware/index.cjs +1 -1
- package/middleware/index.d.ts +104 -2
- package/middleware/index.mjs +1 -1
- package/object/index.cjs +379 -0
- package/{obj/obj.utils.d.ts → object/index.d.ts} +73 -33
- package/object/index.mjs +360 -0
- package/package.json +41 -23
- package/performance/index.cjs +4 -4
- package/performance/index.d.ts +139 -2
- package/performance/index.mjs +4 -4
- package/request/index.cjs +37 -25
- package/request/index.d.ts +242 -3
- package/request/index.mjs +37 -25
- package/response/index.cjs +1 -1
- package/response/index.d.ts +319 -3
- package/response/index.mjs +1 -1
- package/server/index.cjs +249 -146
- package/server/index.d.ts +866 -5
- package/server/index.mjs +248 -144
- package/stream/index.cjs +1 -1
- package/stream/index.d.ts +91 -2
- package/stream/index.mjs +1 -1
- package/string/index.cjs +34 -1
- package/string/index.d.ts +146 -2
- package/string/index.mjs +31 -2
- package/type/index.cjs +19 -2
- package/type/index.d.ts +144 -2
- package/type/index.mjs +17 -3
- package/types/index.cjs +1 -1
- package/types/index.d.ts +775 -5
- package/types/index.mjs +1 -1
- package/url/index.cjs +63 -5
- package/url/index.d.ts +200 -2
- package/url/index.mjs +59 -6
- package/{validate → validation}/index.cjs +91 -44
- package/{validate/validate.utils.d.ts → validation/index.d.ts} +33 -24
- package/{validate → validation}/index.mjs +87 -44
- 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/index.cjs +0 -913
- package/decorators/index.d.ts +0 -25
- package/decorators/index.mjs +0 -872
- package/dir/index.d.ts +0 -25
- 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/index.cjs +0 -317
- package/obj/index.d.ts +0 -25
- package/obj/index.mjs +0 -301
- 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/decorators/index.mjs
DELETED
|
@@ -1,872 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The MIT License
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
|
|
5
|
-
*
|
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
-
* in the Software without restriction, including without limitation the rights
|
|
9
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
* furnished to do so, subject to the following conditions:
|
|
12
|
-
*
|
|
13
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
* copies or substantial portions of the Software.
|
|
15
|
-
*
|
|
16
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
* SOFTWARE.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import 'reflect-metadata';
|
|
26
|
-
import { getLogger } from '@catbee/utils/logger';
|
|
27
|
-
import { createFinalErrorResponse } from '@catbee/utils/response';
|
|
28
|
-
import { HttpStatusCodes } from '@catbee/utils/http-status-codes';
|
|
29
|
-
import { TTLCache } from '@catbee/utils/cache';
|
|
30
|
-
import { BadRequestException } from '@catbee/utils/exception';
|
|
31
|
-
import { optionalRequire } from '@catbee/utils/async';
|
|
32
|
-
import { DependencyErrors } from '@catbee/utils/server';
|
|
33
|
-
|
|
34
|
-
var __defProp = Object.defineProperty;
|
|
35
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
36
|
-
var ROUTES_KEY = Symbol("routes");
|
|
37
|
-
var MIDDLEWARE_KEY = Symbol("middlewares");
|
|
38
|
-
var PARAMS_KEY = Symbol("params");
|
|
39
|
-
var HTTP_CODE_KEY = Symbol("httpCode");
|
|
40
|
-
var HEADER_KEY = Symbol("headers");
|
|
41
|
-
var BEFORE_KEY = Symbol("before");
|
|
42
|
-
var AFTER_KEY = Symbol("after");
|
|
43
|
-
var ROLES_KEY = Symbol("roles");
|
|
44
|
-
var REDIRECT_KEY = Symbol("redirect");
|
|
45
|
-
var CACHE_KEY = Symbol("cache");
|
|
46
|
-
var RATE_LIMIT_KEY = Symbol("rateLimit");
|
|
47
|
-
var CONTENT_TYPE_KEY = Symbol("contentType");
|
|
48
|
-
var VERSION_KEY = Symbol("version");
|
|
49
|
-
var TIMEOUT_KEY = Symbol("timeout");
|
|
50
|
-
var LOG_KEY = Symbol("log");
|
|
51
|
-
var RateLimiterCache = class RateLimiterCache2 {
|
|
52
|
-
static {
|
|
53
|
-
__name(this, "RateLimiterCache");
|
|
54
|
-
}
|
|
55
|
-
rateLimit;
|
|
56
|
-
cache;
|
|
57
|
-
constructor(maxSize = 100, ttlMs = 5 * 60 * 1e3) {
|
|
58
|
-
this.cache = new TTLCache({
|
|
59
|
-
maxSize,
|
|
60
|
-
ttlMs
|
|
61
|
-
});
|
|
62
|
-
const rateLimitModule = optionalRequire("express-rate-limit");
|
|
63
|
-
if (rateLimitModule) this.rateLimit = rateLimitModule.rateLimit;
|
|
64
|
-
}
|
|
65
|
-
generateKey(options) {
|
|
66
|
-
return `${options.max}:${options.windowMs}:${options.standardHeaders}:${options.legacyHeaders}`;
|
|
67
|
-
}
|
|
68
|
-
get(options) {
|
|
69
|
-
const key = this.generateKey(options);
|
|
70
|
-
const cached = this.cache.get(key);
|
|
71
|
-
if (cached) {
|
|
72
|
-
return cached.limiter;
|
|
73
|
-
}
|
|
74
|
-
if (!this.rateLimit) {
|
|
75
|
-
throw new Error(DependencyErrors["express-rate-limit"]);
|
|
76
|
-
}
|
|
77
|
-
const limiter = this.rateLimit({
|
|
78
|
-
...options,
|
|
79
|
-
handler: /* @__PURE__ */ __name((req, res) => {
|
|
80
|
-
const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.TOO_MANY_REQUESTS, "Too Many Requests");
|
|
81
|
-
res.status(HttpStatusCodes.TOO_MANY_REQUESTS).json(errorResponse);
|
|
82
|
-
}, "handler")
|
|
83
|
-
});
|
|
84
|
-
this.cache.set(key, {
|
|
85
|
-
limiter,
|
|
86
|
-
config: key
|
|
87
|
-
});
|
|
88
|
-
return limiter;
|
|
89
|
-
}
|
|
90
|
-
clear() {
|
|
91
|
-
this.cache.clear();
|
|
92
|
-
}
|
|
93
|
-
size() {
|
|
94
|
-
return this.cache.size();
|
|
95
|
-
}
|
|
96
|
-
destroy() {
|
|
97
|
-
this.cache.destroy();
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
var rateLimiterCache = new RateLimiterCache();
|
|
101
|
-
var DIContainer = class {
|
|
102
|
-
static {
|
|
103
|
-
__name(this, "DIContainer");
|
|
104
|
-
}
|
|
105
|
-
instances = /* @__PURE__ */ new Map();
|
|
106
|
-
constructing = /* @__PURE__ */ new Map();
|
|
107
|
-
propertyInjections = /* @__PURE__ */ new Map();
|
|
108
|
-
register(target) {
|
|
109
|
-
if (!this.instances.has(target) && !this.constructing.has(target)) ;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Register a property injection to be resolved when the target class is instantiated
|
|
113
|
-
*/
|
|
114
|
-
registerPropertyInjection(target, propertyKey, injectClass) {
|
|
115
|
-
const targetClass = target.constructor;
|
|
116
|
-
if (!this.propertyInjections.has(targetClass)) {
|
|
117
|
-
this.propertyInjections.set(targetClass, []);
|
|
118
|
-
}
|
|
119
|
-
this.propertyInjections.get(targetClass).push({
|
|
120
|
-
targetClass: injectClass,
|
|
121
|
-
propertyKey
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
get(target) {
|
|
125
|
-
if (this.instances.has(target)) {
|
|
126
|
-
return this.instances.get(target);
|
|
127
|
-
}
|
|
128
|
-
if (this.constructing.has(target)) {
|
|
129
|
-
return this.constructing.get(target);
|
|
130
|
-
}
|
|
131
|
-
let proxy = {};
|
|
132
|
-
this.constructing.set(target, proxy);
|
|
133
|
-
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
134
|
-
const dependencies = paramTypes.map((dep) => this.get(dep));
|
|
135
|
-
const instance = new target(...dependencies);
|
|
136
|
-
this.applyPropertyInjections(target, instance);
|
|
137
|
-
Object.assign(proxy, instance);
|
|
138
|
-
this.instances.set(target, proxy);
|
|
139
|
-
this.constructing.delete(target);
|
|
140
|
-
Object.setPrototypeOf(proxy, target.prototype);
|
|
141
|
-
return proxy;
|
|
142
|
-
}
|
|
143
|
-
applyPropertyInjections(targetClass, instance) {
|
|
144
|
-
const injections = this.propertyInjections.get(targetClass) || [];
|
|
145
|
-
for (const injection of injections) {
|
|
146
|
-
const dependency = this.get(injection.targetClass);
|
|
147
|
-
instance[injection.propertyKey] = dependency;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
clear() {
|
|
151
|
-
this.instances.clear();
|
|
152
|
-
this.constructing.clear();
|
|
153
|
-
this.propertyInjections.clear();
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
var diContainer = new DIContainer();
|
|
157
|
-
function normalizeHeaderValue(value) {
|
|
158
|
-
if (typeof value === "undefined") return void 0;
|
|
159
|
-
if (typeof value === "string") return value;
|
|
160
|
-
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
161
|
-
return value;
|
|
162
|
-
}
|
|
163
|
-
return String(value);
|
|
164
|
-
}
|
|
165
|
-
__name(normalizeHeaderValue, "normalizeHeaderValue");
|
|
166
|
-
function Injectable() {
|
|
167
|
-
return (target) => {
|
|
168
|
-
Reflect.defineMetadata("injectable", true, target);
|
|
169
|
-
diContainer.register(target);
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
__name(Injectable, "Injectable");
|
|
173
|
-
function Inject(targetClass) {
|
|
174
|
-
return (target, propertyKey) => {
|
|
175
|
-
diContainer.registerPropertyInjection(target, propertyKey, targetClass);
|
|
176
|
-
Object.defineProperty(target, propertyKey, {
|
|
177
|
-
configurable: true,
|
|
178
|
-
get: /* @__PURE__ */ __name(function() {
|
|
179
|
-
const value = Object.getOwnPropertyDescriptor(this, propertyKey)?.value;
|
|
180
|
-
if (value !== void 0) return value;
|
|
181
|
-
const injectedValue = diContainer.get(targetClass);
|
|
182
|
-
Object.defineProperty(this, propertyKey, {
|
|
183
|
-
value: injectedValue,
|
|
184
|
-
writable: true,
|
|
185
|
-
configurable: true
|
|
186
|
-
});
|
|
187
|
-
return injectedValue;
|
|
188
|
-
}, "get"),
|
|
189
|
-
set: /* @__PURE__ */ __name(function(value) {
|
|
190
|
-
Object.defineProperty(this, propertyKey, {
|
|
191
|
-
value,
|
|
192
|
-
writable: true,
|
|
193
|
-
configurable: true
|
|
194
|
-
});
|
|
195
|
-
}, "set")
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
__name(Inject, "Inject");
|
|
200
|
-
function inject(targetClass) {
|
|
201
|
-
return diContainer.get(targetClass);
|
|
202
|
-
}
|
|
203
|
-
__name(inject, "inject");
|
|
204
|
-
function createRouteDecorator(method) {
|
|
205
|
-
return (path) => {
|
|
206
|
-
return (target, propertyKey, _descriptor) => {
|
|
207
|
-
const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
|
|
208
|
-
routes.push({
|
|
209
|
-
path,
|
|
210
|
-
method,
|
|
211
|
-
handlerName: propertyKey
|
|
212
|
-
});
|
|
213
|
-
Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
__name(createRouteDecorator, "createRouteDecorator");
|
|
218
|
-
var Get = createRouteDecorator("get");
|
|
219
|
-
var Post = createRouteDecorator("post");
|
|
220
|
-
var Put = createRouteDecorator("put");
|
|
221
|
-
var Patch = createRouteDecorator("patch");
|
|
222
|
-
var Delete = createRouteDecorator("delete");
|
|
223
|
-
var Options = createRouteDecorator("options");
|
|
224
|
-
var Head = createRouteDecorator("head");
|
|
225
|
-
var Trace = createRouteDecorator("trace");
|
|
226
|
-
var Connect = createRouteDecorator("connect");
|
|
227
|
-
function Controller(basePath) {
|
|
228
|
-
return (target) => {
|
|
229
|
-
Reflect.defineMetadata("basePath", basePath, target);
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
__name(Controller, "Controller");
|
|
233
|
-
function Use(...middlewares) {
|
|
234
|
-
return (target, propertyKey, _descriptor) => {
|
|
235
|
-
if (typeof propertyKey === "undefined") {
|
|
236
|
-
const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target) || [];
|
|
237
|
-
Reflect.defineMetadata(MIDDLEWARE_KEY, [
|
|
238
|
-
...existing,
|
|
239
|
-
...middlewares
|
|
240
|
-
], target);
|
|
241
|
-
} else {
|
|
242
|
-
const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
|
|
243
|
-
Reflect.defineMetadata(MIDDLEWARE_KEY, [
|
|
244
|
-
...existing,
|
|
245
|
-
...middlewares
|
|
246
|
-
], target, propertyKey);
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
__name(Use, "Use");
|
|
251
|
-
function defineParamMetadata(target, propertyKey, parameterIndex, type, key) {
|
|
252
|
-
const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
|
|
253
|
-
params.push({
|
|
254
|
-
index: parameterIndex,
|
|
255
|
-
type,
|
|
256
|
-
key
|
|
257
|
-
});
|
|
258
|
-
params.sort((a, b) => a.index - b.index);
|
|
259
|
-
Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
|
|
260
|
-
}
|
|
261
|
-
__name(defineParamMetadata, "defineParamMetadata");
|
|
262
|
-
function createParamDecorator(type, key) {
|
|
263
|
-
return (paramKey) => {
|
|
264
|
-
return (target, propertyKey, parameterIndex) => {
|
|
265
|
-
defineParamMetadata(target, propertyKey, parameterIndex, type, paramKey ?? key);
|
|
266
|
-
};
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
__name(createParamDecorator, "createParamDecorator");
|
|
270
|
-
function createParamDecoratorWithoutParam(type) {
|
|
271
|
-
return () => {
|
|
272
|
-
return (target, propertyKey, parameterIndex) => {
|
|
273
|
-
defineParamMetadata(target, propertyKey, parameterIndex, type, void 0);
|
|
274
|
-
};
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
__name(createParamDecoratorWithoutParam, "createParamDecoratorWithoutParam");
|
|
278
|
-
function createApiUrlParamDecorator(type, key) {
|
|
279
|
-
return (paramKey, options) => {
|
|
280
|
-
return (target, propertyKey, parameterIndex) => {
|
|
281
|
-
const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
|
|
282
|
-
let paramOptions = void 0;
|
|
283
|
-
if (typeof options === "object") {
|
|
284
|
-
paramOptions = {};
|
|
285
|
-
paramOptions.type = "string";
|
|
286
|
-
paramOptions.dataType = "single";
|
|
287
|
-
paramOptions.delimiter = ",";
|
|
288
|
-
paramOptions.required = false;
|
|
289
|
-
paramOptions.throwError = true;
|
|
290
|
-
paramOptions = {
|
|
291
|
-
...paramOptions,
|
|
292
|
-
...options
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
params.push({
|
|
296
|
-
index: parameterIndex,
|
|
297
|
-
type,
|
|
298
|
-
key: paramKey || key,
|
|
299
|
-
options: paramOptions
|
|
300
|
-
});
|
|
301
|
-
params.sort((a, b) => a.index - b.index);
|
|
302
|
-
Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
|
|
303
|
-
};
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
__name(createApiUrlParamDecorator, "createApiUrlParamDecorator");
|
|
307
|
-
var Query = createApiUrlParamDecorator("query");
|
|
308
|
-
var Param = createApiUrlParamDecorator("param");
|
|
309
|
-
var Body = createParamDecorator("body");
|
|
310
|
-
var ReqLogger = createParamDecoratorWithoutParam("logger");
|
|
311
|
-
var ReqId = createParamDecoratorWithoutParam("reqId");
|
|
312
|
-
var ReqHeader = createParamDecorator("reqHeader");
|
|
313
|
-
var ReqCookie = createParamDecorator("cookie");
|
|
314
|
-
var Req = createParamDecoratorWithoutParam("req");
|
|
315
|
-
var Res = createParamDecoratorWithoutParam("res");
|
|
316
|
-
function HttpCode(status) {
|
|
317
|
-
return (target, propertyKey, _descriptor) => {
|
|
318
|
-
Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
__name(HttpCode, "HttpCode");
|
|
322
|
-
function Header(name, value) {
|
|
323
|
-
return Headers(name, value);
|
|
324
|
-
}
|
|
325
|
-
__name(Header, "Header");
|
|
326
|
-
function Headers(headers, value) {
|
|
327
|
-
return (target, propertyKey) => {
|
|
328
|
-
if (typeof propertyKey === "undefined") {
|
|
329
|
-
const existing = Reflect.getMetadata(HEADER_KEY, target) || {};
|
|
330
|
-
const newHeaders = typeof headers === "string" ? {
|
|
331
|
-
[headers]: value
|
|
332
|
-
} : headers;
|
|
333
|
-
Reflect.defineMetadata(HEADER_KEY, {
|
|
334
|
-
...existing,
|
|
335
|
-
...newHeaders
|
|
336
|
-
}, target);
|
|
337
|
-
} else {
|
|
338
|
-
const existing = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
|
|
339
|
-
const newHeaders = typeof headers === "string" ? {
|
|
340
|
-
[headers]: value
|
|
341
|
-
} : headers;
|
|
342
|
-
Reflect.defineMetadata(HEADER_KEY, {
|
|
343
|
-
...existing,
|
|
344
|
-
...newHeaders
|
|
345
|
-
}, target, propertyKey);
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
__name(Headers, "Headers");
|
|
350
|
-
function Before(fn) {
|
|
351
|
-
return (target, propertyKey, _descriptor) => {
|
|
352
|
-
if (typeof propertyKey === "undefined") {
|
|
353
|
-
const hooks = Reflect.getMetadata(BEFORE_KEY, target) || [];
|
|
354
|
-
hooks.push(fn);
|
|
355
|
-
Reflect.defineMetadata(BEFORE_KEY, hooks, target);
|
|
356
|
-
} else {
|
|
357
|
-
const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
|
|
358
|
-
hooks.push(fn);
|
|
359
|
-
Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
|
|
360
|
-
}
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
__name(Before, "Before");
|
|
364
|
-
function After(fn) {
|
|
365
|
-
return (target, propertyKey, _descriptor) => {
|
|
366
|
-
if (typeof propertyKey === "undefined") {
|
|
367
|
-
const hooks = Reflect.getMetadata(AFTER_KEY, target) || [];
|
|
368
|
-
hooks.push(fn);
|
|
369
|
-
Reflect.defineMetadata(AFTER_KEY, hooks, target);
|
|
370
|
-
} else {
|
|
371
|
-
const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
|
|
372
|
-
hooks.push(fn);
|
|
373
|
-
Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
__name(After, "After");
|
|
378
|
-
function Roles(...roles) {
|
|
379
|
-
return (target, propertyKey, _descriptor) => {
|
|
380
|
-
if (typeof propertyKey === "undefined") {
|
|
381
|
-
Reflect.defineMetadata(ROLES_KEY, roles, target);
|
|
382
|
-
} else {
|
|
383
|
-
Reflect.defineMetadata(ROLES_KEY, roles, target, propertyKey);
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
__name(Roles, "Roles");
|
|
388
|
-
function Redirect(url, statusCode = 302) {
|
|
389
|
-
return (target, propertyKey, descriptor) => {
|
|
390
|
-
Reflect.defineMetadata(REDIRECT_KEY, {
|
|
391
|
-
url,
|
|
392
|
-
statusCode
|
|
393
|
-
}, target, propertyKey);
|
|
394
|
-
return descriptor;
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
__name(Redirect, "Redirect");
|
|
398
|
-
function Cache(ttlSeconds) {
|
|
399
|
-
return (target, propertyKey, _descriptor) => {
|
|
400
|
-
if (typeof propertyKey === "undefined") {
|
|
401
|
-
Reflect.defineMetadata(CACHE_KEY, {
|
|
402
|
-
ttlSeconds
|
|
403
|
-
}, target);
|
|
404
|
-
} else {
|
|
405
|
-
Reflect.defineMetadata(CACHE_KEY, {
|
|
406
|
-
ttlSeconds
|
|
407
|
-
}, target, propertyKey);
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
__name(Cache, "Cache");
|
|
412
|
-
function RateLimit(options) {
|
|
413
|
-
const opts = {
|
|
414
|
-
standardHeaders: true,
|
|
415
|
-
legacyHeaders: false,
|
|
416
|
-
...options
|
|
417
|
-
};
|
|
418
|
-
return (target, propertyKey, _descriptor) => {
|
|
419
|
-
if (typeof propertyKey === "undefined") {
|
|
420
|
-
Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target);
|
|
421
|
-
} else {
|
|
422
|
-
Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target, propertyKey);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
__name(RateLimit, "RateLimit");
|
|
427
|
-
function ContentType(type) {
|
|
428
|
-
return (target, propertyKey, _descriptor) => {
|
|
429
|
-
if (typeof propertyKey === "undefined") {
|
|
430
|
-
Reflect.defineMetadata(CONTENT_TYPE_KEY, {
|
|
431
|
-
type
|
|
432
|
-
}, target);
|
|
433
|
-
} else {
|
|
434
|
-
Reflect.defineMetadata(CONTENT_TYPE_KEY, {
|
|
435
|
-
type
|
|
436
|
-
}, target, propertyKey);
|
|
437
|
-
}
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
__name(ContentType, "ContentType");
|
|
441
|
-
function Version(version, options) {
|
|
442
|
-
const opts = {
|
|
443
|
-
addPrefix: true,
|
|
444
|
-
addHeader: true,
|
|
445
|
-
headerName: "X-API-Version",
|
|
446
|
-
...options
|
|
447
|
-
};
|
|
448
|
-
return (target, propertyKey, _descriptor) => {
|
|
449
|
-
if (typeof propertyKey === "undefined") {
|
|
450
|
-
Reflect.defineMetadata(VERSION_KEY, {
|
|
451
|
-
version,
|
|
452
|
-
options: opts
|
|
453
|
-
}, target);
|
|
454
|
-
} else {
|
|
455
|
-
Reflect.defineMetadata(VERSION_KEY, {
|
|
456
|
-
version,
|
|
457
|
-
options: opts
|
|
458
|
-
}, target, propertyKey);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
__name(Version, "Version");
|
|
463
|
-
function Timeout(ms) {
|
|
464
|
-
return (target, propertyKey, _descriptor) => {
|
|
465
|
-
if (typeof propertyKey === "undefined") {
|
|
466
|
-
Reflect.defineMetadata(TIMEOUT_KEY, {
|
|
467
|
-
ms
|
|
468
|
-
}, target);
|
|
469
|
-
} else {
|
|
470
|
-
Reflect.defineMetadata(TIMEOUT_KEY, {
|
|
471
|
-
ms
|
|
472
|
-
}, target, propertyKey);
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
__name(Timeout, "Timeout");
|
|
477
|
-
function Log(options) {
|
|
478
|
-
return (target, propertyKey, _descriptor) => {
|
|
479
|
-
const config = {
|
|
480
|
-
logEntry: true,
|
|
481
|
-
logExit: true,
|
|
482
|
-
logBody: false,
|
|
483
|
-
logParams: false,
|
|
484
|
-
logResponse: false,
|
|
485
|
-
...options
|
|
486
|
-
};
|
|
487
|
-
if (typeof propertyKey === "undefined") {
|
|
488
|
-
Reflect.defineMetadata(LOG_KEY, config, target);
|
|
489
|
-
} else {
|
|
490
|
-
Reflect.defineMetadata(LOG_KEY, config, target, propertyKey);
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
__name(Log, "Log");
|
|
495
|
-
function registerControllers(router, controllers) {
|
|
496
|
-
controllers.forEach((ControllerClass) => {
|
|
497
|
-
if (!Reflect.getMetadata("injectable", ControllerClass)) {
|
|
498
|
-
Reflect.defineMetadata("injectable", true, ControllerClass);
|
|
499
|
-
diContainer.register(ControllerClass);
|
|
500
|
-
}
|
|
501
|
-
const instance = diContainer.get(ControllerClass);
|
|
502
|
-
let basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
|
|
503
|
-
const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
|
|
504
|
-
const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
|
|
505
|
-
const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
|
|
506
|
-
const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
|
|
507
|
-
const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
|
|
508
|
-
const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
|
|
509
|
-
const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
|
|
510
|
-
const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
|
|
511
|
-
const controllerMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, ControllerClass) || [];
|
|
512
|
-
const controllerBeforeHooks = Reflect.getMetadata(BEFORE_KEY, ControllerClass) || [];
|
|
513
|
-
const controllerAfterHooks = Reflect.getMetadata(AFTER_KEY, ControllerClass) || [];
|
|
514
|
-
const controllerContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass);
|
|
515
|
-
if (controllerVersion?.options?.addPrefix) {
|
|
516
|
-
basePath = `/${controllerVersion.version}${basePath || ""}`;
|
|
517
|
-
}
|
|
518
|
-
routes.forEach(({ path, method, handlerName }) => {
|
|
519
|
-
const methodMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
|
|
520
|
-
const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
|
|
521
|
-
const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
|
|
522
|
-
const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
|
|
523
|
-
const headers = {
|
|
524
|
-
...controllerHeaders,
|
|
525
|
-
...methodHeaders
|
|
526
|
-
};
|
|
527
|
-
const middlewares = [
|
|
528
|
-
...controllerMiddlewares,
|
|
529
|
-
...methodMiddlewares
|
|
530
|
-
];
|
|
531
|
-
const methodBeforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
|
|
532
|
-
const methodAfterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
|
|
533
|
-
const beforeHooks = [
|
|
534
|
-
...controllerBeforeHooks,
|
|
535
|
-
...methodBeforeHooks
|
|
536
|
-
];
|
|
537
|
-
const afterHooks = [
|
|
538
|
-
...methodAfterHooks,
|
|
539
|
-
...controllerAfterHooks
|
|
540
|
-
];
|
|
541
|
-
const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
|
|
542
|
-
const methodContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
|
|
543
|
-
const contentType = methodContentType || controllerContentType;
|
|
544
|
-
const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
|
|
545
|
-
const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
|
|
546
|
-
const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
|
|
547
|
-
const methodVersion = Reflect.getMetadata(VERSION_KEY, instance, handlerName);
|
|
548
|
-
const version = methodVersion || controllerVersion;
|
|
549
|
-
const timeout = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
|
|
550
|
-
const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
|
|
551
|
-
let rateLimiter = null;
|
|
552
|
-
if (rateLimitOptions) {
|
|
553
|
-
try {
|
|
554
|
-
rateLimiter = rateLimiterCache.get(rateLimitOptions);
|
|
555
|
-
} catch (err) {
|
|
556
|
-
getLogger().warn({
|
|
557
|
-
err
|
|
558
|
-
}, "express-rate-limit not available, skipping rate limiting for this route");
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
let finalPath = path;
|
|
562
|
-
if (methodVersion?.options?.addPrefix && methodVersion.version !== controllerVersion?.version) {
|
|
563
|
-
finalPath = `/${methodVersion.version}${path}`;
|
|
564
|
-
}
|
|
565
|
-
const handler = /* @__PURE__ */ __name(async (req, res, next) => {
|
|
566
|
-
req["startTime"] = Date.now();
|
|
567
|
-
let timeoutId;
|
|
568
|
-
let timedOut = false;
|
|
569
|
-
try {
|
|
570
|
-
if (timeout) {
|
|
571
|
-
timeoutId = setTimeout(() => {
|
|
572
|
-
if (!res.headersSent && !timedOut) {
|
|
573
|
-
timedOut = true;
|
|
574
|
-
const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
|
|
575
|
-
res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
|
|
576
|
-
}
|
|
577
|
-
}, timeout.ms);
|
|
578
|
-
}
|
|
579
|
-
if (timedOut) return;
|
|
580
|
-
if (rateLimiter) {
|
|
581
|
-
await new Promise((resolve, reject) => {
|
|
582
|
-
rateLimiter(req, res, (err) => {
|
|
583
|
-
if (err) reject(err);
|
|
584
|
-
else resolve();
|
|
585
|
-
});
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
if (!res.headersSent && contentType) {
|
|
589
|
-
res.setHeader("Content-Type", contentType.type);
|
|
590
|
-
}
|
|
591
|
-
if (version?.options?.addHeader && version?.options?.headerName && version?.version) {
|
|
592
|
-
if (!res.headersSent) {
|
|
593
|
-
res.setHeader(version.options.headerName, version.version);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
if (cache && !res.headersSent) {
|
|
597
|
-
res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
|
|
598
|
-
}
|
|
599
|
-
if (logConfig?.logEntry) {
|
|
600
|
-
const logger = getLogger();
|
|
601
|
-
const logData = {
|
|
602
|
-
method: req.method,
|
|
603
|
-
url: req.originalUrl || req.url,
|
|
604
|
-
userAgent: req.get("User-Agent")
|
|
605
|
-
};
|
|
606
|
-
if (logConfig.logParams) {
|
|
607
|
-
logData.params = req.params;
|
|
608
|
-
logData.query = req.query;
|
|
609
|
-
}
|
|
610
|
-
if (logConfig.logBody) logData.body = req.body;
|
|
611
|
-
logger.info({
|
|
612
|
-
entry: logData
|
|
613
|
-
}, "Route Entry:");
|
|
614
|
-
}
|
|
615
|
-
if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
|
|
616
|
-
const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
|
|
617
|
-
res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
|
|
618
|
-
if (timeoutId) {
|
|
619
|
-
clearTimeout(timeoutId);
|
|
620
|
-
}
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
if (redirect && redirect.url) {
|
|
624
|
-
if (timeoutId) {
|
|
625
|
-
clearTimeout(timeoutId);
|
|
626
|
-
}
|
|
627
|
-
return res.redirect(redirect.statusCode, redirect.url);
|
|
628
|
-
}
|
|
629
|
-
for (const fn of beforeHooks) await fn(req, res);
|
|
630
|
-
const args = [];
|
|
631
|
-
if (params.length) {
|
|
632
|
-
params.forEach(({ index, type, key, options }) => {
|
|
633
|
-
let rawValue;
|
|
634
|
-
switch (type) {
|
|
635
|
-
case "query":
|
|
636
|
-
rawValue = key ? req.query[key] : req.query;
|
|
637
|
-
args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
|
|
638
|
-
break;
|
|
639
|
-
case "param":
|
|
640
|
-
rawValue = key ? req.params[key] : req.params;
|
|
641
|
-
args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
|
|
642
|
-
break;
|
|
643
|
-
case "body":
|
|
644
|
-
args[index] = key ? req.body?.[key] : req.body;
|
|
645
|
-
break;
|
|
646
|
-
case "req":
|
|
647
|
-
args[index] = req;
|
|
648
|
-
break;
|
|
649
|
-
case "res":
|
|
650
|
-
args[index] = res;
|
|
651
|
-
break;
|
|
652
|
-
case "logger":
|
|
653
|
-
args[index] = getLogger();
|
|
654
|
-
break;
|
|
655
|
-
case "reqHeader":
|
|
656
|
-
args[index] = key ? req.headers[key.toLowerCase()] : req.headers;
|
|
657
|
-
break;
|
|
658
|
-
case "reqId":
|
|
659
|
-
args[index] = req.headers["x-request-id"] || req?.id || void 0;
|
|
660
|
-
break;
|
|
661
|
-
case "cookie":
|
|
662
|
-
args[index] = key ? req.cookies?.[key] : req.cookies;
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
const result = instance[handlerName](...args);
|
|
668
|
-
const awaited = result instanceof Promise ? await result : result;
|
|
669
|
-
if (timeoutId) {
|
|
670
|
-
clearTimeout(timeoutId);
|
|
671
|
-
}
|
|
672
|
-
if (timedOut) return;
|
|
673
|
-
if (redirect && awaited && typeof awaited === "object" && "url" in awaited) {
|
|
674
|
-
const redirectUrl = awaited.url;
|
|
675
|
-
const redirectStatus = awaited.statusCode || redirect.statusCode;
|
|
676
|
-
return res.redirect(redirectStatus, redirectUrl);
|
|
677
|
-
}
|
|
678
|
-
if (!res.headersSent && typeof awaited !== "undefined") {
|
|
679
|
-
if (httpCode) res.status(httpCode);
|
|
680
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
681
|
-
const normalized = normalizeHeaderValue(v);
|
|
682
|
-
if (typeof normalized !== "undefined") {
|
|
683
|
-
res.set(k, normalized);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
res.json(awaited);
|
|
687
|
-
}
|
|
688
|
-
if (logConfig?.logExit) {
|
|
689
|
-
const logger = getLogger();
|
|
690
|
-
const logData = {
|
|
691
|
-
method: req.method,
|
|
692
|
-
url: req.originalUrl || req.url,
|
|
693
|
-
statusCode: res.statusCode,
|
|
694
|
-
duration: `${Date.now() - req.startTime}ms`
|
|
695
|
-
};
|
|
696
|
-
if (logConfig.logResponse) logData.response = awaited;
|
|
697
|
-
logger.info({
|
|
698
|
-
exit: logData
|
|
699
|
-
}, "Route Exit:");
|
|
700
|
-
}
|
|
701
|
-
for (const fn of afterHooks) await fn(req, res, awaited);
|
|
702
|
-
} catch (err) {
|
|
703
|
-
if (timeoutId) {
|
|
704
|
-
clearTimeout(timeoutId);
|
|
705
|
-
}
|
|
706
|
-
next(err);
|
|
707
|
-
}
|
|
708
|
-
}, "handler");
|
|
709
|
-
router[method](basePath + finalPath, ...middlewares, handler);
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
__name(registerControllers, "registerControllers");
|
|
714
|
-
function applyParamOptions(rawValue, options, key) {
|
|
715
|
-
if (!options) return rawValue;
|
|
716
|
-
let value = rawValue;
|
|
717
|
-
const paramName = key ? `: ${key}` : "";
|
|
718
|
-
if (value === void 0 || value === null || value === "") {
|
|
719
|
-
if ("default" in options) {
|
|
720
|
-
value = options.default;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
if (options.required && (value === void 0 || value === null || value === "")) {
|
|
724
|
-
throw new BadRequestException(`Required parameter missing${paramName}`);
|
|
725
|
-
}
|
|
726
|
-
if (value !== void 0 && value !== null) {
|
|
727
|
-
if (options.dataType === "array") {
|
|
728
|
-
const delimiter = options.delimiter || ",";
|
|
729
|
-
if (typeof value === "string") {
|
|
730
|
-
value = value.split(delimiter).map((v) => v.trim());
|
|
731
|
-
} else if (!Array.isArray(value)) {
|
|
732
|
-
value = [
|
|
733
|
-
value
|
|
734
|
-
];
|
|
735
|
-
}
|
|
736
|
-
if (options.type === "string" && options.pattern) {
|
|
737
|
-
const hasInvalidPattern = value.some((v) => !options.pattern.test(v));
|
|
738
|
-
if (hasInvalidPattern) {
|
|
739
|
-
throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
if (options.type === "number" && options.pattern) {
|
|
743
|
-
const hasInvalidPattern = value.some((v) => !options.pattern.test(String(v)));
|
|
744
|
-
if (hasInvalidPattern) {
|
|
745
|
-
throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
if (options.type === "number" && options.throwError !== false) {
|
|
749
|
-
const hasInvalidNumber = value.some((v) => isNaN(Number(v)));
|
|
750
|
-
if (hasInvalidNumber) {
|
|
751
|
-
throw new BadRequestException(`Type error: expected number array${paramName}`);
|
|
752
|
-
}
|
|
753
|
-
if (options.min !== void 0) {
|
|
754
|
-
const hasBelowMin = value.some((v) => Number(v) < options.min);
|
|
755
|
-
if (hasBelowMin) {
|
|
756
|
-
throw new BadRequestException(`Validation error: number array values must be >= ${options.min}${paramName}`);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
if (options.max !== void 0) {
|
|
760
|
-
const hasAboveMax = value.some((v) => Number(v) > options.max);
|
|
761
|
-
if (hasAboveMax) {
|
|
762
|
-
throw new BadRequestException(`Validation error: number array values must be <= ${options.max}${paramName}`);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
if (options.type === "boolean" && options.throwError !== false) {
|
|
767
|
-
const hasInvalidBoolean = value.some((v) => !isValidBooleanInput(v));
|
|
768
|
-
if (hasInvalidBoolean) {
|
|
769
|
-
throw new BadRequestException(`Type error: expected boolean array${paramName}`);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
if (options.type) {
|
|
773
|
-
value = value.map((v) => convertType(v, options.type || "string"));
|
|
774
|
-
}
|
|
775
|
-
} else if (options.dataType === "object") {
|
|
776
|
-
if (typeof value === "string") {
|
|
777
|
-
try {
|
|
778
|
-
value = JSON.parse(value);
|
|
779
|
-
} catch (_e) {
|
|
780
|
-
if (options.throwError !== false) {
|
|
781
|
-
throw new BadRequestException(`Invalid JSON object${paramName}`);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
} else if (options.type) {
|
|
786
|
-
const originalValue = value;
|
|
787
|
-
value = convertType(value, options.type);
|
|
788
|
-
if (options.throwError === false) {
|
|
789
|
-
if (options.type === "number" && typeof value === "number") {
|
|
790
|
-
if (options.min !== void 0 && value < options.min) {
|
|
791
|
-
value = void 0;
|
|
792
|
-
}
|
|
793
|
-
if (options.max !== void 0 && value > options.max) {
|
|
794
|
-
value = void 0;
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if (options.type === "string" && options.pattern && typeof value === "string" && !options.pattern.test(value)) {
|
|
799
|
-
throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
|
|
800
|
-
} else if (options.type === "number" && options.pattern && typeof value === "number" && !options.pattern.test(String(value))) {
|
|
801
|
-
throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
|
|
802
|
-
}
|
|
803
|
-
if (options.throwError !== false) {
|
|
804
|
-
if (options.type === "number" && typeof value === "number" && isNaN(value)) {
|
|
805
|
-
throw new BadRequestException(`Type error: expected number${paramName}`);
|
|
806
|
-
}
|
|
807
|
-
if (options.type === "number" && typeof value === "number") {
|
|
808
|
-
if (options.min !== void 0 && value < options.min) {
|
|
809
|
-
throw new BadRequestException(`Validation error: number must be >= ${options.min}${paramName}`);
|
|
810
|
-
}
|
|
811
|
-
if (options.max !== void 0 && value > options.max) {
|
|
812
|
-
throw new BadRequestException(`Validation error: number must be <= ${options.max}${paramName}`);
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
if (options.type === "boolean" && !isValidBooleanInput(originalValue)) {
|
|
816
|
-
throw new BadRequestException(`Type error: expected boolean${paramName}`);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
if (options.transform && typeof options.transform === "function") {
|
|
822
|
-
value = options.transform(value);
|
|
823
|
-
}
|
|
824
|
-
if (options.validate && typeof options.validate === "function") {
|
|
825
|
-
if (!options.validate(value)) {
|
|
826
|
-
if (options.throwError !== false) {
|
|
827
|
-
throw new BadRequestException(`Parameter validation failed${paramName}`);
|
|
828
|
-
}
|
|
829
|
-
return void 0;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
return value;
|
|
833
|
-
}
|
|
834
|
-
__name(applyParamOptions, "applyParamOptions");
|
|
835
|
-
function isValidBooleanInput(value) {
|
|
836
|
-
if (typeof value === "boolean") return true;
|
|
837
|
-
if (typeof value === "number") return value === 0 || value === 1;
|
|
838
|
-
if (typeof value === "string") {
|
|
839
|
-
const normalizedValue = value.toLowerCase().trim();
|
|
840
|
-
return [
|
|
841
|
-
"true",
|
|
842
|
-
"false",
|
|
843
|
-
"0",
|
|
844
|
-
"1",
|
|
845
|
-
"yes",
|
|
846
|
-
"no"
|
|
847
|
-
].includes(normalizedValue);
|
|
848
|
-
}
|
|
849
|
-
return false;
|
|
850
|
-
}
|
|
851
|
-
__name(isValidBooleanInput, "isValidBooleanInput");
|
|
852
|
-
function convertType(value, type) {
|
|
853
|
-
if (value === void 0 || value === null) {
|
|
854
|
-
return value;
|
|
855
|
-
}
|
|
856
|
-
switch (type) {
|
|
857
|
-
case "number":
|
|
858
|
-
return Number(value);
|
|
859
|
-
case "boolean":
|
|
860
|
-
if (typeof value === "string") {
|
|
861
|
-
const normalizedValue = value.toLowerCase().trim();
|
|
862
|
-
return normalizedValue === "true" || normalizedValue === "1" || normalizedValue === "yes";
|
|
863
|
-
}
|
|
864
|
-
return value === true || value === 1;
|
|
865
|
-
case "string":
|
|
866
|
-
default:
|
|
867
|
-
return String(value);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
__name(convertType, "convertType");
|
|
871
|
-
|
|
872
|
-
export { After, Before, Body, Cache, Connect, ContentType, Controller, DIContainer, Delete, Get, Head, Header, Headers, HttpCode, Inject, Injectable, Log, Options, Param, Patch, Post, Put, Query, RateLimit, Redirect, Req, ReqCookie, ReqHeader, ReqId, ReqLogger, Res, Roles, Timeout, Trace, Use, Version, createParamDecorator, createParamDecoratorWithoutParam, inject, registerControllers };
|