@nattyjs/core 0.0.1-beta.63 → 0.0.1-beta.65
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/dist/index.cjs +397 -64
- package/dist/index.d.ts +109 -83
- package/dist/index.mjs +388 -66
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { commonContainer, isObject, List, BLANK as BLANK$1
|
|
1
|
+
import { commonContainer, isObject, List, BLANK as BLANK$1 } from '@nattyjs/common';
|
|
2
2
|
import { match } from 'path-to-regexp';
|
|
3
|
+
import path from 'node:path';
|
|
3
4
|
import 'reflect-metadata';
|
|
4
5
|
|
|
5
6
|
function defineNattyConfig(config) {
|
|
@@ -52,6 +53,7 @@ function Delete() {
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
const HTTP_METHODS = ["get", "post", "put", "delete"];
|
|
55
57
|
const _StaticContainer = class {
|
|
56
58
|
setup(types) {
|
|
57
59
|
_StaticContainer.types = types;
|
|
@@ -63,14 +65,56 @@ const nattyContainer = new class {
|
|
|
63
65
|
constructor() {
|
|
64
66
|
this.container = /* @__PURE__ */ new Map();
|
|
65
67
|
this.containerState = /* @__PURE__ */ new Map();
|
|
68
|
+
this.compiledRoutes = {};
|
|
66
69
|
}
|
|
67
70
|
get types() {
|
|
68
71
|
return commonContainer.types;
|
|
69
72
|
}
|
|
70
73
|
setup(config, routes, resolver) {
|
|
71
74
|
this.config = config;
|
|
72
|
-
this.routes = routes;
|
|
73
75
|
this.resolver = resolver;
|
|
76
|
+
this.applyRouteSnapshot(routes);
|
|
77
|
+
}
|
|
78
|
+
replaceRoutes(manifest) {
|
|
79
|
+
if (manifest.resolver)
|
|
80
|
+
this.resolver = manifest.resolver;
|
|
81
|
+
this.applyRouteSnapshot(manifest.routes);
|
|
82
|
+
}
|
|
83
|
+
applyRouteSnapshot(routes) {
|
|
84
|
+
this.routes = routes;
|
|
85
|
+
this.compiledRoutes = this.createCompiledRoutes(routes);
|
|
86
|
+
}
|
|
87
|
+
createCompiledRoutes(routes) {
|
|
88
|
+
const compiledRoutes = {};
|
|
89
|
+
for (const method of HTTP_METHODS)
|
|
90
|
+
compiledRoutes[method] = [];
|
|
91
|
+
for (const [rootPath, routeConfig] of Object.entries(routes)) {
|
|
92
|
+
for (const method of HTTP_METHODS) {
|
|
93
|
+
const childRoutes = routeConfig[method];
|
|
94
|
+
if (!childRoutes)
|
|
95
|
+
continue;
|
|
96
|
+
for (const [childRoutePath, routeInfo] of Object.entries(childRoutes)) {
|
|
97
|
+
const childPath = this.normalizeChildPath(childRoutePath);
|
|
98
|
+
const configuredRoutePath = `${rootPath}${childPath}`;
|
|
99
|
+
compiledRoutes[method].push({
|
|
100
|
+
requestMethod: method,
|
|
101
|
+
configuredRoutePath,
|
|
102
|
+
matcher: match(configuredRoutePath, { decode: decodeURIComponent }),
|
|
103
|
+
routeConfig,
|
|
104
|
+
methodInfo: routeInfo
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return compiledRoutes;
|
|
110
|
+
}
|
|
111
|
+
normalizeChildPath(childRoutePath) {
|
|
112
|
+
if (childRoutePath.indexOf("/") === 0)
|
|
113
|
+
return childRoutePath === "/" ? BLANK : childRoutePath;
|
|
114
|
+
return `/${childRoutePath}`;
|
|
115
|
+
}
|
|
116
|
+
getCompiledRoutes(method) {
|
|
117
|
+
return this.compiledRoutes[method] || [];
|
|
74
118
|
}
|
|
75
119
|
getTypes() {
|
|
76
120
|
return StaticContainer.types;
|
|
@@ -143,13 +187,28 @@ async function startWebSchedule(config) {
|
|
|
143
187
|
function init(config, appConfig) {
|
|
144
188
|
commonContainer.setupConfig(config);
|
|
145
189
|
commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
|
|
146
|
-
|
|
190
|
+
setupLegacyTypes(appConfig.types);
|
|
191
|
+
nattyContainer.setup(config, appConfig.routes, appConfig.resolver || defaultResolver);
|
|
147
192
|
callLifeCycleEvents(config, true);
|
|
148
193
|
const result = initializeModule(config);
|
|
149
194
|
callLifeCycleEvents(config);
|
|
150
195
|
startWebSchedules(config.webSchedules);
|
|
151
196
|
return result;
|
|
152
197
|
}
|
|
198
|
+
function setupLegacyTypes(types) {
|
|
199
|
+
if (types) {
|
|
200
|
+
commonContainer.types = {};
|
|
201
|
+
for (const [name, type] of Object.entries(types))
|
|
202
|
+
commonContainer.registerType({ name, ...type });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function defaultResolver(path) {
|
|
206
|
+
if (typeof path === "function")
|
|
207
|
+
return path();
|
|
208
|
+
if (typeof path === "string")
|
|
209
|
+
return require(path);
|
|
210
|
+
return {};
|
|
211
|
+
}
|
|
153
212
|
function initializeModule(config) {
|
|
154
213
|
if (config.app) {
|
|
155
214
|
return config.app.init(config);
|
|
@@ -831,8 +890,8 @@ class RouteParser extends ParameterTypeConverter {
|
|
|
831
890
|
get httpMethod() {
|
|
832
891
|
return this.httpContext.request.method.toLowerCase();
|
|
833
892
|
}
|
|
834
|
-
get
|
|
835
|
-
return nattyContainer.
|
|
893
|
+
get compiledRoutes() {
|
|
894
|
+
return nattyContainer.getCompiledRoutes(this.httpMethod);
|
|
836
895
|
}
|
|
837
896
|
init() {
|
|
838
897
|
const isMatched = this.matchRoute();
|
|
@@ -845,47 +904,38 @@ class RouteParser extends ParameterTypeConverter {
|
|
|
845
904
|
return controllerInfo[name];
|
|
846
905
|
}
|
|
847
906
|
matchRoute() {
|
|
848
|
-
|
|
849
|
-
const requestPathname = this.getRequestPathname();
|
|
850
|
-
for (const
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
this.routeInfo = {
|
|
864
|
-
path: `${commonContainer.nattyConfig.api.rootPath}/${requestPathname}`,
|
|
865
|
-
configuredRoutePath: `${commonContainer.nattyConfig.api.rootPath}/${configuredRoutePath}`,
|
|
866
|
-
controller: this.getController(routeConfig),
|
|
867
|
-
parameters: routeConfig.parameters,
|
|
868
|
-
methodInfo,
|
|
869
|
-
params: this.convert(methodInfo, matched.params),
|
|
870
|
-
queryParams: this.getQueryParams()
|
|
871
|
-
};
|
|
872
|
-
break;
|
|
873
|
-
}
|
|
874
|
-
}
|
|
907
|
+
const requestUrl = this.getRequestUrl();
|
|
908
|
+
const requestPathname = this.getRequestPathname(requestUrl);
|
|
909
|
+
for (const route of this.compiledRoutes) {
|
|
910
|
+
const matched = route.matcher(requestPathname);
|
|
911
|
+
if (matched) {
|
|
912
|
+
this.routeInfo = {
|
|
913
|
+
path: `${commonContainer.nattyConfig.api.rootPath}/${requestPathname}`,
|
|
914
|
+
configuredRoutePath: `${commonContainer.nattyConfig.api.rootPath}/${route.configuredRoutePath}`,
|
|
915
|
+
controller: this.getController(route.routeConfig),
|
|
916
|
+
parameters: route.routeConfig.parameters,
|
|
917
|
+
methodInfo: route.methodInfo,
|
|
918
|
+
params: this.convert(route.methodInfo, matched.params),
|
|
919
|
+
queryParams: this.getQueryParams(requestUrl)
|
|
920
|
+
};
|
|
921
|
+
return true;
|
|
875
922
|
}
|
|
876
923
|
}
|
|
877
|
-
return
|
|
924
|
+
return false;
|
|
878
925
|
}
|
|
879
|
-
|
|
926
|
+
getRequestUrl() {
|
|
927
|
+
if (!this.parsedRequestUrl)
|
|
928
|
+
this.parsedRequestUrl = new URL(this.httpContext.request.url);
|
|
929
|
+
return this.parsedRequestUrl;
|
|
930
|
+
}
|
|
931
|
+
getRequestPathname(url) {
|
|
880
932
|
const apiRootPath = commonContainer.nattyConfig.api.rootPath;
|
|
881
|
-
const url = new URL(this.httpContext.request.url);
|
|
882
933
|
let splitUrl = url.pathname.split(`${apiRootPath}/`);
|
|
883
934
|
if (splitUrl.length > 1)
|
|
884
935
|
return splitUrl[1];
|
|
885
936
|
return url.pathname;
|
|
886
937
|
}
|
|
887
|
-
getQueryParams() {
|
|
888
|
-
const url = new URL(this.httpContext.request.url);
|
|
938
|
+
getQueryParams(url) {
|
|
889
939
|
const queryParams = {};
|
|
890
940
|
for (const param of url.searchParams.keys())
|
|
891
941
|
queryParams[param] = url.searchParams.get(param);
|
|
@@ -896,8 +946,10 @@ class RouteParser extends ParameterTypeConverter {
|
|
|
896
946
|
const decoratorStateContainer = new class {
|
|
897
947
|
constructor() {
|
|
898
948
|
this.controllerConfig = {};
|
|
949
|
+
this.controllerSources = /* @__PURE__ */ new Map();
|
|
950
|
+
this.sourceControllers = /* @__PURE__ */ new Map();
|
|
899
951
|
}
|
|
900
|
-
register(params, type, additionalConfig) {
|
|
952
|
+
register(params, type, additionalConfig, sourceFile) {
|
|
901
953
|
const name = params.target.name || params.target.constructor.name;
|
|
902
954
|
let controllerInfo = this.controllerConfig[name] || null;
|
|
903
955
|
let controllerMethodInfo = null;
|
|
@@ -910,6 +962,9 @@ const decoratorStateContainer = new class {
|
|
|
910
962
|
controllerMethodInfo[type] = additionalConfig;
|
|
911
963
|
} else
|
|
912
964
|
controllerInfo.config[type] = additionalConfig;
|
|
965
|
+
if (sourceFile) {
|
|
966
|
+
this.trackControllerSource(name, sourceFile);
|
|
967
|
+
}
|
|
913
968
|
}
|
|
914
969
|
getInfo(controllerName, methodName, type) {
|
|
915
970
|
const controllerInfo = this.controllerConfig[controllerName];
|
|
@@ -922,6 +977,55 @@ const decoratorStateContainer = new class {
|
|
|
922
977
|
methodConfig = methodInfo[type];
|
|
923
978
|
return { controllerConfig, methodConfig };
|
|
924
979
|
}
|
|
980
|
+
clearFromSource(sourceFile) {
|
|
981
|
+
const normalizedSourceFile = this.normalizeFilePath(sourceFile);
|
|
982
|
+
const controllerNames = Array.from(
|
|
983
|
+
this.sourceControllers.get(normalizedSourceFile) || []
|
|
984
|
+
);
|
|
985
|
+
this.clearControllers(controllerNames);
|
|
986
|
+
this.sourceControllers.delete(normalizedSourceFile);
|
|
987
|
+
return controllerNames;
|
|
988
|
+
}
|
|
989
|
+
clearControllers(controllerNames) {
|
|
990
|
+
const removedControllers = [];
|
|
991
|
+
for (const controllerName of controllerNames) {
|
|
992
|
+
const previousSource = this.controllerSources.get(controllerName);
|
|
993
|
+
delete this.controllerConfig[controllerName];
|
|
994
|
+
this.controllerSources.delete(controllerName);
|
|
995
|
+
removedControllers.push(controllerName);
|
|
996
|
+
if (previousSource) {
|
|
997
|
+
const controllers = this.sourceControllers.get(previousSource);
|
|
998
|
+
controllers?.delete(controllerName);
|
|
999
|
+
if (controllers && controllers.size === 0) {
|
|
1000
|
+
this.sourceControllers.delete(previousSource);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return removedControllers;
|
|
1005
|
+
}
|
|
1006
|
+
reset() {
|
|
1007
|
+
this.controllerConfig = {};
|
|
1008
|
+
this.controllerSources.clear();
|
|
1009
|
+
this.sourceControllers.clear();
|
|
1010
|
+
}
|
|
1011
|
+
trackControllerSource(controllerName, sourceFile) {
|
|
1012
|
+
const normalizedSourceFile = this.normalizeFilePath(sourceFile);
|
|
1013
|
+
const previousSource = this.controllerSources.get(controllerName);
|
|
1014
|
+
if (previousSource && previousSource !== normalizedSourceFile) {
|
|
1015
|
+
this.sourceControllers.get(previousSource)?.delete(controllerName);
|
|
1016
|
+
if (this.sourceControllers.get(previousSource)?.size === 0) {
|
|
1017
|
+
this.sourceControllers.delete(previousSource);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
this.controllerSources.set(controllerName, normalizedSourceFile);
|
|
1021
|
+
if (!this.sourceControllers.has(normalizedSourceFile)) {
|
|
1022
|
+
this.sourceControllers.set(normalizedSourceFile, /* @__PURE__ */ new Set());
|
|
1023
|
+
}
|
|
1024
|
+
this.sourceControllers.get(normalizedSourceFile)?.add(controllerName);
|
|
1025
|
+
}
|
|
1026
|
+
normalizeFilePath(filePath) {
|
|
1027
|
+
return path.resolve(filePath).replace(/\\/g, "/");
|
|
1028
|
+
}
|
|
925
1029
|
}();
|
|
926
1030
|
|
|
927
1031
|
var DecoratorType = /* @__PURE__ */ ((DecoratorType2) => {
|
|
@@ -1014,11 +1118,12 @@ function getTypeName(typeName) {
|
|
|
1014
1118
|
}
|
|
1015
1119
|
|
|
1016
1120
|
class ModelBindingContext extends ParameterTypeConverter {
|
|
1017
|
-
constructor(type, typeInfo, data) {
|
|
1121
|
+
constructor(type, typeInfo, data, throwOnValidationError = false) {
|
|
1018
1122
|
super();
|
|
1019
1123
|
this.type = type;
|
|
1020
1124
|
this.typeInfo = typeInfo;
|
|
1021
1125
|
this.data = data;
|
|
1126
|
+
this.throwOnValidationError = throwOnValidationError;
|
|
1022
1127
|
this.serialize();
|
|
1023
1128
|
}
|
|
1024
1129
|
serialize() {
|
|
@@ -1028,7 +1133,7 @@ class ModelBindingContext extends ParameterTypeConverter {
|
|
|
1028
1133
|
else
|
|
1029
1134
|
this.data = body;
|
|
1030
1135
|
this.instance = this.convertToInstance(this.type, this.data);
|
|
1031
|
-
if (!this.isValid)
|
|
1136
|
+
if (this.throwOnValidationError && !this.isValid)
|
|
1032
1137
|
throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
|
|
1033
1138
|
}
|
|
1034
1139
|
get isValid() {
|
|
@@ -1089,8 +1194,11 @@ class RequestProcessor extends RouteParser {
|
|
|
1089
1194
|
const authentication = this.getAuthenticationClass();
|
|
1090
1195
|
const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
|
|
1091
1196
|
const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
|
|
1092
|
-
if (!
|
|
1093
|
-
|
|
1197
|
+
if (!authenticationFilter) {
|
|
1198
|
+
if (commonContainer.nattyConfig?.secure?.denyByDefault && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
|
|
1199
|
+
throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1094
1202
|
if (authenticationFilter) {
|
|
1095
1203
|
const result = await authenticationFilter.onAuthentication(this.httpContext);
|
|
1096
1204
|
this.httpContext.user = result;
|
|
@@ -1110,7 +1218,7 @@ class RequestProcessor extends RouteParser {
|
|
|
1110
1218
|
this.routeInfo,
|
|
1111
1219
|
authorizeConfig.methodConfig || authorizeConfig.controllerConfig
|
|
1112
1220
|
);
|
|
1113
|
-
const result = await authorizationFilter.onAuthorization(authorizationContext);
|
|
1221
|
+
const result = await authorizationFilter.onAuthorization(authorizationContext, authorizationContext.config);
|
|
1114
1222
|
if (!result)
|
|
1115
1223
|
throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
|
|
1116
1224
|
}
|
|
@@ -1218,25 +1326,47 @@ class NattyScope {
|
|
|
1218
1326
|
}
|
|
1219
1327
|
}
|
|
1220
1328
|
|
|
1329
|
+
function normalizeFilePath$1(filePath) {
|
|
1330
|
+
return path.resolve(filePath).replace(/\\/g, "/");
|
|
1331
|
+
}
|
|
1221
1332
|
class NattyContainer {
|
|
1222
1333
|
constructor() {
|
|
1223
1334
|
this.regs = /* @__PURE__ */ new Map();
|
|
1224
1335
|
this.singletons = /* @__PURE__ */ new Map();
|
|
1336
|
+
this.tokenSources = /* @__PURE__ */ new Map();
|
|
1337
|
+
this.sourceTokens = /* @__PURE__ */ new Map();
|
|
1338
|
+
this.metadataKeySources = /* @__PURE__ */ new Map();
|
|
1339
|
+
this.sourceMetadataKeys = /* @__PURE__ */ new Map();
|
|
1225
1340
|
}
|
|
1226
|
-
register(token, desc) {
|
|
1341
|
+
register(token, desc, sourceFile) {
|
|
1227
1342
|
this.regs.set(token, desc);
|
|
1343
|
+
if (sourceFile) {
|
|
1344
|
+
this.trackTokenSource(token, sourceFile);
|
|
1345
|
+
}
|
|
1228
1346
|
}
|
|
1229
|
-
addTransient(token, useClass, useFactory) {
|
|
1230
|
-
this.register(
|
|
1347
|
+
addTransient(token, useClass, useFactory, sourceFile) {
|
|
1348
|
+
this.register(
|
|
1349
|
+
token,
|
|
1350
|
+
{ lifetime: Lifetime.Transient, useClass: useClass ?? token, useFactory },
|
|
1351
|
+
sourceFile
|
|
1352
|
+
);
|
|
1231
1353
|
}
|
|
1232
|
-
addScoped(token, useClass, useFactory) {
|
|
1233
|
-
this.register(
|
|
1354
|
+
addScoped(token, useClass, useFactory, sourceFile) {
|
|
1355
|
+
this.register(
|
|
1356
|
+
token,
|
|
1357
|
+
{ lifetime: Lifetime.Scoped, useClass: useClass ?? token, useFactory },
|
|
1358
|
+
sourceFile
|
|
1359
|
+
);
|
|
1234
1360
|
}
|
|
1235
|
-
addSingleton(token, useClass, useFactory) {
|
|
1236
|
-
this.register(
|
|
1361
|
+
addSingleton(token, useClass, useFactory, sourceFile) {
|
|
1362
|
+
this.register(
|
|
1363
|
+
token,
|
|
1364
|
+
{ lifetime: Lifetime.Singleton, useClass: useClass ?? token, useFactory },
|
|
1365
|
+
sourceFile
|
|
1366
|
+
);
|
|
1237
1367
|
}
|
|
1238
|
-
addInstance(token, value) {
|
|
1239
|
-
this.register(token, { lifetime: Lifetime.Singleton, useValue: value });
|
|
1368
|
+
addInstance(token, value, sourceFile) {
|
|
1369
|
+
this.register(token, { lifetime: Lifetime.Singleton, useValue: value }, sourceFile);
|
|
1240
1370
|
this.singletons.set(token, value);
|
|
1241
1371
|
}
|
|
1242
1372
|
createScope() {
|
|
@@ -1281,6 +1411,57 @@ class NattyContainer {
|
|
|
1281
1411
|
_getDescriptor(token) {
|
|
1282
1412
|
return this.regs.get(token);
|
|
1283
1413
|
}
|
|
1414
|
+
trackMetadataKey(sourceFile, key) {
|
|
1415
|
+
const normalizedSourceFile = normalizeFilePath$1(sourceFile);
|
|
1416
|
+
const previousSource = this.metadataKeySources.get(key);
|
|
1417
|
+
if (previousSource && previousSource !== normalizedSourceFile) {
|
|
1418
|
+
this.sourceMetadataKeys.get(previousSource)?.delete(key);
|
|
1419
|
+
if (this.sourceMetadataKeys.get(previousSource)?.size === 0) {
|
|
1420
|
+
this.sourceMetadataKeys.delete(previousSource);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
this.metadataKeySources.set(key, normalizedSourceFile);
|
|
1424
|
+
if (!this.sourceMetadataKeys.has(normalizedSourceFile)) {
|
|
1425
|
+
this.sourceMetadataKeys.set(normalizedSourceFile, /* @__PURE__ */ new Set());
|
|
1426
|
+
}
|
|
1427
|
+
this.sourceMetadataKeys.get(normalizedSourceFile)?.add(key);
|
|
1428
|
+
}
|
|
1429
|
+
clearRegistrationsFromSource(sourceFile) {
|
|
1430
|
+
const normalizedSourceFile = normalizeFilePath$1(sourceFile);
|
|
1431
|
+
const tokens = Array.from(this.sourceTokens.get(normalizedSourceFile) || []);
|
|
1432
|
+
const metadataKeys = Array.from(
|
|
1433
|
+
this.sourceMetadataKeys.get(normalizedSourceFile) || []
|
|
1434
|
+
);
|
|
1435
|
+
for (const token of tokens) {
|
|
1436
|
+
this.regs.delete(token);
|
|
1437
|
+
this.singletons.delete(token);
|
|
1438
|
+
this.tokenSources.delete(token);
|
|
1439
|
+
}
|
|
1440
|
+
for (const metadataKey of metadataKeys) {
|
|
1441
|
+
this.metadataKeySources.delete(metadataKey);
|
|
1442
|
+
}
|
|
1443
|
+
this.sourceTokens.delete(normalizedSourceFile);
|
|
1444
|
+
this.sourceMetadataKeys.delete(normalizedSourceFile);
|
|
1445
|
+
return {
|
|
1446
|
+
metadataKeys,
|
|
1447
|
+
tokens
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
trackTokenSource(token, sourceFile) {
|
|
1451
|
+
const normalizedSourceFile = normalizeFilePath$1(sourceFile);
|
|
1452
|
+
const previousSource = this.tokenSources.get(token);
|
|
1453
|
+
if (previousSource && previousSource !== normalizedSourceFile) {
|
|
1454
|
+
this.sourceTokens.get(previousSource)?.delete(token);
|
|
1455
|
+
if (this.sourceTokens.get(previousSource)?.size === 0) {
|
|
1456
|
+
this.sourceTokens.delete(previousSource);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
this.tokenSources.set(token, normalizedSourceFile);
|
|
1460
|
+
if (!this.sourceTokens.has(normalizedSourceFile)) {
|
|
1461
|
+
this.sourceTokens.set(normalizedSourceFile, /* @__PURE__ */ new Set());
|
|
1462
|
+
}
|
|
1463
|
+
this.sourceTokens.get(normalizedSourceFile)?.add(token);
|
|
1464
|
+
}
|
|
1284
1465
|
}
|
|
1285
1466
|
|
|
1286
1467
|
const nattyServiceResolver = new NattyContainer();
|
|
@@ -1301,18 +1482,27 @@ class Resolver extends RequestProcessor {
|
|
|
1301
1482
|
const instance = new controller(...parameters);
|
|
1302
1483
|
return instance;
|
|
1303
1484
|
}
|
|
1304
|
-
resolveClass(
|
|
1305
|
-
return this.httpContext.services.get(
|
|
1485
|
+
resolveClass(token) {
|
|
1486
|
+
return this.httpContext.services.get(token);
|
|
1306
1487
|
}
|
|
1307
1488
|
resolveConstructorParameters() {
|
|
1308
1489
|
let parameters = [];
|
|
1309
1490
|
for (const parameter of this.routeInfo.parameters) {
|
|
1310
|
-
const
|
|
1311
|
-
if (
|
|
1312
|
-
parameters.push(this.resolveClass(
|
|
1491
|
+
const token = this.getConstructorParameterToken(parameter);
|
|
1492
|
+
if (token)
|
|
1493
|
+
parameters.push(this.resolveClass(token));
|
|
1313
1494
|
}
|
|
1314
1495
|
return parameters;
|
|
1315
1496
|
}
|
|
1497
|
+
getConstructorParameterToken(parameter) {
|
|
1498
|
+
if (parameter.tokenKey) {
|
|
1499
|
+
return Symbol.for(parameter.tokenKey);
|
|
1500
|
+
}
|
|
1501
|
+
if (parameter.type) {
|
|
1502
|
+
return this.getClass(parameter.type);
|
|
1503
|
+
}
|
|
1504
|
+
return void 0;
|
|
1505
|
+
}
|
|
1316
1506
|
getMethodParameters() {
|
|
1317
1507
|
const parameters = new Array();
|
|
1318
1508
|
for (const parameter of this.routeInfo.methodInfo.parameters) {
|
|
@@ -1324,7 +1514,7 @@ class Resolver extends RequestProcessor {
|
|
|
1324
1514
|
else if (queryParams[parameter.name] !== void 0)
|
|
1325
1515
|
parameters.push(queryParams[parameter.name]);
|
|
1326
1516
|
else if (typeInfo && this.httpContext.request.body.json) {
|
|
1327
|
-
const context = new ModelBindingContext(parameter.type, typeInfo.props, this.httpContext.request.body.json);
|
|
1517
|
+
const context = new ModelBindingContext(parameter.type, typeInfo.props, this.httpContext.request.body.json, true);
|
|
1328
1518
|
parameters.push(context);
|
|
1329
1519
|
}
|
|
1330
1520
|
}
|
|
@@ -1384,7 +1574,7 @@ class Resolver extends RequestProcessor {
|
|
|
1384
1574
|
});
|
|
1385
1575
|
} else
|
|
1386
1576
|
result = new HttpException({
|
|
1387
|
-
body:
|
|
1577
|
+
body: { message: ex.message, stack: ex.stack },
|
|
1388
1578
|
status: HttpStatusCode.serverError
|
|
1389
1579
|
}).getResponse();
|
|
1390
1580
|
}
|
|
@@ -1419,7 +1609,10 @@ class RequestHandler extends Resolver {
|
|
|
1419
1609
|
});
|
|
1420
1610
|
} else
|
|
1421
1611
|
return new HttpException({
|
|
1422
|
-
body:
|
|
1612
|
+
body: {
|
|
1613
|
+
message: ex?.message,
|
|
1614
|
+
stack: ex?.stack
|
|
1615
|
+
},
|
|
1423
1616
|
status: HttpStatusCode.serverError
|
|
1424
1617
|
});
|
|
1425
1618
|
}
|
|
@@ -1432,20 +1625,59 @@ class HttpHandler {
|
|
|
1432
1625
|
async processRequest(httpContext) {
|
|
1433
1626
|
const requestProcessor = new RequestHandler(httpContext);
|
|
1434
1627
|
const result = await requestProcessor.onRequest();
|
|
1435
|
-
|
|
1628
|
+
if (result instanceof HttpResponse) {
|
|
1629
|
+
return result;
|
|
1630
|
+
}
|
|
1631
|
+
if (result instanceof HttpException) {
|
|
1632
|
+
return result.getResponse();
|
|
1633
|
+
}
|
|
1634
|
+
return new HttpResponse({ body: result });
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
const STACK_PATH_REGEX = /\bat (?:(?:.+?) \()?(.+):(\d+):(\d+)\)?$/;
|
|
1639
|
+
function normalizeFilePath(filePath) {
|
|
1640
|
+
return path.resolve(filePath).replace(/\\/g, "/");
|
|
1641
|
+
}
|
|
1642
|
+
function isInternalRegistrationFrame(filePath) {
|
|
1643
|
+
const normalizedPath = normalizeFilePath(filePath);
|
|
1644
|
+
return normalizedPath.includes("/packages/core/decorators/") || normalizedPath.includes("/packages/core/functions/") || normalizedPath.includes("/packages/core/domain/di/") || normalizedPath.includes("/packages/core/const/") || normalizedPath.includes("/packages/core/dist/") || normalizedPath.includes("/node_modules/@nattyjs/core/dist/");
|
|
1645
|
+
}
|
|
1646
|
+
function getRegistrationSourceFile() {
|
|
1647
|
+
const stack = new Error().stack;
|
|
1648
|
+
return getRegistrationSourceFileFromStack(stack);
|
|
1649
|
+
}
|
|
1650
|
+
function getRegistrationSourceFileFromStack(stack) {
|
|
1651
|
+
if (!stack) {
|
|
1652
|
+
return void 0;
|
|
1436
1653
|
}
|
|
1654
|
+
const lines = stack.split("\n").slice(1);
|
|
1655
|
+
for (const line of lines) {
|
|
1656
|
+
const match = line.trim().match(STACK_PATH_REGEX);
|
|
1657
|
+
if (!match) {
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
const filePath = normalizeFilePath(match[1]);
|
|
1661
|
+
if (!isInternalRegistrationFrame(filePath)) {
|
|
1662
|
+
return filePath;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return void 0;
|
|
1437
1666
|
}
|
|
1438
1667
|
|
|
1439
1668
|
function injectable(options = {}) {
|
|
1440
1669
|
return (targetConstructor) => {
|
|
1441
1670
|
const lt = options.lifetime ?? Lifetime.Transient;
|
|
1671
|
+
const sourceFile = getRegistrationSourceFile();
|
|
1442
1672
|
if (lt === Lifetime.Singleton)
|
|
1443
|
-
nattyServiceResolver.addSingleton(targetConstructor);
|
|
1673
|
+
nattyServiceResolver.addSingleton(targetConstructor, void 0, void 0, sourceFile);
|
|
1444
1674
|
else if (lt === Lifetime.Scoped)
|
|
1445
|
-
nattyServiceResolver.addScoped(targetConstructor);
|
|
1675
|
+
nattyServiceResolver.addScoped(targetConstructor, void 0, void 0, sourceFile);
|
|
1446
1676
|
else
|
|
1447
|
-
nattyServiceResolver.addTransient(targetConstructor);
|
|
1677
|
+
nattyServiceResolver.addTransient(targetConstructor, void 0, void 0, sourceFile);
|
|
1448
1678
|
commonContainer.setMetadata(targetConstructor.name, targetConstructor, "services");
|
|
1679
|
+
if (sourceFile)
|
|
1680
|
+
nattyServiceResolver.trackMetadataKey(sourceFile, targetConstructor.name);
|
|
1449
1681
|
};
|
|
1450
1682
|
}
|
|
1451
1683
|
|
|
@@ -1731,7 +1963,12 @@ const Results = {
|
|
|
1731
1963
|
};
|
|
1732
1964
|
|
|
1733
1965
|
function base(params, type, additionaConfig) {
|
|
1734
|
-
decoratorStateContainer.register(
|
|
1966
|
+
decoratorStateContainer.register(
|
|
1967
|
+
params,
|
|
1968
|
+
type,
|
|
1969
|
+
additionaConfig,
|
|
1970
|
+
getRegistrationSourceFile()
|
|
1971
|
+
);
|
|
1735
1972
|
}
|
|
1736
1973
|
|
|
1737
1974
|
function useFilter(config) {
|
|
@@ -1756,6 +1993,12 @@ function authenticationOnly() {
|
|
|
1756
1993
|
};
|
|
1757
1994
|
}
|
|
1758
1995
|
|
|
1996
|
+
function onException(exceptionFilter) {
|
|
1997
|
+
return function(target, propertyKey, descriptor) {
|
|
1998
|
+
base({ target, propertyKey, descriptor }, DecoratorType.onException, exceptionFilter);
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
|
|
1759
2002
|
function setEnvInfo(envTsDefinition, envValueInfo) {
|
|
1760
2003
|
if (envTsDefinition && envValueInfo) {
|
|
1761
2004
|
commonContainer.setEnvTsDefinition(envTsDefinition);
|
|
@@ -1788,4 +2031,83 @@ function singleton(token) {
|
|
|
1788
2031
|
return injectable({ lifetime: Lifetime.Singleton, token });
|
|
1789
2032
|
}
|
|
1790
2033
|
|
|
1791
|
-
|
|
2034
|
+
function getTokenTypeName(token) {
|
|
2035
|
+
if (typeof token !== "symbol") {
|
|
2036
|
+
return void 0;
|
|
2037
|
+
}
|
|
2038
|
+
const key = Symbol.keyFor(token);
|
|
2039
|
+
if (!key) {
|
|
2040
|
+
return void 0;
|
|
2041
|
+
}
|
|
2042
|
+
const separatorIndex = key.lastIndexOf("#");
|
|
2043
|
+
if (separatorIndex < 0 || separatorIndex === key.length - 1) {
|
|
2044
|
+
return void 0;
|
|
2045
|
+
}
|
|
2046
|
+
return key.slice(separatorIndex + 1);
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
function registerLifetime(targetConstructor, sourceFile, lifetime) {
|
|
2050
|
+
if (lifetime === Lifetime.Singleton) {
|
|
2051
|
+
nattyServiceResolver.addSingleton(targetConstructor, void 0, void 0, sourceFile);
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
if (lifetime === Lifetime.Scoped) {
|
|
2055
|
+
nattyServiceResolver.addScoped(targetConstructor, void 0, void 0, sourceFile);
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
if (lifetime === Lifetime.Transient) {
|
|
2059
|
+
nattyServiceResolver.addTransient(targetConstructor, void 0, void 0, sourceFile);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
function registerAliasTypeName(token, sourceFile) {
|
|
2063
|
+
const typeName = getTokenTypeName(token);
|
|
2064
|
+
if (typeName) {
|
|
2065
|
+
commonContainer.setMetadata(typeName, token, "services");
|
|
2066
|
+
if (sourceFile)
|
|
2067
|
+
nattyServiceResolver.trackMetadataKey(sourceFile, typeName);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
function registerDiToken(targetConstructor, token, options = {}) {
|
|
2071
|
+
const sourceFile = getRegistrationSourceFile();
|
|
2072
|
+
commonContainer.setMetadata(targetConstructor.name, targetConstructor, "services");
|
|
2073
|
+
if (sourceFile)
|
|
2074
|
+
nattyServiceResolver.trackMetadataKey(sourceFile, targetConstructor.name);
|
|
2075
|
+
registerAliasTypeName(token, sourceFile);
|
|
2076
|
+
registerLifetime(targetConstructor, sourceFile, options.lifetime);
|
|
2077
|
+
nattyServiceResolver.addTransient(
|
|
2078
|
+
token,
|
|
2079
|
+
void 0,
|
|
2080
|
+
(serviceProvider) => serviceProvider.get(targetConstructor),
|
|
2081
|
+
sourceFile
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
function di(token, options = {}) {
|
|
2086
|
+
return (targetConstructor) => {
|
|
2087
|
+
registerDiToken(targetConstructor, token, options);
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
function createServiceScope() {
|
|
2092
|
+
return nattyServiceResolver.createScope();
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
function clearHotReloadRegistrations(files) {
|
|
2096
|
+
for (const filePath of files || []) {
|
|
2097
|
+
const result = nattyServiceResolver.clearRegistrationsFromSource(filePath);
|
|
2098
|
+
decoratorStateContainer.clearFromSource(filePath);
|
|
2099
|
+
for (const metadataKey of result.metadataKeys) {
|
|
2100
|
+
commonContainer.deleteMetadataValue(metadataKey, "services");
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
function clearHotReloadControllerMetadata(controllerNames) {
|
|
2106
|
+
decoratorStateContainer.clearControllers(controllerNames || []);
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
function replaceRoutes(manifest) {
|
|
2110
|
+
nattyContainer.replaceRoutes(manifest);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
export { $request, AbstractModelState, AcceptedException, AcceptedResult, BadRequestResult, BaseController, BaseResult, ConflictResult, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpConflictException, HttpContext, HttpException, HttpHandler, HttpNotFoundException, HttpResponse, HttpStatusCode, HttpUnprocessableEntityException, Lifetime, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, ProblemDetailsException, ProblemResult, RedirectException, RedirectPermanentException, RedirectResult, Results, RunOn, TooManyRequestsException, TooManyRequestsResult, UnAuthorizedResult, UnauthorizedAccessException, UnprocessableEntityResult, ValidationProblemDetailsException, accepted, anonymous, authenticationOnly, authorize, badRequest, clearHotReloadControllerMetadata, clearHotReloadRegistrations, conflict, createServiceScope, created, createdAt, createdWith, defineNattyConfig, di, entityContainer, file, filter, forbiddenAccess, forbiddenAccessInfo, get, init, injectable, noContent, notFound, notFoundWith, ok, onException, post, problem, put, redirect, redirectPermanent, registerDecorator, replaceRoutes, route, scoped, setEnvInfo, singleton, tooManyRequests, transient, unAuthorized, unprocessableEntity, useFilter, validationProblem };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nattyjs/core",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.65",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "ajayojha",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"reflect-metadata": "0.2.2",
|
|
19
19
|
"path-to-regexp": "6.2.1",
|
|
20
|
-
"@nattyjs/common": "0.0.1-beta.
|
|
20
|
+
"@nattyjs/common": "0.0.1-beta.65"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"unbuild": "1.2.1"
|