@nattyjs/core 0.0.1-beta.7 → 0.0.1-beta.71

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 CHANGED
@@ -1,8 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  const common = require('@nattyjs/common');
4
- const tsyringe = require('tsyringe');
5
4
  const pathToRegexp = require('path-to-regexp');
5
+ const path = require('node:path');
6
+ require('reflect-metadata');
7
+
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
9
+
10
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
6
11
 
7
12
  function defineNattyConfig(config) {
8
13
  return config;
@@ -27,6 +32,12 @@ function route(path) {
27
32
  const CONTROLLER = "controller";
28
33
  const INVALID_VALUE = "INVALID_VALUE";
29
34
  const BLANK = "";
35
+ const DENY_BY_DEFAULT = {
36
+ type: "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html#deny-by-default",
37
+ title: "Deny-by-default",
38
+ description: `Zero Trust Architecture (NIST SP 800-207) \u2014 Core principle is "never trust, always verify," which translates to deny-by-default behavior. OWASP Secure Defaults Principle \u2014 \u201CSecurity should be a default setting, and everything should be locked down unless explicitly permitted.\u201D`,
39
+ solution: `Please implement proper authentication and authorization checks. If this API needs to be accessed anonymously, add the @anonymous() decorator above the HTTP action.`
40
+ };
30
41
 
31
42
  function get(path) {
32
43
  return function(target, propertyKey, descriptor) {
@@ -48,6 +59,7 @@ function Delete() {
48
59
  };
49
60
  }
50
61
 
62
+ const HTTP_METHODS = ["get", "post", "put", "delete"];
51
63
  const _StaticContainer = class {
52
64
  setup(types) {
53
65
  _StaticContainer.types = types;
@@ -59,11 +71,101 @@ const nattyContainer = new class {
59
71
  constructor() {
60
72
  this.container = /* @__PURE__ */ new Map();
61
73
  this.containerState = /* @__PURE__ */ new Map();
74
+ this.compiledRoutes = {};
62
75
  }
63
- setup(config, routes, types) {
76
+ get types() {
77
+ return common.commonContainer.types;
78
+ }
79
+ setup(config, routes, resolver) {
64
80
  this.config = config;
81
+ this.resolver = resolver;
82
+ this.applyRouteSnapshot(routes);
83
+ }
84
+ replaceRoutes(manifest) {
85
+ if (manifest.resolver)
86
+ this.resolver = manifest.resolver;
87
+ this.applyRouteSnapshot(manifest.routes);
88
+ }
89
+ applyRouteSnapshot(routes) {
65
90
  this.routes = routes;
66
- this.types = types;
91
+ this.compiledRoutes = this.createCompiledRoutes(routes);
92
+ }
93
+ createCompiledRoutes(routes) {
94
+ const compiledRoutes = {};
95
+ let declarationOrder = 0;
96
+ for (const method of HTTP_METHODS)
97
+ compiledRoutes[method] = [];
98
+ for (const [rootPath, routeConfig] of Object.entries(routes)) {
99
+ for (const method of HTTP_METHODS) {
100
+ const childRoutes = routeConfig[method];
101
+ if (!childRoutes)
102
+ continue;
103
+ for (const [childRoutePath, routeInfo] of Object.entries(childRoutes)) {
104
+ const childPath = this.normalizeChildPath(childRoutePath);
105
+ const configuredRoutePath = `${rootPath}${childPath}`;
106
+ compiledRoutes[method].push({
107
+ declarationOrder: declarationOrder++,
108
+ requestMethod: method,
109
+ configuredRoutePath,
110
+ matcher: pathToRegexp.match(configuredRoutePath, { decode: decodeURIComponent }),
111
+ routeConfig,
112
+ methodInfo: routeInfo,
113
+ specificity: this.getRouteSpecificity(configuredRoutePath)
114
+ });
115
+ }
116
+ }
117
+ }
118
+ const sortedCompiledRoutes = {};
119
+ for (const method of HTTP_METHODS) {
120
+ sortedCompiledRoutes[method] = compiledRoutes[method].sort((routeA, routeB) => this.compareCompiledRoutes(routeA, routeB)).map(({ declarationOrder: declarationOrder2, specificity, ...route }) => route);
121
+ }
122
+ return sortedCompiledRoutes;
123
+ }
124
+ normalizeChildPath(childRoutePath) {
125
+ if (childRoutePath.indexOf("/") === 0)
126
+ return childRoutePath === "/" ? BLANK : childRoutePath;
127
+ return `/${childRoutePath}`;
128
+ }
129
+ getRouteSpecificity(routePath) {
130
+ const segments = routePath.split("/").filter(Boolean);
131
+ const segmentKinds = segments.map((segment) => this.getSegmentKind(segment));
132
+ return {
133
+ segments,
134
+ segmentKinds,
135
+ staticSegmentCount: segmentKinds.filter((kind) => kind === 2).length,
136
+ dynamicSegmentCount: segmentKinds.filter((kind) => kind === 1).length,
137
+ literalLength: segments.filter((segment) => !segment.startsWith(":")).reduce((length, segment) => length + segment.length, 0)
138
+ };
139
+ }
140
+ getSegmentKind(segment) {
141
+ if (!segment)
142
+ return 0;
143
+ if (segment.startsWith(":"))
144
+ return 1;
145
+ return 2;
146
+ }
147
+ compareCompiledRoutes(routeA, routeB) {
148
+ const bySegmentSpecificity = this.compareSegmentSpecificity(routeA.specificity, routeB.specificity);
149
+ if (bySegmentSpecificity !== 0)
150
+ return bySegmentSpecificity;
151
+ if (routeA.specificity.staticSegmentCount !== routeB.specificity.staticSegmentCount)
152
+ return routeB.specificity.staticSegmentCount - routeA.specificity.staticSegmentCount;
153
+ if (routeA.specificity.dynamicSegmentCount !== routeB.specificity.dynamicSegmentCount)
154
+ return routeA.specificity.dynamicSegmentCount - routeB.specificity.dynamicSegmentCount;
155
+ if (routeA.specificity.literalLength !== routeB.specificity.literalLength)
156
+ return routeB.specificity.literalLength - routeA.specificity.literalLength;
157
+ return routeA.declarationOrder - routeB.declarationOrder;
158
+ }
159
+ compareSegmentSpecificity(routeA, routeB) {
160
+ const maxSharedSegments = Math.min(routeA.segmentKinds.length, routeB.segmentKinds.length);
161
+ for (let index = 0; index < maxSharedSegments; index++) {
162
+ if (routeA.segmentKinds[index] !== routeB.segmentKinds[index])
163
+ return routeB.segmentKinds[index] - routeA.segmentKinds[index];
164
+ }
165
+ return 0;
166
+ }
167
+ getCompiledRoutes(method) {
168
+ return this.compiledRoutes[method] || [];
67
169
  }
68
170
  getTypes() {
69
171
  return StaticContainer.types;
@@ -113,57 +215,133 @@ const nattyContainer = new class {
113
215
  }
114
216
  }();
115
217
 
218
+ function startWebSchedules(schedules) {
219
+ if (schedules && Array.isArray(schedules)) {
220
+ for (const schedule of schedules)
221
+ startWebSchedule(schedule);
222
+ }
223
+ }
224
+ async function startWebSchedule(config) {
225
+ if (config) {
226
+ const interval = setInterval(async () => {
227
+ try {
228
+ clearInterval(interval);
229
+ await config.scheduleFunction();
230
+ startWebSchedule(config);
231
+ } catch (ex) {
232
+ startWebSchedule(config);
233
+ }
234
+ }, config.interval);
235
+ }
236
+ }
237
+
116
238
  function init(config, appConfig) {
117
239
  common.commonContainer.setupConfig(config);
118
240
  common.commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
119
- nattyContainer.setup(config, appConfig.routes, appConfig.types);
120
- return initializeModule(config);
241
+ setupLegacyTypes(appConfig.types);
242
+ nattyContainer.setup(config, appConfig.routes, appConfig.resolver || defaultResolver);
243
+ callLifeCycleEvents(config, true);
244
+ const result = initializeModule(config);
245
+ callLifeCycleEvents(config);
246
+ startWebSchedules(config.webSchedules);
247
+ return result;
248
+ }
249
+ function setupLegacyTypes(types) {
250
+ if (types) {
251
+ common.commonContainer.types = {};
252
+ for (const [name, type] of Object.entries(types))
253
+ common.commonContainer.registerType({ name, ...type });
254
+ }
255
+ }
256
+ function defaultResolver(path) {
257
+ if (typeof path === "function")
258
+ return path();
259
+ if (typeof path === "string") {
260
+ const normalizedPath = path.startsWith("/") ? `.${path}` : path;
261
+ return require(normalizedPath);
262
+ }
263
+ return {};
121
264
  }
122
265
  function initializeModule(config) {
123
266
  if (config.app) {
124
267
  return config.app.init(config);
125
268
  }
126
269
  }
127
-
128
- function getPreResponseBody(body) {
129
- let bodyInfo;
130
- if (body) {
131
- if (common.isObject(body) || Array.isArray(body))
132
- bodyInfo = { json: body };
133
- const typeText = typeof body;
134
- switch (typeText) {
135
- case "string":
136
- bodyInfo = { string: body };
137
- break;
138
- case "number":
139
- bodyInfo = { number: body };
140
- break;
141
- case "boolean":
142
- bodyInfo = { boolean: body };
143
- break;
270
+ async function callLifeCycleEvents(config, isPreInit = false) {
271
+ if (config.lifeCycle) {
272
+ if (config.lifeCycle.preInit && isPreInit) {
273
+ const preInit = config.lifeCycle.preInit();
274
+ if (preInit) {
275
+ if (preInit.cors) {
276
+ if (!config.cors) {
277
+ const jObject = { origin: [] };
278
+ config.cors = jObject;
279
+ } else if (!config.cors.origin)
280
+ config.cors.origin = [];
281
+ if (preInit.cors.origin)
282
+ preInit.cors.origin.forEach((t) => {
283
+ config.cors?.origin.push(t);
284
+ });
285
+ if (preInit.cors.methods)
286
+ config.cors.methods = preInit.cors.methods;
287
+ if (preInit.cors.optionsSuccessStatus)
288
+ config.cors.optionsSuccessStatus = preInit.cors.optionsSuccessStatus;
289
+ if (preInit.cors.preflightContinue)
290
+ config.cors.preflightContinue = preInit.cors.preflightContinue;
291
+ }
292
+ }
144
293
  }
294
+ if (config.lifeCycle.onStart) {
295
+ config.lifeCycle.onStart();
296
+ }
297
+ }
298
+ }
299
+
300
+ function getPreResponseBody(body, isBuffer = false) {
301
+ if (body === void 0 || body === null)
302
+ return void 0;
303
+ if (isBuffer)
304
+ return { buffer: body };
305
+ if (common.isObject(body) || Array.isArray(body))
306
+ return { json: body };
307
+ switch (typeof body) {
308
+ case "string":
309
+ return { string: body };
310
+ case "number":
311
+ return { number: body };
312
+ case "boolean":
313
+ return { boolean: body };
314
+ default:
315
+ return { json: body };
145
316
  }
146
- return bodyInfo;
147
317
  }
148
318
 
149
319
  class HttpResponse {
150
320
  constructor(response) {
151
- this._cookies = new Array();
321
+ this._cookies = [];
152
322
  this._headers = new Headers();
323
+ this._isBuffer = false;
153
324
  this.setValues(response);
154
325
  }
155
326
  setValues(responseInit) {
156
- if (responseInit) {
157
- if (responseInit.headers)
158
- for (const [key, value] of Object.entries(responseInit.headers))
159
- this.headers.append(key, value);
160
- if (responseInit.cookies)
161
- for (const cookie of responseInit.cookies)
162
- this.addCookie(cookie);
163
- if (responseInit.status)
164
- this.status = responseInit.status;
165
- if (responseInit.body)
166
- this.body = responseInit.body;
327
+ if (!responseInit)
328
+ return;
329
+ if ("isBuffer" in responseInit)
330
+ this._isBuffer = !!responseInit.isBuffer;
331
+ if (responseInit.headers) {
332
+ for (const [key, value] of Object.entries(responseInit.headers)) {
333
+ this.headers.append(key, String(value));
334
+ }
335
+ }
336
+ if (responseInit.cookies) {
337
+ for (const cookie of responseInit.cookies)
338
+ this.addCookie(cookie);
339
+ }
340
+ if ("status" in responseInit && responseInit.status !== void 0) {
341
+ this.status = responseInit.status;
342
+ }
343
+ if ("body" in responseInit) {
344
+ this.body = responseInit.body;
167
345
  }
168
346
  }
169
347
  addCookie(cookie) {
@@ -173,7 +351,7 @@ class HttpResponse {
173
351
  return this._cookies;
174
352
  }
175
353
  get status() {
176
- return this._status;
354
+ return this._status ?? 200;
177
355
  }
178
356
  set status(value) {
179
357
  this._status = value;
@@ -185,22 +363,62 @@ class HttpResponse {
185
363
  return this._body;
186
364
  }
187
365
  set body(value) {
188
- this._body = getPreResponseBody(value);
366
+ this._body = getPreResponseBody(value, this._isBuffer);
189
367
  }
190
368
  write(responseInit) {
191
369
  this.setValues(responseInit);
192
370
  }
193
371
  }
194
372
 
195
- class HttpException {
196
- constructor(response) {
373
+ class HttpException extends Error {
374
+ constructor(response, message) {
375
+ const bodyMsg = response?.body?.message;
376
+ const msg = message ?? (typeof bodyMsg === "string" && bodyMsg.trim() ? bodyMsg : `HTTP ${response.status ?? 500}`);
377
+ super(msg);
378
+ this.name = this.constructor.name;
197
379
  this.httpResponse = new HttpResponse(response);
380
+ const anyErr = Error;
381
+ if (typeof anyErr.captureStackTrace === "function") {
382
+ anyErr.captureStackTrace(this, this.constructor);
383
+ }
198
384
  }
199
385
  getResponse() {
200
386
  return this.httpResponse;
201
387
  }
202
388
  }
203
389
 
390
+ class HttpRequest {
391
+ constructor(http) {
392
+ this.httpRequest = http;
393
+ }
394
+ get cookies() {
395
+ return this.httpRequest.cookies;
396
+ }
397
+ get url() {
398
+ return this.httpRequest.url;
399
+ }
400
+ get method() {
401
+ return this.httpRequest.method;
402
+ }
403
+ get headers() {
404
+ return this.httpRequest.headers;
405
+ }
406
+ get user() {
407
+ return null;
408
+ }
409
+ get body() {
410
+ return this.httpRequest.body;
411
+ }
412
+ }
413
+
414
+ class HttpContext {
415
+ constructor(request, context) {
416
+ this.request = new HttpRequest(request);
417
+ this.response = new HttpResponse();
418
+ this.context = context;
419
+ }
420
+ }
421
+
204
422
  var RequestPipeline = /* @__PURE__ */ ((RequestPipeline2) => {
205
423
  RequestPipeline2[RequestPipeline2["onAuthentication"] = 0] = "onAuthentication";
206
424
  RequestPipeline2[RequestPipeline2["onAuthorization"] = 1] = "onAuthorization";
@@ -327,20 +545,24 @@ class HttpNotFoundException extends HttpException {
327
545
  var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {
328
546
  HttpStatusCode2[HttpStatusCode2["success"] = 200] = "success";
329
547
  HttpStatusCode2[HttpStatusCode2["created"] = 201] = "created";
548
+ HttpStatusCode2[HttpStatusCode2["accepted"] = 202] = "accepted";
330
549
  HttpStatusCode2[HttpStatusCode2["noContent"] = 204] = "noContent";
331
- HttpStatusCode2[HttpStatusCode2["notFound"] = 404] = "notFound";
550
+ HttpStatusCode2[HttpStatusCode2["movedPermanently"] = 301] = "movedPermanently";
551
+ HttpStatusCode2[HttpStatusCode2["found"] = 302] = "found";
552
+ HttpStatusCode2[HttpStatusCode2["badRequest"] = 400] = "badRequest";
332
553
  HttpStatusCode2[HttpStatusCode2["unAuthorized"] = 401] = "unAuthorized";
333
554
  HttpStatusCode2[HttpStatusCode2["forbiddenAccess"] = 403] = "forbiddenAccess";
334
- HttpStatusCode2[HttpStatusCode2["badRequest"] = 400] = "badRequest";
555
+ HttpStatusCode2[HttpStatusCode2["notFound"] = 404] = "notFound";
556
+ HttpStatusCode2[HttpStatusCode2["conflict"] = 409] = "conflict";
557
+ HttpStatusCode2[HttpStatusCode2["unprocessableEntity"] = 422] = "unprocessableEntity";
558
+ HttpStatusCode2[HttpStatusCode2["tooManyRequests"] = 429] = "tooManyRequests";
335
559
  HttpStatusCode2[HttpStatusCode2["serverError"] = 500] = "serverError";
336
560
  return HttpStatusCode2;
337
561
  })(HttpStatusCode || {});
338
562
 
339
563
  class BaseResult {
340
- constructor(response, responseHeaders) {
341
- this.response = response;
342
- if (responseHeaders)
343
- this.response = { ...this.response, ...responseHeaders };
564
+ constructor(response, extras) {
565
+ this.response = extras ? { ...response, ...extras } : response;
344
566
  }
345
567
  getResponse() {
346
568
  return this.response;
@@ -348,6 +570,7 @@ class BaseResult {
348
570
  }
349
571
 
350
572
  function getResponseBodyObject(body, props) {
573
+ const sensitiveProps = common.commonContainer.nattyConfig?.secure?.sensitiveProps;
351
574
  if (body instanceof common.List)
352
575
  return getResponseBodyObject(body.values, body.props);
353
576
  if (Array.isArray(body)) {
@@ -361,7 +584,8 @@ function getResponseBodyObject(body, props) {
361
584
  const keys = Object.keys(body);
362
585
  const getterProps = props ? Object.keys(props).map((key) => props[key]) : [];
363
586
  for (const key of [...keys, ...getterProps])
364
- jObject[key] = getResponseBodyObject(body[key]);
587
+ if (!sensitiveProps || sensitiveProps.filter((t) => t == key.toLowerCase()).length == 0)
588
+ jObject[key] = getResponseBodyObject(body[key]);
365
589
  return jObject;
366
590
  }
367
591
  return body;
@@ -385,10 +609,19 @@ class BaseResponse {
385
609
  notFound() {
386
610
  throw new HttpNotFoundException({});
387
611
  }
612
+ normalizeHttpResponse(result) {
613
+ if (result instanceof HttpResponse)
614
+ return result;
615
+ if (result instanceof HttpException)
616
+ return result.getResponse();
617
+ if (result && typeof result === "object" && ("status" in result || "body" in result || "headers" in result || "cookies" in result || "isBuffer" in result))
618
+ return new HttpResponse(result);
619
+ return result;
620
+ }
388
621
  }
389
622
 
390
623
  function getTypedErrorMessage(type, value) {
391
- const message = common.commonContainer.nattyConfig.modelBinding.errorMessage.typed[type];
624
+ const message = common.commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed ? common.commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed[type] : "";
392
625
  return parseMessage(message, [value]);
393
626
  }
394
627
  function parseMessage(message, value) {
@@ -455,7 +688,7 @@ const entityContainer = new class {
455
688
  }
456
689
  getPropertyValidators(entityName, propName) {
457
690
  const entityInfo = this.entityConfig[entityName];
458
- const propertyInfo = entityInfo.properties[propName];
691
+ const propertyInfo = entityInfo ? entityInfo.properties[propName] : void 0;
459
692
  return propertyInfo ? propertyInfo.validators : {};
460
693
  }
461
694
  getProperties(entityName) {
@@ -464,6 +697,115 @@ const entityContainer = new class {
464
697
  }
465
698
  }();
466
699
 
700
+ class ForbiddenAccessException extends HttpException {
701
+ constructor(data) {
702
+ super({
703
+ body: data,
704
+ status: 403
705
+ });
706
+ }
707
+ }
708
+
709
+ class UnauthorizedAccessException extends HttpException {
710
+ constructor(data) {
711
+ super({
712
+ body: data,
713
+ status: 401
714
+ });
715
+ }
716
+ }
717
+
718
+ class AcceptedException extends HttpException {
719
+ constructor(data) {
720
+ super({ body: data, status: HttpStatusCode.accepted });
721
+ }
722
+ }
723
+
724
+ class HttpConflictException extends HttpException {
725
+ constructor(data) {
726
+ super({ body: data, status: HttpStatusCode.conflict });
727
+ }
728
+ }
729
+
730
+ class HttpUnprocessableEntityException extends HttpException {
731
+ constructor(data) {
732
+ super({ body: data, status: HttpStatusCode.unprocessableEntity });
733
+ }
734
+ }
735
+
736
+ function formatRetryAfter(value) {
737
+ if (typeof value === "number")
738
+ return String(Math.max(0, Math.floor(value)));
739
+ if (value instanceof Date)
740
+ return value.toUTCString();
741
+ return String(value);
742
+ }
743
+ class TooManyRequestsException extends HttpException {
744
+ constructor(data, retryAfter) {
745
+ super({
746
+ body: data,
747
+ status: HttpStatusCode.tooManyRequests,
748
+ headers: retryAfter !== void 0 ? { "Retry-After": formatRetryAfter(retryAfter) } : void 0
749
+ });
750
+ }
751
+ }
752
+
753
+ class RedirectException extends HttpException {
754
+ constructor(location, data) {
755
+ super({
756
+ body: data,
757
+ status: HttpStatusCode.found,
758
+ headers: { Location: location }
759
+ });
760
+ }
761
+ }
762
+
763
+ class RedirectPermanentException extends HttpException {
764
+ constructor(location, data) {
765
+ super({
766
+ body: data,
767
+ status: HttpStatusCode.movedPermanently,
768
+ headers: { Location: location }
769
+ });
770
+ }
771
+ }
772
+
773
+ class ProblemDetailsException extends HttpException {
774
+ constructor(problem, status, headers) {
775
+ const resolvedStatus = status ?? problem.status ?? 500;
776
+ super({
777
+ status: resolvedStatus,
778
+ body: { ...problem, status: resolvedStatus },
779
+ headers: {
780
+ "Content-Type": "application/problem+json; charset=utf-8",
781
+ ...headers ?? {}
782
+ }
783
+ });
784
+ }
785
+ }
786
+ class ValidationProblemDetailsException extends ProblemDetailsException {
787
+ constructor(errors, detail, status = 400) {
788
+ super(
789
+ {
790
+ type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
791
+ title: "One or more validation errors occurred.",
792
+ status,
793
+ detail,
794
+ errors
795
+ },
796
+ status
797
+ );
798
+ }
799
+ }
800
+
801
+ function CreateProblemDetail(modelName, detail) {
802
+ return {
803
+ type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
804
+ title: `The specified ${modelName} model props are invalid.`,
805
+ detail
806
+ };
807
+ }
808
+
467
809
  class ParameterTypeConverter extends BaseResponse {
468
810
  constructor() {
469
811
  super(...arguments);
@@ -524,12 +866,14 @@ class ParameterTypeConverter extends BaseResponse {
524
866
  } else {
525
867
  if (this.isArrayType(property.type) && Array.isArray(value)) {
526
868
  let arrayValue = body[property.name] = [];
527
- let arrayInvalidProps = invalidProps[property.name] = [];
528
869
  for (const item of value) {
529
870
  const sanitizeValue = this.sanitizer[property.type.toLowerCase()] ? this.sanitizer[property.type.toLowerCase()](item) : item;
530
- if (sanitizeValue === INVALID_VALUE)
871
+ if (sanitizeValue === INVALID_VALUE) {
872
+ let arrayInvalidProps = invalidProps[property.name];
873
+ if (!arrayInvalidProps)
874
+ arrayInvalidProps = invalidProps[property.name] = [];
531
875
  arrayInvalidProps.push(property);
532
- else
876
+ } else
533
877
  arrayValue.push(sanitizeValue);
534
878
  }
535
879
  } else
@@ -550,14 +894,17 @@ class ParameterTypeConverter extends BaseResponse {
550
894
  for (const parameterInfo of methodInfo.parameters) {
551
895
  const value = jObject[parameterInfo.name];
552
896
  if (value !== void 0) {
553
- jObject[parameterInfo.name] = SANITIZERS[parameterInfo.type](value);
897
+ const sanitizedValue = SANITIZERS[parameterInfo.type](value);
898
+ if (sanitizedValue === null && sanitizedValue != value)
899
+ throw new HttpBadRequestException(CreateProblemDetail(parameterInfo.type, [{ [parameterInfo.name]: `The supplied data type must be "${parameterInfo.type}"` }]));
900
+ jObject[parameterInfo.name] = sanitizedValue;
554
901
  }
555
902
  }
556
903
  return jObject;
557
904
  }
558
905
  convertToInstance(entityName, data) {
559
906
  const typesInfo = this.types[entityName];
560
- const target = this.getClassTarget(typesInfo.path) || entityContainer.getTarget(entityName);
907
+ const target = this.getClassTarget(typesInfo.path, entityName) || entityContainer.getTarget(entityName);
561
908
  let instance = null;
562
909
  if (target) {
563
910
  instance = new target();
@@ -566,11 +913,10 @@ class ParameterTypeConverter extends BaseResponse {
566
913
  instance = data;
567
914
  return instance;
568
915
  }
569
- getClassTarget(resolver) {
570
- if (resolver) {
571
- const classInfo = resolver();
572
- const name = Object.keys(classInfo)[0];
573
- return classInfo[name];
916
+ getClassTarget(path, entityName) {
917
+ if (path) {
918
+ const classInfo = nattyContainer.resolver(path);
919
+ return classInfo[entityName];
574
920
  }
575
921
  return void 0;
576
922
  }
@@ -606,8 +952,8 @@ class RouteParser extends ParameterTypeConverter {
606
952
  get httpMethod() {
607
953
  return this.httpContext.request.method.toLowerCase();
608
954
  }
609
- get appRoutes() {
610
- return nattyContainer.routes;
955
+ get compiledRoutes() {
956
+ return nattyContainer.getCompiledRoutes(this.httpMethod);
611
957
  }
612
958
  init() {
613
959
  const isMatched = this.matchRoute();
@@ -620,47 +966,46 @@ class RouteParser extends ParameterTypeConverter {
620
966
  return controllerInfo[name];
621
967
  }
622
968
  matchRoute() {
623
- let isMatched = false;
624
- const requestPathname = this.getRequestPathname();
625
- for (const [key, value] of Object.entries(this.appRoutes)) {
626
- const rootPath = key;
627
- const routeConfig = value;
628
- const childRoutes = routeConfig[this.httpMethod];
629
- if (childRoutes) {
630
- for (const [key2, value2] of Object.entries(childRoutes)) {
631
- const childPath = key2.indexOf(common.RIGHT_SLASH) == 0 ? key2 === common.RIGHT_SLASH ? common.BLANK : key2 : `/${key2}`;
632
- const methodInfo = value2;
633
- const configuredRoutePath = `${rootPath}${childPath}`;
634
- const routeMatch = pathToRegexp.match(`${rootPath}${childPath}`, { decode: decodeURIComponent });
635
- const matched = routeMatch(requestPathname);
636
- if (matched) {
637
- isMatched = true;
638
- this.routeInfo = {
639
- path: `${common.commonContainer.nattyConfig.api.rootPath}/${requestPathname}`,
640
- configuredRoutePath: `${common.commonContainer.nattyConfig.api.rootPath}/${configuredRoutePath}`,
641
- controller: this.getController(routeConfig),
642
- parameters: routeConfig.parameters,
643
- methodInfo,
644
- params: this.convert(methodInfo, matched.params),
645
- queryParams: this.getQueryParams()
646
- };
647
- break;
648
- }
649
- }
969
+ const requestUrl = this.getRequestUrl();
970
+ const requestPathname = this.getRequestPathname(requestUrl);
971
+ for (const route of this.compiledRoutes) {
972
+ const matched = route.matcher(requestPathname);
973
+ if (matched) {
974
+ this.routeInfo = {
975
+ path: `${common.commonContainer.nattyConfig.api.rootPath}/${requestPathname}`,
976
+ configuredRoutePath: `${common.commonContainer.nattyConfig.api.rootPath}/${route.configuredRoutePath}`,
977
+ controller: this.getController(route.routeConfig),
978
+ parameters: route.routeConfig.parameters,
979
+ methodInfo: route.methodInfo,
980
+ params: this.convert(route.methodInfo, matched.params),
981
+ queryParams: this.getQueryParams(requestUrl)
982
+ };
983
+ return true;
650
984
  }
651
985
  }
652
- return isMatched;
653
- }
654
- getRequestPathname() {
655
- const apiRootPath = common.commonContainer.nattyConfig.api.rootPath;
656
- const url = new URL(this.httpContext.request.url);
657
- let splitUrl = url.pathname.split(`${apiRootPath}/`);
658
- if (splitUrl.length > 1)
659
- return splitUrl[1];
660
- return url.pathname;
661
- }
662
- getQueryParams() {
663
- const url = new URL(this.httpContext.request.url);
986
+ return false;
987
+ }
988
+ getRequestUrl() {
989
+ if (!this.parsedRequestUrl)
990
+ this.parsedRequestUrl = new URL(this.httpContext.request.url);
991
+ return this.parsedRequestUrl;
992
+ }
993
+ getRequestPathname(url) {
994
+ const apiRootPath = String(common.commonContainer.nattyConfig.api.rootPath || "").replace(/^\/+|\/+$/g, "");
995
+ const normalizedPathname = url.pathname.replace(/^\/+/, "");
996
+ if (!apiRootPath) {
997
+ return normalizedPathname;
998
+ }
999
+ if (normalizedPathname === apiRootPath) {
1000
+ return "";
1001
+ }
1002
+ const apiPrefix = `${apiRootPath}/`;
1003
+ if (normalizedPathname.startsWith(apiPrefix)) {
1004
+ return normalizedPathname.slice(apiPrefix.length);
1005
+ }
1006
+ return normalizedPathname;
1007
+ }
1008
+ getQueryParams(url) {
664
1009
  const queryParams = {};
665
1010
  for (const param of url.searchParams.keys())
666
1011
  queryParams[param] = url.searchParams.get(param);
@@ -668,20 +1013,13 @@ class RouteParser extends ParameterTypeConverter {
668
1013
  }
669
1014
  }
670
1015
 
671
- class UnauthorizedAccessException extends HttpException {
672
- constructor(data) {
673
- super({
674
- body: data,
675
- status: 401
676
- });
677
- }
678
- }
679
-
680
1016
  const decoratorStateContainer = new class {
681
1017
  constructor() {
682
1018
  this.controllerConfig = {};
1019
+ this.controllerSources = /* @__PURE__ */ new Map();
1020
+ this.sourceControllers = /* @__PURE__ */ new Map();
683
1021
  }
684
- register(params, type, additionalConfig) {
1022
+ register(params, type, additionalConfig, sourceFile) {
685
1023
  const name = params.target.name || params.target.constructor.name;
686
1024
  let controllerInfo = this.controllerConfig[name] || null;
687
1025
  let controllerMethodInfo = null;
@@ -694,6 +1032,9 @@ const decoratorStateContainer = new class {
694
1032
  controllerMethodInfo[type] = additionalConfig;
695
1033
  } else
696
1034
  controllerInfo.config[type] = additionalConfig;
1035
+ if (sourceFile) {
1036
+ this.trackControllerSource(name, sourceFile);
1037
+ }
697
1038
  }
698
1039
  getInfo(controllerName, methodName, type) {
699
1040
  const controllerInfo = this.controllerConfig[controllerName];
@@ -706,6 +1047,55 @@ const decoratorStateContainer = new class {
706
1047
  methodConfig = methodInfo[type];
707
1048
  return { controllerConfig, methodConfig };
708
1049
  }
1050
+ clearFromSource(sourceFile) {
1051
+ const normalizedSourceFile = this.normalizeFilePath(sourceFile);
1052
+ const controllerNames = Array.from(
1053
+ this.sourceControllers.get(normalizedSourceFile) || []
1054
+ );
1055
+ this.clearControllers(controllerNames);
1056
+ this.sourceControllers.delete(normalizedSourceFile);
1057
+ return controllerNames;
1058
+ }
1059
+ clearControllers(controllerNames) {
1060
+ const removedControllers = [];
1061
+ for (const controllerName of controllerNames) {
1062
+ const previousSource = this.controllerSources.get(controllerName);
1063
+ delete this.controllerConfig[controllerName];
1064
+ this.controllerSources.delete(controllerName);
1065
+ removedControllers.push(controllerName);
1066
+ if (previousSource) {
1067
+ const controllers = this.sourceControllers.get(previousSource);
1068
+ controllers?.delete(controllerName);
1069
+ if (controllers && controllers.size === 0) {
1070
+ this.sourceControllers.delete(previousSource);
1071
+ }
1072
+ }
1073
+ }
1074
+ return removedControllers;
1075
+ }
1076
+ reset() {
1077
+ this.controllerConfig = {};
1078
+ this.controllerSources.clear();
1079
+ this.sourceControllers.clear();
1080
+ }
1081
+ trackControllerSource(controllerName, sourceFile) {
1082
+ const normalizedSourceFile = this.normalizeFilePath(sourceFile);
1083
+ const previousSource = this.controllerSources.get(controllerName);
1084
+ if (previousSource && previousSource !== normalizedSourceFile) {
1085
+ this.sourceControllers.get(previousSource)?.delete(controllerName);
1086
+ if (this.sourceControllers.get(previousSource)?.size === 0) {
1087
+ this.sourceControllers.delete(previousSource);
1088
+ }
1089
+ }
1090
+ this.controllerSources.set(controllerName, normalizedSourceFile);
1091
+ if (!this.sourceControllers.has(normalizedSourceFile)) {
1092
+ this.sourceControllers.set(normalizedSourceFile, /* @__PURE__ */ new Set());
1093
+ }
1094
+ this.sourceControllers.get(normalizedSourceFile)?.add(controllerName);
1095
+ }
1096
+ normalizeFilePath(filePath) {
1097
+ return path__default.resolve(filePath).replace(/\\/g, "/");
1098
+ }
709
1099
  }();
710
1100
 
711
1101
  var DecoratorType = /* @__PURE__ */ ((DecoratorType2) => {
@@ -722,22 +1112,13 @@ var DecoratorType = /* @__PURE__ */ ((DecoratorType2) => {
722
1112
  return DecoratorType2;
723
1113
  })(DecoratorType || {});
724
1114
 
725
- class ForbiddenAccessException extends HttpException {
726
- constructor(data) {
727
- super({
728
- body: data,
729
- status: 403
730
- });
731
- }
732
- }
733
-
734
1115
  class AbstractExecutionContext {
735
1116
  constructor(context, routeInfo) {
736
1117
  this.context = context;
737
1118
  this.routeInfo = routeInfo;
738
1119
  }
739
1120
  resolveService(instance) {
740
- return tsyringe.container.resolve(instance);
1121
+ return this.context.services.get(instance);
741
1122
  }
742
1123
  get request() {
743
1124
  return this.context.request;
@@ -760,14 +1141,6 @@ class ActionExecutingContext extends AbstractExecutionContext {
760
1141
  }
761
1142
  }
762
1143
 
763
- function CreateProblemDetail(modelName, detail) {
764
- return {
765
- type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
766
- title: `The specified ${modelName} model props are invalid.`,
767
- detail
768
- };
769
- }
770
-
771
1144
  function runValidators(entityName, value) {
772
1145
  const typeInfo = nattyContainer.types[entityName];
773
1146
  let errors = {};
@@ -790,7 +1163,7 @@ function runValidators(entityName, value) {
790
1163
  errors[propertyInfo.name] = arrayPropErrors.length > 0 ? arrayPropErrors : null;
791
1164
  } else
792
1165
  errors[propertyInfo.name] = runValidators(childEntityName, propValue);
793
- if (Array.isArray(errors[propertyInfo.name]) && errors[propertyInfo.name].length == 0 || Object.keys(errors[propertyInfo.name]).length == 0)
1166
+ if (Array.isArray(errors[propertyInfo.name]) && errors[propertyInfo.name].length == 0 || Object.keys(errors[propertyInfo.name] ?? {}).length == 0)
794
1167
  errors[propertyInfo.name] = null;
795
1168
  }
796
1169
  } else {
@@ -815,11 +1188,12 @@ function getTypeName(typeName) {
815
1188
  }
816
1189
 
817
1190
  class ModelBindingContext extends ParameterTypeConverter {
818
- constructor(type, typeInfo, data) {
1191
+ constructor(type, typeInfo, data, throwOnValidationError = false) {
819
1192
  super();
820
1193
  this.type = type;
821
1194
  this.typeInfo = typeInfo;
822
1195
  this.data = data;
1196
+ this.throwOnValidationError = throwOnValidationError;
823
1197
  this.serialize();
824
1198
  }
825
1199
  serialize() {
@@ -829,6 +1203,8 @@ class ModelBindingContext extends ParameterTypeConverter {
829
1203
  else
830
1204
  this.data = body;
831
1205
  this.instance = this.convertToInstance(this.type, this.data);
1206
+ if (this.throwOnValidationError && !this.isValid)
1207
+ throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
832
1208
  }
833
1209
  get isValid() {
834
1210
  const errors = runValidators(this.type, this.instance);
@@ -845,6 +1221,17 @@ class ActionExecutedContext extends AbstractExecutionContext {
845
1221
  super(httpContext, routeInfo);
846
1222
  this.content = content;
847
1223
  }
1224
+ get response() {
1225
+ return this.context.response;
1226
+ }
1227
+ }
1228
+
1229
+ class AuthorizationContext extends AbstractExecutionContext {
1230
+ constructor(models, context, routeInfo, config) {
1231
+ super(context, routeInfo);
1232
+ this.models = models;
1233
+ this.config = config;
1234
+ }
848
1235
  }
849
1236
 
850
1237
  class RequestProcessor extends RouteParser {
@@ -857,13 +1244,10 @@ class RequestProcessor extends RouteParser {
857
1244
  case RequestPipeline.onAuthentication:
858
1245
  await this.onAuthentication();
859
1246
  break;
860
- case RequestPipeline.onAuthorization:
861
- await this.onAuthorization();
862
- break;
863
1247
  }
864
1248
  }
865
1249
  resolveFilter(instance) {
866
- return tsyringe.container.resolve(instance);
1250
+ return this.httpContext.services.get(instance);
867
1251
  }
868
1252
  getAuthenticationClass() {
869
1253
  let authentication = void 0;
@@ -880,26 +1264,37 @@ class RequestProcessor extends RouteParser {
880
1264
  const authentication = this.getAuthenticationClass();
881
1265
  const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
882
1266
  const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
1267
+ if (!authenticationFilter) {
1268
+ if (common.commonContainer.nattyConfig?.secure?.denyByDefault && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
1269
+ throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
1270
+ return;
1271
+ }
883
1272
  if (authenticationFilter) {
884
1273
  const result = await authenticationFilter.onAuthentication(this.httpContext);
885
1274
  this.httpContext.user = result;
886
1275
  if (!result.isAuthenticate && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
887
1276
  throw new UnauthorizedAccessException(authenticationFilter.onFailedResponse());
888
- await this.onAuthorization();
889
1277
  }
890
1278
  }
891
- async onAuthorization() {
1279
+ async onAuthorization(methodParameters) {
892
1280
  const authorization = common.commonContainer.globalConfig.authorization;
893
1281
  const authorizationFilter = authorization ? this.resolveFilter(authorization) : void 0;
894
1282
  const authorizeConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authorize);
895
1283
  const authenticationOnly = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authenticationOnly);
896
- if (this.httpContext.user?.isAuthenticate && authorizationFilter && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
897
- const result = await authorizationFilter.onAuthorization(this.httpContext, authorizeConfig.methodConfig || authorizeConfig.controllerConfig);
1284
+ if (this.httpContext.user?.isAuthenticate && authorizationFilter && (authorizeConfig.controllerConfig || authorizeConfig.methodConfig) && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
1285
+ const authorizationContext = new AuthorizationContext(
1286
+ methodParameters.filter((t) => t instanceof ModelBindingContext),
1287
+ this.httpContext,
1288
+ this.routeInfo,
1289
+ authorizeConfig.methodConfig || authorizeConfig.controllerConfig
1290
+ );
1291
+ const result = await authorizationFilter.onAuthorization(authorizationContext, authorizationContext.config);
898
1292
  if (!result)
899
1293
  throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
900
1294
  }
901
1295
  }
902
1296
  async onActionExecuting(methodParameters) {
1297
+ await this.onAuthorization(methodParameters);
903
1298
  let actionFilters = common.commonContainer.globalConfig.actionFilters || [];
904
1299
  const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
905
1300
  actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
@@ -929,9 +1324,227 @@ class RequestProcessor extends RouteParser {
929
1324
  }
930
1325
  }
931
1326
 
1327
+ const PARAM_TOKENS_KEY = Symbol.for("natty:di:paramtokens");
1328
+ function getParamTokens(Cls) {
1329
+ return Reflect.getMetadata(PARAM_TOKENS_KEY, Cls);
1330
+ }
1331
+
1332
+ function isClassToken(x) {
1333
+ return typeof x === "function";
1334
+ }
1335
+
1336
+ var Lifetime = /* @__PURE__ */ ((Lifetime2) => {
1337
+ Lifetime2["Singleton"] = "singleton";
1338
+ Lifetime2["Scoped"] = "scoped";
1339
+ Lifetime2["Transient"] = "transient";
1340
+ return Lifetime2;
1341
+ })(Lifetime || {});
1342
+
1343
+ function isDisposable(x) {
1344
+ return x && typeof x.dispose === "function";
1345
+ }
1346
+
1347
+ class NattyScope {
1348
+ constructor(root) {
1349
+ this.root = root;
1350
+ this.scoped = /* @__PURE__ */ new Map();
1351
+ this.disposables = [];
1352
+ }
1353
+ createScope() {
1354
+ return new NattyScope(this.root);
1355
+ }
1356
+ set(token, value) {
1357
+ this.scoped.set(token, value);
1358
+ if (isDisposable(value))
1359
+ this.disposables.push(value);
1360
+ }
1361
+ tryGet(token) {
1362
+ try {
1363
+ return this.get(token);
1364
+ } catch {
1365
+ return void 0;
1366
+ }
1367
+ }
1368
+ get(token) {
1369
+ if (this.scoped.has(token))
1370
+ return this.scoped.get(token);
1371
+ const desc = this.root._getDescriptor(token);
1372
+ if (!desc) {
1373
+ if (typeof token === "function")
1374
+ return this.root.construct(token, this);
1375
+ throw new Error(`DI: No registration for token: ${String(token)}`);
1376
+ }
1377
+ if (desc.lifetime === Lifetime.Singleton) {
1378
+ return this.root.get(token);
1379
+ }
1380
+ if (desc.lifetime === Lifetime.Scoped) {
1381
+ const created = desc.useFactory ? desc.useFactory(this) : this.root.construct(desc.useClass, this);
1382
+ this.scoped.set(token, created);
1383
+ if (isDisposable(created))
1384
+ this.disposables.push(created);
1385
+ return created;
1386
+ }
1387
+ return desc.useFactory ? desc.useFactory(this) : this.root.construct(desc.useClass, this);
1388
+ }
1389
+ async dispose() {
1390
+ for (let i = this.disposables.length - 1; i >= 0; i--) {
1391
+ const d = this.disposables[i];
1392
+ await d.dispose();
1393
+ }
1394
+ this.disposables.length = 0;
1395
+ this.scoped.clear();
1396
+ }
1397
+ }
1398
+
1399
+ function normalizeFilePath$1(filePath) {
1400
+ return path__default.resolve(filePath).replace(/\\/g, "/");
1401
+ }
1402
+ class NattyContainer {
1403
+ constructor() {
1404
+ this.regs = /* @__PURE__ */ new Map();
1405
+ this.singletons = /* @__PURE__ */ new Map();
1406
+ this.tokenSources = /* @__PURE__ */ new Map();
1407
+ this.sourceTokens = /* @__PURE__ */ new Map();
1408
+ this.metadataKeySources = /* @__PURE__ */ new Map();
1409
+ this.sourceMetadataKeys = /* @__PURE__ */ new Map();
1410
+ }
1411
+ register(token, desc, sourceFile) {
1412
+ this.regs.set(token, desc);
1413
+ if (sourceFile) {
1414
+ this.trackTokenSource(token, sourceFile);
1415
+ }
1416
+ }
1417
+ addTransient(token, useClass, useFactory, sourceFile) {
1418
+ this.register(
1419
+ token,
1420
+ { lifetime: Lifetime.Transient, useClass: useClass ?? token, useFactory },
1421
+ sourceFile
1422
+ );
1423
+ }
1424
+ addScoped(token, useClass, useFactory, sourceFile) {
1425
+ this.register(
1426
+ token,
1427
+ { lifetime: Lifetime.Scoped, useClass: useClass ?? token, useFactory },
1428
+ sourceFile
1429
+ );
1430
+ }
1431
+ addSingleton(token, useClass, useFactory, sourceFile) {
1432
+ this.register(
1433
+ token,
1434
+ { lifetime: Lifetime.Singleton, useClass: useClass ?? token, useFactory },
1435
+ sourceFile
1436
+ );
1437
+ }
1438
+ addInstance(token, value, sourceFile) {
1439
+ this.register(token, { lifetime: Lifetime.Singleton, useValue: value }, sourceFile);
1440
+ this.singletons.set(token, value);
1441
+ }
1442
+ createScope() {
1443
+ return new NattyScope(this);
1444
+ }
1445
+ set(_token, _value) {
1446
+ throw new Error("Use scope.set(token, value) for per-request instances.");
1447
+ }
1448
+ tryGet(token) {
1449
+ try {
1450
+ return this.get(token);
1451
+ } catch {
1452
+ return void 0;
1453
+ }
1454
+ }
1455
+ get(token) {
1456
+ const desc = this.regs.get(token);
1457
+ if (!desc) {
1458
+ if (isClassToken(token))
1459
+ return this.construct(token, this);
1460
+ throw new Error(`DI: No registration for token: ${String(token)}`);
1461
+ }
1462
+ if (desc.lifetime === Lifetime.Singleton) {
1463
+ if (desc.useValue !== void 0)
1464
+ return desc.useValue;
1465
+ if (this.singletons.has(token))
1466
+ return this.singletons.get(token);
1467
+ const created = desc.useFactory ? desc.useFactory(this) : this.construct(desc.useClass, this);
1468
+ this.singletons.set(token, created);
1469
+ return created;
1470
+ }
1471
+ throw new Error(
1472
+ `DI: Tried to resolve ${desc.lifetime} service from root container. Use httpContext.services.get(...)`
1473
+ );
1474
+ }
1475
+ construct(Cls, sp) {
1476
+ const paramTypes = Reflect.getMetadata("design:paramtypes", Cls) || [];
1477
+ const overrideTokens = getParamTokens(Cls) || [];
1478
+ const args = paramTypes.map((t, i) => sp.get(overrideTokens[i] ?? t));
1479
+ return new Cls(...args);
1480
+ }
1481
+ _getDescriptor(token) {
1482
+ return this.regs.get(token);
1483
+ }
1484
+ trackMetadataKey(sourceFile, key) {
1485
+ const normalizedSourceFile = normalizeFilePath$1(sourceFile);
1486
+ const previousSource = this.metadataKeySources.get(key);
1487
+ if (previousSource && previousSource !== normalizedSourceFile) {
1488
+ this.sourceMetadataKeys.get(previousSource)?.delete(key);
1489
+ if (this.sourceMetadataKeys.get(previousSource)?.size === 0) {
1490
+ this.sourceMetadataKeys.delete(previousSource);
1491
+ }
1492
+ }
1493
+ this.metadataKeySources.set(key, normalizedSourceFile);
1494
+ if (!this.sourceMetadataKeys.has(normalizedSourceFile)) {
1495
+ this.sourceMetadataKeys.set(normalizedSourceFile, /* @__PURE__ */ new Set());
1496
+ }
1497
+ this.sourceMetadataKeys.get(normalizedSourceFile)?.add(key);
1498
+ }
1499
+ clearRegistrationsFromSource(sourceFile) {
1500
+ const normalizedSourceFile = normalizeFilePath$1(sourceFile);
1501
+ const tokens = Array.from(this.sourceTokens.get(normalizedSourceFile) || []);
1502
+ const metadataKeys = Array.from(
1503
+ this.sourceMetadataKeys.get(normalizedSourceFile) || []
1504
+ );
1505
+ for (const token of tokens) {
1506
+ this.regs.delete(token);
1507
+ this.singletons.delete(token);
1508
+ this.tokenSources.delete(token);
1509
+ }
1510
+ for (const metadataKey of metadataKeys) {
1511
+ this.metadataKeySources.delete(metadataKey);
1512
+ }
1513
+ this.sourceTokens.delete(normalizedSourceFile);
1514
+ this.sourceMetadataKeys.delete(normalizedSourceFile);
1515
+ return {
1516
+ metadataKeys,
1517
+ tokens
1518
+ };
1519
+ }
1520
+ trackTokenSource(token, sourceFile) {
1521
+ const normalizedSourceFile = normalizeFilePath$1(sourceFile);
1522
+ const previousSource = this.tokenSources.get(token);
1523
+ if (previousSource && previousSource !== normalizedSourceFile) {
1524
+ this.sourceTokens.get(previousSource)?.delete(token);
1525
+ if (this.sourceTokens.get(previousSource)?.size === 0) {
1526
+ this.sourceTokens.delete(previousSource);
1527
+ }
1528
+ }
1529
+ this.tokenSources.set(token, normalizedSourceFile);
1530
+ if (!this.sourceTokens.has(normalizedSourceFile)) {
1531
+ this.sourceTokens.set(normalizedSourceFile, /* @__PURE__ */ new Set());
1532
+ }
1533
+ this.sourceTokens.get(normalizedSourceFile)?.add(token);
1534
+ }
1535
+ }
1536
+
1537
+ const nattyServiceResolver = new NattyContainer();
1538
+
932
1539
  class Resolver extends RequestProcessor {
933
1540
  constructor(httpContext) {
934
1541
  super(httpContext);
1542
+ this.registerDependency();
1543
+ }
1544
+ registerDependency() {
1545
+ this.httpContext.services = nattyServiceResolver.createScope();
1546
+ common.commonContainer.setMetadata(HttpContext.name, HttpContext, "services");
1547
+ this.httpContext.services.set(HttpContext, this.httpContext);
935
1548
  }
936
1549
  getControllerInstance() {
937
1550
  const controller = this.routeInfo.controller;
@@ -939,18 +1552,27 @@ class Resolver extends RequestProcessor {
939
1552
  const instance = new controller(...parameters);
940
1553
  return instance;
941
1554
  }
942
- resolveClass(classConstruct) {
943
- return tsyringe.container.resolve(classConstruct);
1555
+ resolveClass(token) {
1556
+ return this.httpContext.services.get(token);
944
1557
  }
945
1558
  resolveConstructorParameters() {
946
1559
  let parameters = [];
947
1560
  for (const parameter of this.routeInfo.parameters) {
948
- const classConstruct = this.getClass(parameter.type);
949
- if (classConstruct)
950
- parameters.push(this.resolveClass(classConstruct));
1561
+ const token = this.getConstructorParameterToken(parameter);
1562
+ if (token)
1563
+ parameters.push(this.resolveClass(token));
951
1564
  }
952
1565
  return parameters;
953
1566
  }
1567
+ getConstructorParameterToken(parameter) {
1568
+ if (parameter.tokenKey) {
1569
+ return Symbol.for(parameter.tokenKey);
1570
+ }
1571
+ if (parameter.type) {
1572
+ return this.getClass(parameter.type);
1573
+ }
1574
+ return void 0;
1575
+ }
954
1576
  getMethodParameters() {
955
1577
  const parameters = new Array();
956
1578
  for (const parameter of this.routeInfo.methodInfo.parameters) {
@@ -962,7 +1584,7 @@ class Resolver extends RequestProcessor {
962
1584
  else if (queryParams[parameter.name] !== void 0)
963
1585
  parameters.push(queryParams[parameter.name]);
964
1586
  else if (typeInfo && this.httpContext.request.body.json) {
965
- const context = new ModelBindingContext(parameter.type, typeInfo.props, this.httpContext.request.body.json);
1587
+ const context = new ModelBindingContext(parameter.type, typeInfo.props, this.httpContext.request.body.json, true);
966
1588
  parameters.push(context);
967
1589
  }
968
1590
  }
@@ -1015,14 +1637,14 @@ class Resolver extends RequestProcessor {
1015
1637
  if (onException) {
1016
1638
  const instance = this.resolveClass(onException);
1017
1639
  if (instance.onException)
1018
- result = instance.onException({
1640
+ result = this.normalizeHttpResponse(instance.onException({
1019
1641
  error: ex,
1020
1642
  request: this.httpContext.request,
1021
1643
  routeInfo: this.routeInfo
1022
- });
1644
+ }));
1023
1645
  } else
1024
1646
  result = new HttpException({
1025
- body: getPreResponseBody({ message: ex.message, stack: ex.stack }),
1647
+ body: { message: ex.message, stack: ex.stack },
1026
1648
  status: HttpStatusCode.serverError
1027
1649
  }).getResponse();
1028
1650
  }
@@ -1050,14 +1672,17 @@ class RequestHandler extends Resolver {
1050
1672
  if (onException) {
1051
1673
  const instance = this.resolveClass(onException);
1052
1674
  if (instance.onException)
1053
- return instance.onException({
1675
+ return this.normalizeHttpResponse(instance.onException({
1054
1676
  error: ex,
1055
1677
  request: this.httpContext.request,
1056
1678
  routeInfo: this.routeInfo
1057
- });
1679
+ }));
1058
1680
  } else
1059
1681
  return new HttpException({
1060
- body: ex,
1682
+ body: {
1683
+ message: ex?.message,
1684
+ stack: ex?.stack
1685
+ },
1061
1686
  status: HttpStatusCode.serverError
1062
1687
  });
1063
1688
  }
@@ -1070,46 +1695,59 @@ class HttpHandler {
1070
1695
  async processRequest(httpContext) {
1071
1696
  const requestProcessor = new RequestHandler(httpContext);
1072
1697
  const result = await requestProcessor.onRequest();
1073
- return result;
1698
+ if (result instanceof HttpResponse) {
1699
+ return result;
1700
+ }
1701
+ if (result instanceof HttpException) {
1702
+ return result.getResponse();
1703
+ }
1704
+ return new HttpResponse({ body: result });
1074
1705
  }
1075
1706
  }
1076
1707
 
1077
- class HttpRequest {
1078
- constructor(http) {
1079
- this.httpRequest = http;
1080
- }
1081
- get cookies() {
1082
- return this.httpRequest.cookies;
1083
- }
1084
- get url() {
1085
- return this.httpRequest.url;
1086
- }
1087
- get method() {
1088
- return this.httpRequest.method;
1089
- }
1090
- get headers() {
1091
- return this.httpRequest.headers;
1092
- }
1093
- get user() {
1094
- return null;
1095
- }
1096
- get body() {
1097
- return this.httpRequest.body;
1098
- }
1708
+ const STACK_PATH_REGEX = /\bat (?:(?:.+?) \()?(.+):(\d+):(\d+)\)?$/;
1709
+ function normalizeFilePath(filePath) {
1710
+ return path__default.resolve(filePath).replace(/\\/g, "/");
1099
1711
  }
1100
-
1101
- class HttpContext {
1102
- constructor(request, context) {
1103
- this.request = new HttpRequest(request);
1104
- this.response = new HttpResponse();
1105
- this.context = context;
1712
+ function isInternalRegistrationFrame(filePath) {
1713
+ const normalizedPath = normalizeFilePath(filePath);
1714
+ 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/");
1715
+ }
1716
+ function getRegistrationSourceFile() {
1717
+ const stack = new Error().stack;
1718
+ return getRegistrationSourceFileFromStack(stack);
1719
+ }
1720
+ function getRegistrationSourceFileFromStack(stack) {
1721
+ if (!stack) {
1722
+ return void 0;
1723
+ }
1724
+ const lines = stack.split("\n").slice(1);
1725
+ for (const line of lines) {
1726
+ const match = line.trim().match(STACK_PATH_REGEX);
1727
+ if (!match) {
1728
+ continue;
1729
+ }
1730
+ const filePath = normalizeFilePath(match[1]);
1731
+ if (!isInternalRegistrationFrame(filePath)) {
1732
+ return filePath;
1733
+ }
1106
1734
  }
1735
+ return void 0;
1107
1736
  }
1108
1737
 
1109
1738
  function injectable(options = {}) {
1110
1739
  return (targetConstructor) => {
1111
- tsyringe.injectable()(targetConstructor);
1740
+ const lt = options.lifetime ?? Lifetime.Transient;
1741
+ const sourceFile = getRegistrationSourceFile();
1742
+ if (lt === Lifetime.Singleton)
1743
+ nattyServiceResolver.addSingleton(targetConstructor, void 0, void 0, sourceFile);
1744
+ else if (lt === Lifetime.Scoped)
1745
+ nattyServiceResolver.addScoped(targetConstructor, void 0, void 0, sourceFile);
1746
+ else
1747
+ nattyServiceResolver.addTransient(targetConstructor, void 0, void 0, sourceFile);
1112
1748
  common.commonContainer.setMetadata(targetConstructor.name, targetConstructor, "services");
1749
+ if (sourceFile)
1750
+ nattyServiceResolver.trackMetadataKey(sourceFile, targetConstructor.name);
1113
1751
  };
1114
1752
  }
1115
1753
 
@@ -1121,7 +1759,7 @@ function $request(request) {
1121
1759
 
1122
1760
  function filter(config) {
1123
1761
  return (targetConstructor) => {
1124
- tsyringe.injectable()(targetConstructor);
1762
+ injectable({ lifetime: Lifetime.Transient })(targetConstructor);
1125
1763
  };
1126
1764
  }
1127
1765
 
@@ -1150,63 +1788,257 @@ class BaseController {
1150
1788
  }
1151
1789
 
1152
1790
  class OkResult extends BaseResult {
1153
- constructor(value, response) {
1154
- super({ ...{ body: getResponseBodyObject(value) }, ...{ status: HttpStatusCode.success } }, response);
1155
- this.value = value;
1791
+ constructor(value, extras) {
1792
+ super(
1793
+ {
1794
+ status: HttpStatusCode.success,
1795
+ body: getResponseBodyObject(value ?? common.BLANK)
1796
+ },
1797
+ extras
1798
+ );
1156
1799
  }
1157
1800
  }
1158
- function ok(value, response) {
1159
- return new OkResult(value || common.BLANK, response);
1801
+ function ok(value, extras) {
1802
+ return new OkResult(value, extras);
1160
1803
  }
1161
1804
 
1162
- class NotFoundResult extends BaseResult {
1163
- constructor(response) {
1164
- super({ ...{ body: common.BLANK }, ...{ status: HttpStatusCode.notFound } }, response);
1805
+ class CreatedResult extends BaseResult {
1806
+ constructor(value, extras) {
1807
+ super({ status: HttpStatusCode.created, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1808
+ }
1809
+ }
1810
+ function created(value, extras) {
1811
+ return new CreatedResult(value, extras);
1812
+ }
1813
+ function createdWith(location, value, extras) {
1814
+ const merged = {
1815
+ ...extras ?? {},
1816
+ headers: { ...extras?.headers ?? {}, Location: location }
1817
+ };
1818
+ return new CreatedResult(value, merged);
1819
+ }
1820
+ function createdAt(location, value, extras) {
1821
+ return createdWith(location, value, extras);
1822
+ }
1823
+
1824
+ class AcceptedResult extends BaseResult {
1825
+ constructor(value, extras) {
1826
+ super({ status: HttpStatusCode.accepted, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1827
+ this.value = value;
1165
1828
  }
1166
1829
  }
1167
- function notFound(response) {
1168
- return new NotFoundResult(response);
1830
+ function accepted(value, extras) {
1831
+ return new AcceptedResult(value, extras);
1169
1832
  }
1170
1833
 
1171
1834
  class NoContentResult extends BaseResult {
1172
- constructor(response) {
1173
- super({ ...{ body: common.BLANK }, ...{ status: HttpStatusCode.noContent } }, response);
1835
+ constructor(extras) {
1836
+ super(
1837
+ {
1838
+ status: HttpStatusCode.noContent,
1839
+ body: void 0
1840
+ },
1841
+ extras
1842
+ );
1843
+ }
1844
+ }
1845
+ function noContent(extras) {
1846
+ return new NoContentResult(extras);
1847
+ }
1848
+
1849
+ class BadRequestResult extends BaseResult {
1850
+ constructor(value, extras) {
1851
+ super({ status: HttpStatusCode.badRequest, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1852
+ this.value = value;
1853
+ }
1854
+ }
1855
+ function badRequest(value, extras) {
1856
+ return new BadRequestResult(value, extras);
1857
+ }
1858
+
1859
+ class UnAuthorizedResult extends BaseResult {
1860
+ constructor(value, extras) {
1861
+ super({ status: HttpStatusCode.unAuthorized, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1862
+ this.value = value;
1174
1863
  }
1175
1864
  }
1176
- function noContent(response) {
1177
- return new NoContentResult(response);
1865
+ function unAuthorized(value, extras) {
1866
+ return new UnAuthorizedResult(value, extras);
1178
1867
  }
1179
1868
 
1180
1869
  class ForbiddenAccessInfoResult extends BaseResult {
1181
- constructor(value, response) {
1182
- super({ ...{ body: value }, ...{ status: HttpStatusCode.forbiddenAccess } }, response);
1870
+ constructor(value, extras) {
1871
+ super(
1872
+ {
1873
+ status: HttpStatusCode.forbiddenAccess,
1874
+ body: getResponseBodyObject(value ?? common.BLANK)
1875
+ },
1876
+ extras
1877
+ );
1183
1878
  }
1184
1879
  }
1185
- function forbiddenAccessInfo(value, response) {
1186
- return new ForbiddenAccessInfoResult(value, response);
1880
+ function forbiddenAccessInfo(value, extras) {
1881
+ return new ForbiddenAccessInfoResult(value, extras);
1882
+ }
1883
+ function forbiddenAccess(value, extras) {
1884
+ return new ForbiddenAccessInfoResult(value, extras);
1187
1885
  }
1188
1886
 
1189
- class CreatedResult extends BaseResult {
1190
- constructor(response) {
1191
- super({ ...{ body: common.BLANK }, ...{ status: HttpStatusCode.created } }, response);
1887
+ class NotFoundResult extends BaseResult {
1888
+ constructor(value, extras) {
1889
+ super(
1890
+ {
1891
+ status: HttpStatusCode.notFound,
1892
+ body: getResponseBodyObject(value ?? common.BLANK)
1893
+ },
1894
+ extras
1895
+ );
1192
1896
  }
1193
1897
  }
1194
- function created(response) {
1195
- return new CreatedResult(response);
1898
+ function notFound(extras) {
1899
+ return new NotFoundResult(common.BLANK, extras);
1900
+ }
1901
+ function notFoundWith(value, extras) {
1902
+ return new NotFoundResult(value, extras);
1196
1903
  }
1197
1904
 
1198
- class BadRequestResult extends BaseResult {
1199
- constructor(value, response) {
1200
- super({ ...{ body: value }, ...{ status: HttpStatusCode.badRequest } }, response);
1905
+ class ConflictResult extends BaseResult {
1906
+ constructor(value, extras) {
1907
+ super({ status: HttpStatusCode.conflict, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1201
1908
  this.value = value;
1202
1909
  }
1203
1910
  }
1204
- function badRequest(value, response) {
1205
- return new BadRequestResult(value || common.BLANK, response);
1911
+ function conflict(value, extras) {
1912
+ return new ConflictResult(value, extras);
1913
+ }
1914
+
1915
+ class UnprocessableEntityResult extends BaseResult {
1916
+ constructor(value, extras) {
1917
+ super({ status: HttpStatusCode.unprocessableEntity, body: getResponseBodyObject(value ?? common.BLANK) }, extras);
1918
+ this.value = value;
1919
+ }
1920
+ }
1921
+ function unprocessableEntity(value, extras) {
1922
+ return new UnprocessableEntityResult(value, extras);
1923
+ }
1924
+
1925
+ class TooManyRequestsResult extends BaseResult {
1926
+ constructor(value, retryAfterSeconds, extras) {
1927
+ const merged = {
1928
+ ...extras ?? {},
1929
+ headers: {
1930
+ ...extras?.headers ?? {},
1931
+ ...retryAfterSeconds != null ? { "Retry-After": String(retryAfterSeconds) } : {}
1932
+ }
1933
+ };
1934
+ super({ status: HttpStatusCode.tooManyRequests, body: getResponseBodyObject(value ?? common.BLANK) }, merged);
1935
+ this.value = value;
1936
+ }
1937
+ }
1938
+ function tooManyRequests(value, retryAfterSeconds, extras) {
1939
+ return new TooManyRequestsResult(value, retryAfterSeconds, extras);
1940
+ }
1941
+
1942
+ class RedirectResult extends BaseResult {
1943
+ constructor(location, permanent = false, extras) {
1944
+ const merged = {
1945
+ ...extras ?? {},
1946
+ headers: { ...extras?.headers ?? {}, Location: location }
1947
+ };
1948
+ super({ status: permanent ? HttpStatusCode.movedPermanently : HttpStatusCode.found, body: void 0 }, merged);
1949
+ }
1950
+ }
1951
+ function redirect(location, extras) {
1952
+ return new RedirectResult(location, false, extras);
1953
+ }
1954
+ function redirectPermanent(location, extras) {
1955
+ return new RedirectResult(location, true, extras);
1956
+ }
1957
+
1958
+ class ProblemResult extends BaseResult {
1959
+ constructor(problem2, extras) {
1960
+ const status = problem2.status ?? HttpStatusCode.serverError;
1961
+ const merged = {
1962
+ ...extras ?? {},
1963
+ headers: { ...extras?.headers ?? {}, "Content-Type": "application/problem+json; charset=utf-8" }
1964
+ };
1965
+ super({ status, body: { ...problem2, status } }, merged);
1966
+ }
1967
+ }
1968
+ function problem(problem2, extras) {
1969
+ return new ProblemResult(problem2, extras);
1970
+ }
1971
+ function validationProblem(errors, detail, extras) {
1972
+ return new ProblemResult(
1973
+ {
1974
+ type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
1975
+ title: "One or more validation errors occurred.",
1976
+ status: HttpStatusCode.badRequest,
1977
+ detail,
1978
+ errors
1979
+ },
1980
+ extras
1981
+ );
1982
+ }
1983
+
1984
+ class FileResult extends BaseResult {
1985
+ constructor(buffer, extras) {
1986
+ super({ status: HttpStatusCode.success, body: buffer, isBuffer: true }, extras);
1987
+ }
1988
+ }
1989
+ function file(buffer, extras) {
1990
+ return new FileResult(buffer, extras);
1991
+ }
1992
+
1993
+ class StatusCodeResult extends BaseResult {
1994
+ constructor(status, value, extras) {
1995
+ super(
1996
+ {
1997
+ status,
1998
+ body: getResponseBodyObject(value ?? common.BLANK)
1999
+ },
2000
+ extras
2001
+ );
2002
+ }
2003
+ }
2004
+ function statusCode(status, value, extras) {
2005
+ return new StatusCodeResult(status, value, extras);
1206
2006
  }
1207
2007
 
2008
+ const Results = {
2009
+ // 2xx
2010
+ ok: (value, extras) => ok(value, extras),
2011
+ created: (value, extras) => created(value, extras),
2012
+ createdWith: (location, value, extras) => createdWith(location, value, extras),
2013
+ createdAt: (location, value, extras) => createdAt(location, value, extras),
2014
+ accepted: (value, extras) => accepted(value, extras),
2015
+ noContent: (extras) => noContent(extras),
2016
+ file: (buffer, extras) => file(buffer, extras),
2017
+ statusCode: (status, value, extras) => statusCode(status, value, extras),
2018
+ // 4xx
2019
+ badRequest: (value, extras) => badRequest(value, extras),
2020
+ notFound: (extras) => notFound(extras),
2021
+ notFoundWith: (value, extras) => notFoundWith(value, extras),
2022
+ unAuthorized: (value, extras) => unAuthorized(value, extras),
2023
+ forbid: (value, extras) => forbiddenAccess(value, extras),
2024
+ conflict: (value, extras) => conflict(value, extras),
2025
+ unprocessableEntity: (value, extras) => unprocessableEntity(value, extras),
2026
+ tooManyRequests: (value, retryAfterSeconds, extras) => tooManyRequests(value, retryAfterSeconds, extras),
2027
+ // 3xx
2028
+ redirect: (location, extras) => redirect(location, extras),
2029
+ redirectPermanent: (location, extras) => redirectPermanent(location, extras),
2030
+ // problem
2031
+ problem: (p, extras) => problem(p, extras),
2032
+ validationProblem: (errors, detail, extras) => validationProblem(errors, detail, extras)
2033
+ };
2034
+
1208
2035
  function base(params, type, additionaConfig) {
1209
- decoratorStateContainer.register(params, type, additionaConfig);
2036
+ decoratorStateContainer.register(
2037
+ params,
2038
+ type,
2039
+ additionaConfig,
2040
+ getRegistrationSourceFile()
2041
+ );
1210
2042
  }
1211
2043
 
1212
2044
  function useFilter(config) {
@@ -1231,42 +2063,205 @@ function authenticationOnly() {
1231
2063
  };
1232
2064
  }
1233
2065
 
2066
+ function onException(exceptionFilter) {
2067
+ return function(target, propertyKey, descriptor) {
2068
+ base({ target, propertyKey, descriptor }, DecoratorType.onException, exceptionFilter);
2069
+ };
2070
+ }
2071
+
2072
+ function setEnvInfo(envTsDefinition, envValueInfo) {
2073
+ if (envTsDefinition && envValueInfo) {
2074
+ common.commonContainer.setEnvTsDefinition(envTsDefinition);
2075
+ Object.keys(envValueInfo).forEach((key) => {
2076
+ if (envValueInfo[key])
2077
+ process.env[key] = envValueInfo[key];
2078
+ });
2079
+ }
2080
+ }
2081
+
2082
+ function authorize(permission) {
2083
+ return function(target, propertyKey, descriptor) {
2084
+ base({
2085
+ target,
2086
+ propertyKey,
2087
+ descriptor
2088
+ }, DecoratorType.authorize, permission);
2089
+ };
2090
+ }
2091
+
2092
+ function scoped(token) {
2093
+ return injectable({ lifetime: Lifetime.Scoped, token });
2094
+ }
2095
+
2096
+ function transient(token) {
2097
+ return injectable({ lifetime: Lifetime.Transient, token });
2098
+ }
2099
+
2100
+ function singleton(token) {
2101
+ return injectable({ lifetime: Lifetime.Singleton, token });
2102
+ }
2103
+
2104
+ function getTokenTypeName(token) {
2105
+ if (typeof token !== "symbol") {
2106
+ return void 0;
2107
+ }
2108
+ const key = Symbol.keyFor(token);
2109
+ if (!key) {
2110
+ return void 0;
2111
+ }
2112
+ const separatorIndex = key.lastIndexOf("#");
2113
+ if (separatorIndex < 0 || separatorIndex === key.length - 1) {
2114
+ return void 0;
2115
+ }
2116
+ return key.slice(separatorIndex + 1);
2117
+ }
2118
+
2119
+ function registerLifetime(targetConstructor, sourceFile, lifetime) {
2120
+ if (lifetime === Lifetime.Singleton) {
2121
+ nattyServiceResolver.addSingleton(targetConstructor, void 0, void 0, sourceFile);
2122
+ return;
2123
+ }
2124
+ if (lifetime === Lifetime.Scoped) {
2125
+ nattyServiceResolver.addScoped(targetConstructor, void 0, void 0, sourceFile);
2126
+ return;
2127
+ }
2128
+ if (lifetime === Lifetime.Transient) {
2129
+ nattyServiceResolver.addTransient(targetConstructor, void 0, void 0, sourceFile);
2130
+ }
2131
+ }
2132
+ function registerAliasTypeName(token, sourceFile) {
2133
+ const typeName = getTokenTypeName(token);
2134
+ if (typeName) {
2135
+ common.commonContainer.setMetadata(typeName, token, "services");
2136
+ if (sourceFile)
2137
+ nattyServiceResolver.trackMetadataKey(sourceFile, typeName);
2138
+ }
2139
+ }
2140
+ function registerDiToken(targetConstructor, token, options = {}) {
2141
+ const sourceFile = getRegistrationSourceFile();
2142
+ common.commonContainer.setMetadata(targetConstructor.name, targetConstructor, "services");
2143
+ if (sourceFile)
2144
+ nattyServiceResolver.trackMetadataKey(sourceFile, targetConstructor.name);
2145
+ registerAliasTypeName(token, sourceFile);
2146
+ registerLifetime(targetConstructor, sourceFile, options.lifetime);
2147
+ nattyServiceResolver.addTransient(
2148
+ token,
2149
+ void 0,
2150
+ (serviceProvider) => serviceProvider.get(targetConstructor),
2151
+ sourceFile
2152
+ );
2153
+ }
2154
+
2155
+ function di(token, options = {}) {
2156
+ return (targetConstructor) => {
2157
+ registerDiToken(targetConstructor, token, options);
2158
+ };
2159
+ }
2160
+
2161
+ function createServiceScope() {
2162
+ return nattyServiceResolver.createScope();
2163
+ }
2164
+
2165
+ function clearHotReloadRegistrations(files) {
2166
+ for (const filePath of files || []) {
2167
+ const result = nattyServiceResolver.clearRegistrationsFromSource(filePath);
2168
+ decoratorStateContainer.clearFromSource(filePath);
2169
+ for (const metadataKey of result.metadataKeys) {
2170
+ common.commonContainer.deleteMetadataValue(metadataKey, "services");
2171
+ }
2172
+ }
2173
+ }
2174
+
2175
+ function clearHotReloadControllerMetadata(controllerNames) {
2176
+ decoratorStateContainer.clearControllers(controllerNames || []);
2177
+ }
2178
+
2179
+ function replaceRoutes(manifest) {
2180
+ nattyContainer.replaceRoutes(manifest);
2181
+ }
2182
+
1234
2183
  exports.$request = $request;
1235
2184
  exports.AbstractModelState = AbstractModelState;
2185
+ exports.AcceptedException = AcceptedException;
2186
+ exports.AcceptedResult = AcceptedResult;
1236
2187
  exports.BadRequestResult = BadRequestResult;
1237
2188
  exports.BaseController = BaseController;
2189
+ exports.BaseResult = BaseResult;
2190
+ exports.ConflictResult = ConflictResult;
2191
+ exports.CreateProblemDetail = CreateProblemDetail;
1238
2192
  exports.CreatedResult = CreatedResult;
1239
2193
  exports.Delete = Delete;
2194
+ exports.FileResult = FileResult;
1240
2195
  exports.ForbiddenAccessException = ForbiddenAccessException;
1241
2196
  exports.ForbiddenAccessInfoResult = ForbiddenAccessInfoResult;
1242
2197
  exports.HttpBadRequestException = HttpBadRequestException;
2198
+ exports.HttpConflictException = HttpConflictException;
1243
2199
  exports.HttpContext = HttpContext;
1244
2200
  exports.HttpException = HttpException;
1245
2201
  exports.HttpHandler = HttpHandler;
1246
2202
  exports.HttpNotFoundException = HttpNotFoundException;
1247
2203
  exports.HttpResponse = HttpResponse;
2204
+ exports.HttpStatusCode = HttpStatusCode;
2205
+ exports.HttpUnprocessableEntityException = HttpUnprocessableEntityException;
2206
+ exports.Lifetime = Lifetime;
1248
2207
  exports.ModelBindingContext = ModelBindingContext;
1249
2208
  exports.NoContentResult = NoContentResult;
1250
2209
  exports.NotFoundResult = NotFoundResult;
1251
2210
  exports.OkResult = OkResult;
2211
+ exports.ProblemDetailsException = ProblemDetailsException;
2212
+ exports.ProblemResult = ProblemResult;
2213
+ exports.RedirectException = RedirectException;
2214
+ exports.RedirectPermanentException = RedirectPermanentException;
2215
+ exports.RedirectResult = RedirectResult;
2216
+ exports.Results = Results;
1252
2217
  exports.RunOn = RunOn;
2218
+ exports.TooManyRequestsException = TooManyRequestsException;
2219
+ exports.TooManyRequestsResult = TooManyRequestsResult;
2220
+ exports.UnAuthorizedResult = UnAuthorizedResult;
1253
2221
  exports.UnauthorizedAccessException = UnauthorizedAccessException;
2222
+ exports.UnprocessableEntityResult = UnprocessableEntityResult;
2223
+ exports.ValidationProblemDetailsException = ValidationProblemDetailsException;
2224
+ exports.accepted = accepted;
1254
2225
  exports.anonymous = anonymous;
1255
2226
  exports.authenticationOnly = authenticationOnly;
2227
+ exports.authorize = authorize;
1256
2228
  exports.badRequest = badRequest;
2229
+ exports.clearHotReloadControllerMetadata = clearHotReloadControllerMetadata;
2230
+ exports.clearHotReloadRegistrations = clearHotReloadRegistrations;
2231
+ exports.conflict = conflict;
2232
+ exports.createServiceScope = createServiceScope;
1257
2233
  exports.created = created;
2234
+ exports.createdAt = createdAt;
2235
+ exports.createdWith = createdWith;
1258
2236
  exports.defineNattyConfig = defineNattyConfig;
2237
+ exports.di = di;
1259
2238
  exports.entityContainer = entityContainer;
2239
+ exports.file = file;
1260
2240
  exports.filter = filter;
2241
+ exports.forbiddenAccess = forbiddenAccess;
1261
2242
  exports.forbiddenAccessInfo = forbiddenAccessInfo;
1262
2243
  exports.get = get;
1263
2244
  exports.init = init;
1264
2245
  exports.injectable = injectable;
1265
2246
  exports.noContent = noContent;
1266
2247
  exports.notFound = notFound;
2248
+ exports.notFoundWith = notFoundWith;
1267
2249
  exports.ok = ok;
2250
+ exports.onException = onException;
1268
2251
  exports.post = post;
2252
+ exports.problem = problem;
1269
2253
  exports.put = put;
2254
+ exports.redirect = redirect;
2255
+ exports.redirectPermanent = redirectPermanent;
1270
2256
  exports.registerDecorator = registerDecorator;
2257
+ exports.replaceRoutes = replaceRoutes;
1271
2258
  exports.route = route;
2259
+ exports.scoped = scoped;
2260
+ exports.setEnvInfo = setEnvInfo;
2261
+ exports.singleton = singleton;
2262
+ exports.tooManyRequests = tooManyRequests;
2263
+ exports.transient = transient;
2264
+ exports.unAuthorized = unAuthorized;
2265
+ exports.unprocessableEntity = unprocessableEntity;
1272
2266
  exports.useFilter = useFilter;
2267
+ exports.validationProblem = validationProblem;