@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.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { commonContainer, isObject, List, BLANK as BLANK$1, RIGHT_SLASH } from '@nattyjs/common';
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
- nattyContainer.setup(config, appConfig.routes, appConfig.resolver);
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 appRoutes() {
835
- return nattyContainer.routes;
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
- let isMatched = false;
849
- const requestPathname = this.getRequestPathname();
850
- for (const [key, value] of Object.entries(this.appRoutes)) {
851
- const rootPath = key;
852
- const routeConfig = value;
853
- const childRoutes = routeConfig[this.httpMethod];
854
- if (childRoutes) {
855
- for (const [key2, value2] of Object.entries(childRoutes)) {
856
- const childPath = key2.indexOf(RIGHT_SLASH) == 0 ? key2 === RIGHT_SLASH ? BLANK$1 : key2 : `/${key2}`;
857
- const methodInfo = value2;
858
- const configuredRoutePath = `${rootPath}${childPath}`;
859
- const routeMatch = match(`${rootPath}${childPath}`, { decode: decodeURIComponent });
860
- const matched = routeMatch(requestPathname);
861
- if (matched) {
862
- isMatched = true;
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 isMatched;
924
+ return false;
878
925
  }
879
- getRequestPathname() {
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 (!anonymousInfo.controllerConfig && !anonymousInfo.methodConfig && !authenticationFilter)
1093
- throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
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(token, { lifetime: Lifetime.Transient, useClass: useClass ?? token, useFactory });
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(token, { lifetime: Lifetime.Scoped, useClass: useClass ?? token, useFactory });
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(token, { lifetime: Lifetime.Singleton, useClass: useClass ?? token, useFactory });
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(classConstruct) {
1305
- return this.httpContext.services.get(classConstruct);
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 classConstruct = this.getClass(parameter.type);
1311
- if (classConstruct)
1312
- parameters.push(this.resolveClass(classConstruct));
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: getPreResponseBody({ message: ex.message, stack: ex.stack }),
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: ex,
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
- return result;
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(params, type, additionaConfig);
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
- export { $request, AbstractModelState, AcceptedException, AcceptedResult, BadRequestResult, BaseController, BaseResult, ConflictResult, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpConflictException, HttpContext, HttpException, HttpHandler, HttpNotFoundException, HttpResponse, HttpStatusCode, HttpUnprocessableEntityException, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, ProblemDetailsException, ProblemResult, RedirectException, RedirectPermanentException, RedirectResult, Results, RunOn, TooManyRequestsException, TooManyRequestsResult, UnAuthorizedResult, UnauthorizedAccessException, UnprocessableEntityResult, ValidationProblemDetailsException, accepted, anonymous, authenticationOnly, authorize, badRequest, conflict, created, createdAt, createdWith, defineNattyConfig, entityContainer, file, filter, forbiddenAccess, forbiddenAccessInfo, get, init, injectable, noContent, notFound, notFoundWith, ok, post, problem, put, redirect, redirectPermanent, registerDecorator, route, scoped, setEnvInfo, singleton, tooManyRequests, transient, unAuthorized, unprocessableEntity, useFilter, validationProblem };
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.63",
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.63"
20
+ "@nattyjs/common": "0.0.1-beta.65"
21
21
  },
22
22
  "devDependencies": {
23
23
  "unbuild": "1.2.1"