@nattyjs/core 0.0.1-beta.4 → 0.0.1-beta.40

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
@@ -27,6 +27,12 @@ function route(path) {
27
27
  const CONTROLLER = "controller";
28
28
  const INVALID_VALUE = "INVALID_VALUE";
29
29
  const BLANK = "";
30
+ const DENY_BY_DEFAULT = {
31
+ type: "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html#deny-by-default",
32
+ title: "Deny-by-default",
33
+ 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`,
34
+ solution: `Please implement proper authentication and authorization checks. If this API needs to be accessed anonymously, add the @anonymous() decorator above the HTTP action.`
35
+ };
30
36
 
31
37
  function get(path) {
32
38
  return function(target, propertyKey, descriptor) {
@@ -60,10 +66,13 @@ const nattyContainer = new class {
60
66
  this.container = /* @__PURE__ */ new Map();
61
67
  this.containerState = /* @__PURE__ */ new Map();
62
68
  }
63
- setup(config, routes, types) {
69
+ get types() {
70
+ return common.commonContainer.types;
71
+ }
72
+ setup(config, routes, resolver) {
64
73
  this.config = config;
65
74
  this.routes = routes;
66
- this.types = types;
75
+ this.resolver = resolver;
67
76
  }
68
77
  getTypes() {
69
78
  return StaticContainer.types;
@@ -116,7 +125,7 @@ const nattyContainer = new class {
116
125
  function init(config, appConfig) {
117
126
  common.commonContainer.setupConfig(config);
118
127
  common.commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
119
- nattyContainer.setup(config, appConfig.routes, appConfig.types);
128
+ nattyContainer.setup(config, appConfig.routes, appConfig.resolver);
120
129
  return initializeModule(config);
121
130
  }
122
131
  function initializeModule(config) {
@@ -125,22 +134,26 @@ function initializeModule(config) {
125
134
  }
126
135
  }
127
136
 
128
- function getPreResponseBody(body) {
137
+ function getPreResponseBody(body, isBuffer = false) {
129
138
  let bodyInfo;
130
139
  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;
140
+ if (isBuffer)
141
+ bodyInfo = { buffer: body };
142
+ else {
143
+ if (common.isObject(body) || Array.isArray(body))
144
+ bodyInfo = { json: body };
145
+ const typeText = typeof body;
146
+ switch (typeText) {
147
+ case "string":
148
+ bodyInfo = { string: body };
149
+ break;
150
+ case "number":
151
+ bodyInfo = { number: body };
152
+ break;
153
+ case "boolean":
154
+ bodyInfo = { boolean: body };
155
+ break;
156
+ }
144
157
  }
145
158
  }
146
159
  return bodyInfo;
@@ -154,6 +167,7 @@ class HttpResponse {
154
167
  }
155
168
  setValues(responseInit) {
156
169
  if (responseInit) {
170
+ this._isBuffer = responseInit.isBuffer;
157
171
  if (responseInit.headers)
158
172
  for (const [key, value] of Object.entries(responseInit.headers))
159
173
  this.headers.append(key, value);
@@ -185,7 +199,7 @@ class HttpResponse {
185
199
  return this._body;
186
200
  }
187
201
  set body(value) {
188
- this._body = getPreResponseBody(value);
202
+ this._body = getPreResponseBody(value, this._isBuffer);
189
203
  }
190
204
  write(responseInit) {
191
205
  this.setValues(responseInit);
@@ -207,6 +221,26 @@ var RequestPipeline = /* @__PURE__ */ ((RequestPipeline2) => {
207
221
  return RequestPipeline2;
208
222
  })(RequestPipeline || {});
209
223
 
224
+ function lessThan(value) {
225
+ return value ? value.replace(/</g, "&lt;") : value;
226
+ }
227
+ function greaterThan(value) {
228
+ return value ? value.replace(/>/g, "&gt;") : value;
229
+ }
230
+ function ampersand(value) {
231
+ return value ? value.replace(/&/g, "&amp;") : value;
232
+ }
233
+ function doubleDash(value) {
234
+ return value ? value.replace(/--/g, "") : value;
235
+ }
236
+ function sanitizeSpecialCodes(value) {
237
+ value = ampersand(value);
238
+ value = lessThan(value);
239
+ value = greaterThan(value);
240
+ value = doubleDash(value);
241
+ return value;
242
+ }
243
+
210
244
  function isBoolean(value) {
211
245
  return typeof value === "boolean" || value === "1" || value === "true" || value === "0" || value === "false";
212
246
  }
@@ -267,7 +301,7 @@ function toInt(value, radix = 0) {
267
301
  }
268
302
  function toString(value) {
269
303
  if (isNotBlank(value))
270
- return String(value);
304
+ return sanitizeSpecialCodes(String(value));
271
305
  return value;
272
306
  }
273
307
  function whitelist(value, chars) {
@@ -348,6 +382,7 @@ class BaseResult {
348
382
  }
349
383
 
350
384
  function getResponseBodyObject(body, props) {
385
+ const sensitiveProps = common.commonContainer.nattyConfig?.secure?.sensitiveProps;
351
386
  if (body instanceof common.List)
352
387
  return getResponseBodyObject(body.values, body.props);
353
388
  if (Array.isArray(body)) {
@@ -361,7 +396,8 @@ function getResponseBodyObject(body, props) {
361
396
  const keys = Object.keys(body);
362
397
  const getterProps = props ? Object.keys(props).map((key) => props[key]) : [];
363
398
  for (const key of [...keys, ...getterProps])
364
- jObject[key] = getResponseBodyObject(body[key]);
399
+ if (!sensitiveProps || sensitiveProps.filter((t) => t == key.toLowerCase()).length == 0)
400
+ jObject[key] = getResponseBodyObject(body[key]);
365
401
  return jObject;
366
402
  }
367
403
  return body;
@@ -388,7 +424,7 @@ class BaseResponse {
388
424
  }
389
425
 
390
426
  function getTypedErrorMessage(type, value) {
391
- const message = common.commonContainer.nattyConfig.modelBinding.errorMessage.typed[type];
427
+ const message = common.commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed ? common.commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed[type] : "";
392
428
  return parseMessage(message, [value]);
393
429
  }
394
430
  function parseMessage(message, value) {
@@ -464,6 +500,32 @@ const entityContainer = new class {
464
500
  }
465
501
  }();
466
502
 
503
+ class ForbiddenAccessException extends HttpException {
504
+ constructor(data) {
505
+ super({
506
+ body: data,
507
+ status: 403
508
+ });
509
+ }
510
+ }
511
+
512
+ class UnauthorizedAccessException extends HttpException {
513
+ constructor(data) {
514
+ super({
515
+ body: data,
516
+ status: 401
517
+ });
518
+ }
519
+ }
520
+
521
+ function CreateProblemDetail(modelName, detail) {
522
+ return {
523
+ type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
524
+ title: `The specified ${modelName} model props are invalid.`,
525
+ detail
526
+ };
527
+ }
528
+
467
529
  class ParameterTypeConverter extends BaseResponse {
468
530
  constructor() {
469
531
  super(...arguments);
@@ -524,12 +586,14 @@ class ParameterTypeConverter extends BaseResponse {
524
586
  } else {
525
587
  if (this.isArrayType(property.type) && Array.isArray(value)) {
526
588
  let arrayValue = body[property.name] = [];
527
- let arrayInvalidProps = invalidProps[property.name] = [];
528
589
  for (const item of value) {
529
590
  const sanitizeValue = this.sanitizer[property.type.toLowerCase()] ? this.sanitizer[property.type.toLowerCase()](item) : item;
530
- if (sanitizeValue === INVALID_VALUE)
591
+ if (sanitizeValue === INVALID_VALUE) {
592
+ let arrayInvalidProps = invalidProps[property.name];
593
+ if (!arrayInvalidProps)
594
+ arrayInvalidProps = invalidProps[property.name] = [];
531
595
  arrayInvalidProps.push(property);
532
- else
596
+ } else
533
597
  arrayValue.push(sanitizeValue);
534
598
  }
535
599
  } else
@@ -550,14 +614,17 @@ class ParameterTypeConverter extends BaseResponse {
550
614
  for (const parameterInfo of methodInfo.parameters) {
551
615
  const value = jObject[parameterInfo.name];
552
616
  if (value !== void 0) {
553
- jObject[parameterInfo.name] = SANITIZERS[parameterInfo.type](value);
617
+ const sanitizedValue = SANITIZERS[parameterInfo.type](value);
618
+ if (sanitizedValue === null && sanitizedValue != value)
619
+ throw new HttpBadRequestException(CreateProblemDetail(parameterInfo.type, [{ [parameterInfo.name]: `The supplied data type must be "${parameterInfo.type}"` }]));
620
+ jObject[parameterInfo.name] = sanitizedValue;
554
621
  }
555
622
  }
556
623
  return jObject;
557
624
  }
558
625
  convertToInstance(entityName, data) {
559
626
  const typesInfo = this.types[entityName];
560
- const target = this.getClassTarget(typesInfo.path) || entityContainer.getTarget(entityName);
627
+ const target = this.getClassTarget(typesInfo.path, entityName) || entityContainer.getTarget(entityName);
561
628
  let instance = null;
562
629
  if (target) {
563
630
  instance = new target();
@@ -566,11 +633,10 @@ class ParameterTypeConverter extends BaseResponse {
566
633
  instance = data;
567
634
  return instance;
568
635
  }
569
- getClassTarget(resolver) {
570
- if (resolver) {
571
- const classInfo = resolver();
572
- const name = Object.keys(classInfo)[0];
573
- return classInfo[name];
636
+ getClassTarget(path, entityName) {
637
+ if (path) {
638
+ const classInfo = nattyContainer.resolver(path);
639
+ return classInfo[entityName];
574
640
  }
575
641
  return void 0;
576
642
  }
@@ -668,15 +734,6 @@ class RouteParser extends ParameterTypeConverter {
668
734
  }
669
735
  }
670
736
 
671
- class UnauthorizedAccessException extends HttpException {
672
- constructor(data) {
673
- super({
674
- body: data,
675
- status: 401
676
- });
677
- }
678
- }
679
-
680
737
  const decoratorStateContainer = new class {
681
738
  constructor() {
682
739
  this.controllerConfig = {};
@@ -722,15 +779,6 @@ var DecoratorType = /* @__PURE__ */ ((DecoratorType2) => {
722
779
  return DecoratorType2;
723
780
  })(DecoratorType || {});
724
781
 
725
- class ForbiddenAccessException extends HttpException {
726
- constructor(data) {
727
- super({
728
- body: data,
729
- status: 403
730
- });
731
- }
732
- }
733
-
734
782
  class AbstractExecutionContext {
735
783
  constructor(context, routeInfo) {
736
784
  this.context = context;
@@ -760,14 +808,6 @@ class ActionExecutingContext extends AbstractExecutionContext {
760
808
  }
761
809
  }
762
810
 
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
811
  function runValidators(entityName, value) {
772
812
  const typeInfo = nattyContainer.types[entityName];
773
813
  let errors = {};
@@ -829,6 +869,8 @@ class ModelBindingContext extends ParameterTypeConverter {
829
869
  else
830
870
  this.data = body;
831
871
  this.instance = this.convertToInstance(this.type, this.data);
872
+ if (!this.isValid)
873
+ throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
832
874
  }
833
875
  get isValid() {
834
876
  const errors = runValidators(this.type, this.instance);
@@ -845,6 +887,17 @@ class ActionExecutedContext extends AbstractExecutionContext {
845
887
  super(httpContext, routeInfo);
846
888
  this.content = content;
847
889
  }
890
+ get response() {
891
+ return this.context.response;
892
+ }
893
+ }
894
+
895
+ class AuthorizationContext extends AbstractExecutionContext {
896
+ constructor(models, context, routeInfo, config) {
897
+ super(context, routeInfo);
898
+ this.models = models;
899
+ this.config = config;
900
+ }
848
901
  }
849
902
 
850
903
  class RequestProcessor extends RouteParser {
@@ -857,9 +910,6 @@ class RequestProcessor extends RouteParser {
857
910
  case RequestPipeline.onAuthentication:
858
911
  await this.onAuthentication();
859
912
  break;
860
- case RequestPipeline.onAuthorization:
861
- await this.onAuthorization();
862
- break;
863
913
  }
864
914
  }
865
915
  resolveFilter(instance) {
@@ -880,26 +930,45 @@ class RequestProcessor extends RouteParser {
880
930
  const authentication = this.getAuthenticationClass();
881
931
  const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
882
932
  const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
933
+ if (!anonymousInfo && !authenticationFilter)
934
+ throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
883
935
  if (authenticationFilter) {
884
936
  const result = await authenticationFilter.onAuthentication(this.httpContext);
885
937
  this.httpContext.user = result;
886
938
  if (!result.isAuthenticate && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
887
939
  throw new UnauthorizedAccessException(authenticationFilter.onFailedResponse());
888
- await this.onAuthorization();
889
940
  }
890
941
  }
891
- async onAuthorization() {
942
+ async onAuthorization(methodParameters) {
892
943
  const authorization = common.commonContainer.globalConfig.authorization;
893
944
  const authorizationFilter = authorization ? this.resolveFilter(authorization) : void 0;
894
945
  const authorizeConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authorize);
895
946
  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);
947
+ if (this.httpContext.user?.isAuthenticate && authorizationFilter && (authorizeConfig.controllerConfig || authorizeConfig.methodConfig) && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
948
+ const authorizationContext = new AuthorizationContext(
949
+ methodParameters.filter((t) => t instanceof ModelBindingContext),
950
+ this.httpContext,
951
+ this.routeInfo,
952
+ authorizeConfig.methodConfig || authorizeConfig.controllerConfig
953
+ );
954
+ const result = await authorizationFilter.onAuthorization(authorizationContext);
898
955
  if (!result)
899
956
  throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
900
957
  }
901
958
  }
902
- async onActionExecuting(methodParameters) {
959
+ async onModelBinding(methodParameters) {
960
+ const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
961
+ for (const actionFilter of actionFilters) {
962
+ const filter = this.resolveFilter(actionFilter);
963
+ this.actionFilterInstances.push(filter);
964
+ await filter.onActionExecuting(actionExecutingContext);
965
+ if (actionExecutingContext.result) {
966
+ return actionExecutingContext.result;
967
+ }
968
+ }
969
+ return null;
970
+ }
971
+ getExecutingContext(methodParameters) {
903
972
  let actionFilters = common.commonContainer.globalConfig.actionFilters || [];
904
973
  const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
905
974
  actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
@@ -908,6 +977,11 @@ class RequestProcessor extends RouteParser {
908
977
  this.httpContext,
909
978
  this.routeInfo
910
979
  );
980
+ return { actionFilters, actionExecutingContext };
981
+ }
982
+ async onActionExecuting(methodParameters) {
983
+ await this.onAuthorization(methodParameters);
984
+ const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
911
985
  for (const actionFilter of actionFilters) {
912
986
  const filter = this.resolveFilter(actionFilter);
913
987
  this.actionFilterInstances.push(filter);
@@ -1205,6 +1279,16 @@ function badRequest(value, response) {
1205
1279
  return new BadRequestResult(value || common.BLANK, response);
1206
1280
  }
1207
1281
 
1282
+ class FileResult extends BaseResult {
1283
+ constructor(value, response) {
1284
+ super({ ...{ isBuffer: true, body: value }, ...{ status: HttpStatusCode.success } }, response);
1285
+ this.value = value;
1286
+ }
1287
+ }
1288
+ function fileResult(value, response) {
1289
+ return new FileResult(value || common.BLANK, response);
1290
+ }
1291
+
1208
1292
  function base(params, type, additionaConfig) {
1209
1293
  decoratorStateContainer.register(params, type, additionaConfig);
1210
1294
  }
@@ -1231,12 +1315,31 @@ function authenticationOnly() {
1231
1315
  };
1232
1316
  }
1233
1317
 
1318
+ function setEnvInfo(envTsDefinition, envValueInfo) {
1319
+ if (envTsDefinition && envValueInfo) {
1320
+ common.commonContainer.setEnvTsDefinition(envTsDefinition);
1321
+ Object.keys(envValueInfo).forEach((key) => process.env[key] = envValueInfo[key]);
1322
+ }
1323
+ }
1324
+
1325
+ function authorize(permission) {
1326
+ return function(target, propertyKey, descriptor) {
1327
+ base({
1328
+ target,
1329
+ propertyKey,
1330
+ descriptor
1331
+ }, DecoratorType.authorize, permission);
1332
+ };
1333
+ }
1334
+
1234
1335
  exports.$request = $request;
1235
1336
  exports.AbstractModelState = AbstractModelState;
1236
1337
  exports.BadRequestResult = BadRequestResult;
1237
1338
  exports.BaseController = BaseController;
1339
+ exports.CreateProblemDetail = CreateProblemDetail;
1238
1340
  exports.CreatedResult = CreatedResult;
1239
1341
  exports.Delete = Delete;
1342
+ exports.FileResult = FileResult;
1240
1343
  exports.ForbiddenAccessException = ForbiddenAccessException;
1241
1344
  exports.ForbiddenAccessInfoResult = ForbiddenAccessInfoResult;
1242
1345
  exports.HttpBadRequestException = HttpBadRequestException;
@@ -1245,6 +1348,7 @@ exports.HttpException = HttpException;
1245
1348
  exports.HttpHandler = HttpHandler;
1246
1349
  exports.HttpNotFoundException = HttpNotFoundException;
1247
1350
  exports.HttpResponse = HttpResponse;
1351
+ exports.HttpStatusCode = HttpStatusCode;
1248
1352
  exports.ModelBindingContext = ModelBindingContext;
1249
1353
  exports.NoContentResult = NoContentResult;
1250
1354
  exports.NotFoundResult = NotFoundResult;
@@ -1253,10 +1357,12 @@ exports.RunOn = RunOn;
1253
1357
  exports.UnauthorizedAccessException = UnauthorizedAccessException;
1254
1358
  exports.anonymous = anonymous;
1255
1359
  exports.authenticationOnly = authenticationOnly;
1360
+ exports.authorize = authorize;
1256
1361
  exports.badRequest = badRequest;
1257
1362
  exports.created = created;
1258
1363
  exports.defineNattyConfig = defineNattyConfig;
1259
1364
  exports.entityContainer = entityContainer;
1365
+ exports.fileResult = fileResult;
1260
1366
  exports.filter = filter;
1261
1367
  exports.forbiddenAccessInfo = forbiddenAccessInfo;
1262
1368
  exports.get = get;
@@ -1269,4 +1375,5 @@ exports.post = post;
1269
1375
  exports.put = put;
1270
1376
  exports.registerDecorator = registerDecorator;
1271
1377
  exports.route = route;
1378
+ exports.setEnvInfo = setEnvInfo;
1272
1379
  exports.useFilter = useFilter;
package/dist/index.d.ts CHANGED
@@ -53,12 +53,70 @@ declare function route(path: string): (target: any, propertyKey?: string, parame
53
53
 
54
54
  declare function get(path: string): (target: any, propertyKey?: string, descriptor?: any) => void;
55
55
 
56
- declare function post(path: string): (target: any, propertyKey?: string, descriptor?: any) => void;
56
+ declare function post(path?: string): (target: any, propertyKey?: string, descriptor?: any) => void;
57
57
 
58
- declare function put(path: string): (target: any, propertyKey?: string, descriptor?: any) => void;
58
+ declare function put(path?: string): (target: any, propertyKey?: string, descriptor?: any) => void;
59
59
 
60
60
  declare function Delete(): (target: any, propertyKey?: string, descriptor?: any) => void;
61
61
 
62
+ interface RouteConfig {
63
+ controller: Function;
64
+ parameters: Array<{
65
+ name: string;
66
+ type: string;
67
+ }>;
68
+ get: {
69
+ [key: string]: {
70
+ name: string;
71
+ parameters: Array<{
72
+ name: string;
73
+ type: string;
74
+ }>;
75
+ returnType: string;
76
+ };
77
+ };
78
+ post: {
79
+ [key: string]: {
80
+ name: string;
81
+ parameters: Array<{
82
+ name: string;
83
+ type: string;
84
+ }>;
85
+ returnType: string;
86
+ };
87
+ };
88
+ put: {
89
+ [key: string]: {
90
+ name: string;
91
+ parameters: Array<{
92
+ name: string;
93
+ type: string;
94
+ }>;
95
+ returnType: string;
96
+ };
97
+ };
98
+ delete: {
99
+ [key: string]: {
100
+ name: string;
101
+ parameters: Array<{
102
+ name: string;
103
+ type: string;
104
+ }>;
105
+ returnType: string;
106
+ };
107
+ };
108
+ }
109
+
110
+ declare function init(config: NattyConfig, appConfig: {
111
+ routes: {
112
+ [key: string]: RouteConfig;
113
+ };
114
+ envTsDefinition: {
115
+ [key: string]: string;
116
+ };
117
+ resolver: (path: string) => {};
118
+ }): any;
119
+
62
120
  interface DecoratorInfo {
63
121
  httpMethod: string;
64
122
  route: string;
@@ -81,6 +139,7 @@ type HttpRequestBodyInfo = {
81
139
  number?: number | number[];
82
140
  boolean?: boolean | boolean[];
83
141
  FormData?: FormData;
142
+ buffer?: any;
84
143
  ArrayBuffer?: ArrayBuffer;
85
144
  Blob?: Blob;
86
145
  json?: {
@@ -120,6 +179,7 @@ interface HttpResponseInit {
120
179
  headers?: HeadersInit;
121
180
  cookies?: Cookie[];
122
181
  enableContentNegotiation?: boolean;
182
+ isBuffer?: boolean;
123
183
  }
124
184
 
125
185
  interface ProblemDetail {
@@ -190,64 +250,6 @@ interface IHttpResult {
190
250
  getResponse(): HttpResponseInit;
191
251
  }
192
252
 
193
- interface RouteConfig {
194
- controller: Function;
195
- parameters: Array<{
196
- name: string;
197
- type: string;
198
- }>;
199
- get: {
200
- [key: string]: {
201
- name: string;
202
- parameters: Array<{
203
- name: string;
204
- type: string;
205
- }>;
206
- returnType: string;
207
- };
208
- };
209
- post: {
210
- [key: string]: {
211
- name: string;
212
- parameters: Array<{
213
- name: string;
214
- type: string;
215
- }>;
216
- returnType: string;
217
- };
218
- };
219
- put: {
220
- [key: string]: {
221
- name: string;
222
- parameters: Array<{
223
- name: string;
224
- type: string;
225
- }>;
226
- returnType: string;
227
- };
228
- };
229
- delete: {
230
- [key: string]: {
231
- name: string;
232
- parameters: Array<{
233
- name: string;
234
- type: string;
235
- }>;
236
- returnType: string;
237
- };
238
- };
239
- }
240
-
241
- declare function init(config: NattyConfig, appConfig: {
242
- routes: {
243
- [key: string]: RouteConfig;
244
- };
245
- envTsDefinition: {
246
- [key: string]: string;
247
- };
248
- types?: TypesInfo;
249
- }): any;
250
-
251
253
  declare class HttpRequest {
252
254
  private httpRequest;
253
255
  constructor(http: HttpRequestInit);
@@ -264,6 +266,7 @@ declare class HttpResponse {
264
266
  private _headers;
265
267
  private _body;
266
268
  private _status;
269
+ private _isBuffer;
267
270
  constructor(response?: HttpResponseInit);
268
271
  private setValues;
269
272
  addCookie(cookie: Cookie): void;
@@ -341,9 +344,9 @@ declare abstract class ParameterTypeConverter extends BaseResponse {
341
344
  };
342
345
  get types(): TypesInfo;
343
346
  getObjectTypeInfo(typeName: string): {
344
- path?: any;
345
- props?: TypeInfo[];
346
- values?: any[];
347
+ path?: string | any | Function;
348
+ props?: Array<TypeInfo>;
349
+ values?: Array<any>;
347
350
  };
348
351
  isArrayType(typeName: string): boolean;
349
352
  getTypeName(typeName: string): string;
@@ -435,6 +438,12 @@ declare class BadRequestResult extends BaseResult implements IHttpResult {
435
438
  }
436
439
  declare function badRequest(value?: ExceptionTypeInfo, response?: Pick<HttpResponseInit, "headers" | "cookies">): BadRequestResult;
437
440
 
441
+ declare class FileResult extends BaseResult {
442
+ value: any;
443
+ constructor(value: any, response?: Pick<HttpResponseInit, "headers" | "cookies">);
444
+ }
445
+ declare function fileResult(value?: any, response?: Pick<HttpResponseInit, "headers" | "cookies">): FileResult;
446
+
438
447
  declare class HttpException {
439
448
  private httpResponse;
440
449
  constructor(response: HttpResponseInit);
@@ -463,4 +472,27 @@ declare function anonymous(): (target: any, propertyKey?: string, descriptor?: a
463
472
 
464
473
  declare function authenticationOnly(): (target: any, propertyKey?: string, descriptor?: any) => void;
465
474
 
466
- export { $request, AbstractModelState, BadRequestResult, BaseController, BuildOptions, ClassTypeInfo, CreatedResult, Delete, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpModule, HttpNotFoundException, HttpResponse, MethodInfo$1 as MethodInfo, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, ParameterInfo, RunOn, TypeInfo$1 as TypeInfo, UnauthorizedAccessException, anonymous, authenticationOnly, badRequest, created, defineNattyConfig, entityContainer, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, useFilter };
475
+ declare function setEnvInfo(envTsDefinition: {
476
+ [key: string]: string;
477
+ }, envValueInfo: {
478
+ [key: string]: any;
479
+ }): void;
480
+
481
+ declare enum HttpStatusCode {
482
+ success = 200,
483
+ created = 201,
484
+ noContent = 204,
485
+ notFound = 404,
486
+ unAuthorized = 401,
487
+ forbiddenAccess = 403,
488
+ badRequest = 400,
489
+ serverError = 500
490
+ }
491
+
492
+ declare function authorize(permission: {
493
+ [key: string]: any;
494
+ }): (target: any, propertyKey?: string, descriptor?: any) => void;
495
+
496
+ declare function CreateProblemDetail(modelName: string, detail: any): ProblemDetail;
497
+
498
+ export { $request, AbstractModelState, BadRequestResult, BaseController, BuildOptions, ClassTypeInfo, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpModule, HttpNotFoundException, HttpResponse, HttpStatusCode, MethodInfo$1 as MethodInfo, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, ParameterInfo, RunOn, TypeInfo$1 as TypeInfo, UnauthorizedAccessException, anonymous, authenticationOnly, authorize, badRequest, created, defineNattyConfig, entityContainer, fileResult, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, setEnvInfo, useFilter };
package/dist/index.mjs CHANGED
@@ -25,6 +25,12 @@ function route(path) {
25
25
  const CONTROLLER = "controller";
26
26
  const INVALID_VALUE = "INVALID_VALUE";
27
27
  const BLANK = "";
28
+ const DENY_BY_DEFAULT = {
29
+ type: "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html#deny-by-default",
30
+ title: "Deny-by-default",
31
+ 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`,
32
+ solution: `Please implement proper authentication and authorization checks. If this API needs to be accessed anonymously, add the @anonymous() decorator above the HTTP action.`
33
+ };
28
34
 
29
35
  function get(path) {
30
36
  return function(target, propertyKey, descriptor) {
@@ -58,10 +64,13 @@ const nattyContainer = new class {
58
64
  this.container = /* @__PURE__ */ new Map();
59
65
  this.containerState = /* @__PURE__ */ new Map();
60
66
  }
61
- setup(config, routes, types) {
67
+ get types() {
68
+ return commonContainer.types;
69
+ }
70
+ setup(config, routes, resolver) {
62
71
  this.config = config;
63
72
  this.routes = routes;
64
- this.types = types;
73
+ this.resolver = resolver;
65
74
  }
66
75
  getTypes() {
67
76
  return StaticContainer.types;
@@ -114,7 +123,7 @@ const nattyContainer = new class {
114
123
  function init(config, appConfig) {
115
124
  commonContainer.setupConfig(config);
116
125
  commonContainer.setEnvTsDefinition(appConfig.envTsDefinition);
117
- nattyContainer.setup(config, appConfig.routes, appConfig.types);
126
+ nattyContainer.setup(config, appConfig.routes, appConfig.resolver);
118
127
  return initializeModule(config);
119
128
  }
120
129
  function initializeModule(config) {
@@ -123,22 +132,26 @@ function initializeModule(config) {
123
132
  }
124
133
  }
125
134
 
126
- function getPreResponseBody(body) {
135
+ function getPreResponseBody(body, isBuffer = false) {
127
136
  let bodyInfo;
128
137
  if (body) {
129
- if (isObject(body) || Array.isArray(body))
130
- bodyInfo = { json: body };
131
- const typeText = typeof body;
132
- switch (typeText) {
133
- case "string":
134
- bodyInfo = { string: body };
135
- break;
136
- case "number":
137
- bodyInfo = { number: body };
138
- break;
139
- case "boolean":
140
- bodyInfo = { boolean: body };
141
- break;
138
+ if (isBuffer)
139
+ bodyInfo = { buffer: body };
140
+ else {
141
+ if (isObject(body) || Array.isArray(body))
142
+ bodyInfo = { json: body };
143
+ const typeText = typeof body;
144
+ switch (typeText) {
145
+ case "string":
146
+ bodyInfo = { string: body };
147
+ break;
148
+ case "number":
149
+ bodyInfo = { number: body };
150
+ break;
151
+ case "boolean":
152
+ bodyInfo = { boolean: body };
153
+ break;
154
+ }
142
155
  }
143
156
  }
144
157
  return bodyInfo;
@@ -152,6 +165,7 @@ class HttpResponse {
152
165
  }
153
166
  setValues(responseInit) {
154
167
  if (responseInit) {
168
+ this._isBuffer = responseInit.isBuffer;
155
169
  if (responseInit.headers)
156
170
  for (const [key, value] of Object.entries(responseInit.headers))
157
171
  this.headers.append(key, value);
@@ -183,7 +197,7 @@ class HttpResponse {
183
197
  return this._body;
184
198
  }
185
199
  set body(value) {
186
- this._body = getPreResponseBody(value);
200
+ this._body = getPreResponseBody(value, this._isBuffer);
187
201
  }
188
202
  write(responseInit) {
189
203
  this.setValues(responseInit);
@@ -205,6 +219,26 @@ var RequestPipeline = /* @__PURE__ */ ((RequestPipeline2) => {
205
219
  return RequestPipeline2;
206
220
  })(RequestPipeline || {});
207
221
 
222
+ function lessThan(value) {
223
+ return value ? value.replace(/</g, "&lt;") : value;
224
+ }
225
+ function greaterThan(value) {
226
+ return value ? value.replace(/>/g, "&gt;") : value;
227
+ }
228
+ function ampersand(value) {
229
+ return value ? value.replace(/&/g, "&amp;") : value;
230
+ }
231
+ function doubleDash(value) {
232
+ return value ? value.replace(/--/g, "") : value;
233
+ }
234
+ function sanitizeSpecialCodes(value) {
235
+ value = ampersand(value);
236
+ value = lessThan(value);
237
+ value = greaterThan(value);
238
+ value = doubleDash(value);
239
+ return value;
240
+ }
241
+
208
242
  function isBoolean(value) {
209
243
  return typeof value === "boolean" || value === "1" || value === "true" || value === "0" || value === "false";
210
244
  }
@@ -265,7 +299,7 @@ function toInt(value, radix = 0) {
265
299
  }
266
300
  function toString(value) {
267
301
  if (isNotBlank(value))
268
- return String(value);
302
+ return sanitizeSpecialCodes(String(value));
269
303
  return value;
270
304
  }
271
305
  function whitelist(value, chars) {
@@ -346,6 +380,7 @@ class BaseResult {
346
380
  }
347
381
 
348
382
  function getResponseBodyObject(body, props) {
383
+ const sensitiveProps = commonContainer.nattyConfig?.secure?.sensitiveProps;
349
384
  if (body instanceof List)
350
385
  return getResponseBodyObject(body.values, body.props);
351
386
  if (Array.isArray(body)) {
@@ -359,7 +394,8 @@ function getResponseBodyObject(body, props) {
359
394
  const keys = Object.keys(body);
360
395
  const getterProps = props ? Object.keys(props).map((key) => props[key]) : [];
361
396
  for (const key of [...keys, ...getterProps])
362
- jObject[key] = getResponseBodyObject(body[key]);
397
+ if (!sensitiveProps || sensitiveProps.filter((t) => t == key.toLowerCase()).length == 0)
398
+ jObject[key] = getResponseBodyObject(body[key]);
363
399
  return jObject;
364
400
  }
365
401
  return body;
@@ -386,7 +422,7 @@ class BaseResponse {
386
422
  }
387
423
 
388
424
  function getTypedErrorMessage(type, value) {
389
- const message = commonContainer.nattyConfig.modelBinding.errorMessage.typed[type];
425
+ const message = commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed ? commonContainer.nattyConfig?.modelBinding?.errorMessage?.typed[type] : "";
390
426
  return parseMessage(message, [value]);
391
427
  }
392
428
  function parseMessage(message, value) {
@@ -462,6 +498,32 @@ const entityContainer = new class {
462
498
  }
463
499
  }();
464
500
 
501
+ class ForbiddenAccessException extends HttpException {
502
+ constructor(data) {
503
+ super({
504
+ body: data,
505
+ status: 403
506
+ });
507
+ }
508
+ }
509
+
510
+ class UnauthorizedAccessException extends HttpException {
511
+ constructor(data) {
512
+ super({
513
+ body: data,
514
+ status: 401
515
+ });
516
+ }
517
+ }
518
+
519
+ function CreateProblemDetail(modelName, detail) {
520
+ return {
521
+ type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
522
+ title: `The specified ${modelName} model props are invalid.`,
523
+ detail
524
+ };
525
+ }
526
+
465
527
  class ParameterTypeConverter extends BaseResponse {
466
528
  constructor() {
467
529
  super(...arguments);
@@ -522,12 +584,14 @@ class ParameterTypeConverter extends BaseResponse {
522
584
  } else {
523
585
  if (this.isArrayType(property.type) && Array.isArray(value)) {
524
586
  let arrayValue = body[property.name] = [];
525
- let arrayInvalidProps = invalidProps[property.name] = [];
526
587
  for (const item of value) {
527
588
  const sanitizeValue = this.sanitizer[property.type.toLowerCase()] ? this.sanitizer[property.type.toLowerCase()](item) : item;
528
- if (sanitizeValue === INVALID_VALUE)
589
+ if (sanitizeValue === INVALID_VALUE) {
590
+ let arrayInvalidProps = invalidProps[property.name];
591
+ if (!arrayInvalidProps)
592
+ arrayInvalidProps = invalidProps[property.name] = [];
529
593
  arrayInvalidProps.push(property);
530
- else
594
+ } else
531
595
  arrayValue.push(sanitizeValue);
532
596
  }
533
597
  } else
@@ -548,14 +612,17 @@ class ParameterTypeConverter extends BaseResponse {
548
612
  for (const parameterInfo of methodInfo.parameters) {
549
613
  const value = jObject[parameterInfo.name];
550
614
  if (value !== void 0) {
551
- jObject[parameterInfo.name] = SANITIZERS[parameterInfo.type](value);
615
+ const sanitizedValue = SANITIZERS[parameterInfo.type](value);
616
+ if (sanitizedValue === null && sanitizedValue != value)
617
+ throw new HttpBadRequestException(CreateProblemDetail(parameterInfo.type, [{ [parameterInfo.name]: `The supplied data type must be "${parameterInfo.type}"` }]));
618
+ jObject[parameterInfo.name] = sanitizedValue;
552
619
  }
553
620
  }
554
621
  return jObject;
555
622
  }
556
623
  convertToInstance(entityName, data) {
557
624
  const typesInfo = this.types[entityName];
558
- const target = this.getClassTarget(typesInfo.path) || entityContainer.getTarget(entityName);
625
+ const target = this.getClassTarget(typesInfo.path, entityName) || entityContainer.getTarget(entityName);
559
626
  let instance = null;
560
627
  if (target) {
561
628
  instance = new target();
@@ -564,11 +631,10 @@ class ParameterTypeConverter extends BaseResponse {
564
631
  instance = data;
565
632
  return instance;
566
633
  }
567
- getClassTarget(resolver) {
568
- if (resolver) {
569
- const classInfo = resolver();
570
- const name = Object.keys(classInfo)[0];
571
- return classInfo[name];
634
+ getClassTarget(path, entityName) {
635
+ if (path) {
636
+ const classInfo = nattyContainer.resolver(path);
637
+ return classInfo[entityName];
572
638
  }
573
639
  return void 0;
574
640
  }
@@ -666,15 +732,6 @@ class RouteParser extends ParameterTypeConverter {
666
732
  }
667
733
  }
668
734
 
669
- class UnauthorizedAccessException extends HttpException {
670
- constructor(data) {
671
- super({
672
- body: data,
673
- status: 401
674
- });
675
- }
676
- }
677
-
678
735
  const decoratorStateContainer = new class {
679
736
  constructor() {
680
737
  this.controllerConfig = {};
@@ -720,15 +777,6 @@ var DecoratorType = /* @__PURE__ */ ((DecoratorType2) => {
720
777
  return DecoratorType2;
721
778
  })(DecoratorType || {});
722
779
 
723
- class ForbiddenAccessException extends HttpException {
724
- constructor(data) {
725
- super({
726
- body: data,
727
- status: 403
728
- });
729
- }
730
- }
731
-
732
780
  class AbstractExecutionContext {
733
781
  constructor(context, routeInfo) {
734
782
  this.context = context;
@@ -758,14 +806,6 @@ class ActionExecutingContext extends AbstractExecutionContext {
758
806
  }
759
807
  }
760
808
 
761
- function CreateProblemDetail(modelName, detail) {
762
- return {
763
- type: "https://tools.ietf.org/html/rfc7231#section-6.5.1",
764
- title: `The specified ${modelName} model props are invalid.`,
765
- detail
766
- };
767
- }
768
-
769
809
  function runValidators(entityName, value) {
770
810
  const typeInfo = nattyContainer.types[entityName];
771
811
  let errors = {};
@@ -827,6 +867,8 @@ class ModelBindingContext extends ParameterTypeConverter {
827
867
  else
828
868
  this.data = body;
829
869
  this.instance = this.convertToInstance(this.type, this.data);
870
+ if (!this.isValid)
871
+ throw new HttpBadRequestException(CreateProblemDetail(this.type, this.errors));
830
872
  }
831
873
  get isValid() {
832
874
  const errors = runValidators(this.type, this.instance);
@@ -843,6 +885,17 @@ class ActionExecutedContext extends AbstractExecutionContext {
843
885
  super(httpContext, routeInfo);
844
886
  this.content = content;
845
887
  }
888
+ get response() {
889
+ return this.context.response;
890
+ }
891
+ }
892
+
893
+ class AuthorizationContext extends AbstractExecutionContext {
894
+ constructor(models, context, routeInfo, config) {
895
+ super(context, routeInfo);
896
+ this.models = models;
897
+ this.config = config;
898
+ }
846
899
  }
847
900
 
848
901
  class RequestProcessor extends RouteParser {
@@ -855,9 +908,6 @@ class RequestProcessor extends RouteParser {
855
908
  case RequestPipeline.onAuthentication:
856
909
  await this.onAuthentication();
857
910
  break;
858
- case RequestPipeline.onAuthorization:
859
- await this.onAuthorization();
860
- break;
861
911
  }
862
912
  }
863
913
  resolveFilter(instance) {
@@ -878,26 +928,45 @@ class RequestProcessor extends RouteParser {
878
928
  const authentication = this.getAuthenticationClass();
879
929
  const authenticationFilter = authentication ? this.resolveFilter(authentication) : void 0;
880
930
  const anonymousInfo = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.anonymous);
931
+ if (!anonymousInfo && !authenticationFilter)
932
+ throw new UnauthorizedAccessException(DENY_BY_DEFAULT);
881
933
  if (authenticationFilter) {
882
934
  const result = await authenticationFilter.onAuthentication(this.httpContext);
883
935
  this.httpContext.user = result;
884
936
  if (!result.isAuthenticate && !anonymousInfo.controllerConfig && !anonymousInfo.methodConfig)
885
937
  throw new UnauthorizedAccessException(authenticationFilter.onFailedResponse());
886
- await this.onAuthorization();
887
938
  }
888
939
  }
889
- async onAuthorization() {
940
+ async onAuthorization(methodParameters) {
890
941
  const authorization = commonContainer.globalConfig.authorization;
891
942
  const authorizationFilter = authorization ? this.resolveFilter(authorization) : void 0;
892
943
  const authorizeConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authorize);
893
944
  const authenticationOnly = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.authenticationOnly);
894
- if (this.httpContext.user?.isAuthenticate && authorizationFilter && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
895
- const result = await authorizationFilter.onAuthorization(this.httpContext, authorizeConfig.methodConfig || authorizeConfig.controllerConfig);
945
+ if (this.httpContext.user?.isAuthenticate && authorizationFilter && (authorizeConfig.controllerConfig || authorizeConfig.methodConfig) && (!authenticationOnly.controllerConfig && !authenticationOnly.methodConfig)) {
946
+ const authorizationContext = new AuthorizationContext(
947
+ methodParameters.filter((t) => t instanceof ModelBindingContext),
948
+ this.httpContext,
949
+ this.routeInfo,
950
+ authorizeConfig.methodConfig || authorizeConfig.controllerConfig
951
+ );
952
+ const result = await authorizationFilter.onAuthorization(authorizationContext);
896
953
  if (!result)
897
954
  throw new ForbiddenAccessException(authorizationFilter.onFailedAuthorization());
898
955
  }
899
956
  }
900
- async onActionExecuting(methodParameters) {
957
+ async onModelBinding(methodParameters) {
958
+ const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
959
+ for (const actionFilter of actionFilters) {
960
+ const filter = this.resolveFilter(actionFilter);
961
+ this.actionFilterInstances.push(filter);
962
+ await filter.onActionExecuting(actionExecutingContext);
963
+ if (actionExecutingContext.result) {
964
+ return actionExecutingContext.result;
965
+ }
966
+ }
967
+ return null;
968
+ }
969
+ getExecutingContext(methodParameters) {
901
970
  let actionFilters = commonContainer.globalConfig.actionFilters || [];
902
971
  const actionFiltersConfig = decoratorStateContainer.getInfo(this.routeInfo.controller.name, this.routeInfo.methodInfo.name, DecoratorType.useFilter);
903
972
  actionFilters = [...actionFilters, ...actionFiltersConfig.controllerConfig?.actionFilters || [], ...actionFiltersConfig.methodConfig?.actionFilters || []];
@@ -906,6 +975,11 @@ class RequestProcessor extends RouteParser {
906
975
  this.httpContext,
907
976
  this.routeInfo
908
977
  );
978
+ return { actionFilters, actionExecutingContext };
979
+ }
980
+ async onActionExecuting(methodParameters) {
981
+ await this.onAuthorization(methodParameters);
982
+ const { actionExecutingContext, actionFilters } = this.getExecutingContext(methodParameters);
909
983
  for (const actionFilter of actionFilters) {
910
984
  const filter = this.resolveFilter(actionFilter);
911
985
  this.actionFilterInstances.push(filter);
@@ -1203,6 +1277,16 @@ function badRequest(value, response) {
1203
1277
  return new BadRequestResult(value || BLANK$1, response);
1204
1278
  }
1205
1279
 
1280
+ class FileResult extends BaseResult {
1281
+ constructor(value, response) {
1282
+ super({ ...{ isBuffer: true, body: value }, ...{ status: HttpStatusCode.success } }, response);
1283
+ this.value = value;
1284
+ }
1285
+ }
1286
+ function fileResult(value, response) {
1287
+ return new FileResult(value || BLANK$1, response);
1288
+ }
1289
+
1206
1290
  function base(params, type, additionaConfig) {
1207
1291
  decoratorStateContainer.register(params, type, additionaConfig);
1208
1292
  }
@@ -1229,4 +1313,21 @@ function authenticationOnly() {
1229
1313
  };
1230
1314
  }
1231
1315
 
1232
- export { $request, AbstractModelState, BadRequestResult, BaseController, CreatedResult, Delete, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpNotFoundException, HttpResponse, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, RunOn, UnauthorizedAccessException, anonymous, authenticationOnly, badRequest, created, defineNattyConfig, entityContainer, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, useFilter };
1316
+ function setEnvInfo(envTsDefinition, envValueInfo) {
1317
+ if (envTsDefinition && envValueInfo) {
1318
+ commonContainer.setEnvTsDefinition(envTsDefinition);
1319
+ Object.keys(envValueInfo).forEach((key) => process.env[key] = envValueInfo[key]);
1320
+ }
1321
+ }
1322
+
1323
+ function authorize(permission) {
1324
+ return function(target, propertyKey, descriptor) {
1325
+ base({
1326
+ target,
1327
+ propertyKey,
1328
+ descriptor
1329
+ }, DecoratorType.authorize, permission);
1330
+ };
1331
+ }
1332
+
1333
+ export { $request, AbstractModelState, BadRequestResult, BaseController, CreateProblemDetail, CreatedResult, Delete, FileResult, ForbiddenAccessException, ForbiddenAccessInfoResult, HttpBadRequestException, HttpContext, HttpException, HttpHandler, HttpNotFoundException, HttpResponse, HttpStatusCode, ModelBindingContext, NoContentResult, NotFoundResult, OkResult, RunOn, UnauthorizedAccessException, anonymous, authenticationOnly, authorize, badRequest, created, defineNattyConfig, entityContainer, fileResult, filter, forbiddenAccessInfo, get, init, injectable, noContent, notFound, ok, post, put, registerDecorator, route, setEnvInfo, useFilter };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nattyjs/core",
3
- "version": "0.0.1-beta.4",
3
+ "version": "0.0.1-beta.40",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "author": "ajayojha",
@@ -15,9 +15,10 @@
15
15
  "build": "unbuild"
16
16
  },
17
17
  "dependencies": {
18
+ "reflect-metadata": "0.2.2",
18
19
  "tsyringe": "^4.7.0",
19
20
  "path-to-regexp": "6.2.1",
20
- "@nattyjs/common": "0.0.1-beta.4"
21
+ "@nattyjs/common": "0.0.1-beta.40"
21
22
  },
22
23
  "devDependencies": {
23
24
  "unbuild": "1.2.1"