@xeno-js/core 0.1.4 → 0.1.6

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.js CHANGED
@@ -1508,15 +1508,15 @@ var init_logger_utils = __esm({
1508
1508
  */
1509
1509
  async addLogger(container, opts) {
1510
1510
  const loggerDependencies = [];
1511
- const { Guards: Guards46, LOG_LEVEL: LOG_LEVEL7, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
1512
- if (!Guards46.isDefined(opts) || opts.console) {
1511
+ const { Guards: Guards47, LOG_LEVEL: LOG_LEVEL7, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
1512
+ if (!Guards47.isDefined(opts) || opts.console) {
1513
1513
  const { ConsoleLogger: ConsoleLogger2 } = await Promise.resolve().then(() => (init_console_logger(), console_logger_exports));
1514
1514
  container.addSingleton(TOKENS4.CONSOLE_LOGGER, () => new ConsoleLogger2(opts?.level));
1515
1515
  loggerDependencies.push(TOKENS4.CONSOLE_LOGGER);
1516
1516
  }
1517
1517
  const customLoggerFactories = [];
1518
- if (Guards46.isDefined(opts)) {
1519
- if (Guards46.isDefined(opts.sentry.config)) {
1518
+ if (Guards47.isDefined(opts)) {
1519
+ if (Guards47.isDefined(opts.sentry.config)) {
1520
1520
  const { SentryLoggerFactory: SentryLoggerFactory2 } = await Promise.resolve().then(() => (init_sentry_logger_factory(), sentry_logger_factory_exports));
1521
1521
  container.addSingleton(TOKENS4.SENTRY_LOGGER, () => {
1522
1522
  const factory = new SentryLoggerFactory2();
@@ -1524,7 +1524,7 @@ var init_logger_utils = __esm({
1524
1524
  });
1525
1525
  loggerDependencies.push(TOKENS4.SENTRY_LOGGER);
1526
1526
  }
1527
- if (Guards46.isDefined(opts.pino.config)) {
1527
+ if (Guards47.isDefined(opts.pino.config)) {
1528
1528
  const { PinoLoggerFactory: PinoLoggerFactory2 } = await Promise.resolve().then(() => (init_pino_logger_factory(), pino_logger_factory_exports));
1529
1529
  container.addSingleton(TOKENS4.PINO_LOGGER, () => {
1530
1530
  const factory = new PinoLoggerFactory2();
@@ -1532,10 +1532,10 @@ var init_logger_utils = __esm({
1532
1532
  });
1533
1533
  loggerDependencies.push(TOKENS4.PINO_LOGGER);
1534
1534
  }
1535
- if (!Guards46.isNullOrEmpty(opts.customLoggers)) {
1535
+ if (!Guards47.isNullOrEmpty(opts.customLoggers)) {
1536
1536
  const customLoggers = opts.customLoggers;
1537
1537
  customLoggers.forEach((f) => {
1538
- if (Guards46.isDefined(f)) {
1538
+ if (Guards47.isDefined(f)) {
1539
1539
  customLoggerFactories.push(f);
1540
1540
  }
1541
1541
  });
@@ -1708,8 +1708,8 @@ var init_cache_utils = __esm({
1708
1708
  * @link https://github.com/xeno-js/xeno-js
1709
1709
  */
1710
1710
  async addCache(container, opts) {
1711
- const { Guards: Guards46, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
1712
- if (!opts.inMemory && !Guards46.isDefined(opts.redis)) {
1711
+ const { Guards: Guards47, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
1712
+ if (!opts.inMemory && !Guards47.isDefined(opts.redis)) {
1713
1713
  throw new Error(
1714
1714
  "No cache strategies are configured. Please provide at least one cache strategy."
1715
1715
  );
@@ -1719,12 +1719,12 @@ var init_cache_utils = __esm({
1719
1719
  TOKENS4.CACHE_KEY_BUILDER,
1720
1720
  (c) => new CacheKeyBuilder(c.resolve(TOKENS4.IDENTITY_ACCESSOR))
1721
1721
  );
1722
- if (opts.inMemory || !Guards46.isDefined(opts.redis)) {
1722
+ if (opts.inMemory || !Guards47.isDefined(opts.redis)) {
1723
1723
  const { InMemoryCacheExtended: InMemoryCacheExtended2 } = await Promise.resolve().then(() => (init_inmemory_cache(), inmemory_cache_exports));
1724
1724
  container.addSingleton(TOKENS4.CACHE, () => new InMemoryCacheExtended2());
1725
1725
  return;
1726
1726
  }
1727
- if (Guards46.isDefined(opts.redis)) {
1727
+ if (Guards47.isDefined(opts.redis)) {
1728
1728
  const { RedisCacheFactory: RedisCacheFactory2 } = await Promise.resolve().then(() => (init_redis_cache_factory(), redis_cache_factory_exports));
1729
1729
  container.addSingleton(TOKENS4.CACHE, () => {
1730
1730
  const config = opts.redis;
@@ -1763,6 +1763,17 @@ var init_allow_method_service = __esm({
1763
1763
  }
1764
1764
  return false;
1765
1765
  }
1766
+ getMethods(path) {
1767
+ const cleanPath = this.normalizePath(path.split("?")[0].split("#")[0]);
1768
+ const methods = this.findMethods(cleanPath);
1769
+ return Guards22.isDefined(methods) ? methods.join(", ").toUpperCase() : "";
1770
+ }
1771
+ findMethods(cleanPath) {
1772
+ const staticMethods = this._staticRoutes.get(cleanPath);
1773
+ if (Guards22.isDefined(staticMethods)) return staticMethods;
1774
+ for (const route of this._dynamicRoutes) if (route.pattern.test(cleanPath)) return route.methods;
1775
+ return void 0;
1776
+ }
1766
1777
  isDynamicPath(path) {
1767
1778
  return path.includes(":") || path.includes("{") && path.includes("}");
1768
1779
  }
@@ -2789,8 +2800,8 @@ var init_auth_utils = __esm({
2789
2800
  const { TOKENS: TOKENS4 } = await import("@xeno-js/shared");
2790
2801
  const pipelines = [];
2791
2802
  const strategies = [];
2792
- const { Guards: Guards46 } = await import("@xeno-js/shared");
2793
- if (Guards46.isDefined(opts.policies)) {
2803
+ const { Guards: Guards47 } = await import("@xeno-js/shared");
2804
+ if (Guards47.isDefined(opts.policies)) {
2794
2805
  const { PolicyRegistry: PolicyRegistry2 } = await Promise.resolve().then(() => (init_application(), application_exports));
2795
2806
  container.addSingleton(TOKENS4.POLICY_REGISTRY, () => new PolicyRegistry2());
2796
2807
  const policyRegistry = opts.policies;
@@ -2799,16 +2810,16 @@ var init_auth_utils = __esm({
2799
2810
  for (const [intent, policy] of Object.entries(policyRegistry)) {
2800
2811
  const intentLower = intent.toLowerCase();
2801
2812
  registryInstance.addPolicy(intentLower, policy);
2802
- if (!Guards46.isNullOrEmpty(policy.roles)) {
2813
+ if (!Guards47.isNullOrEmpty(policy.roles)) {
2803
2814
  Policies.add("roles");
2804
2815
  }
2805
- if (!Guards46.isNullOrEmpty(policy.permissions)) {
2816
+ if (!Guards47.isNullOrEmpty(policy.permissions)) {
2806
2817
  Policies.add("permissions");
2807
2818
  }
2808
- if (!Guards46.isNullOrEmpty(policy.userId)) {
2819
+ if (!Guards47.isNullOrEmpty(policy.userId)) {
2809
2820
  Policies.add("userId");
2810
2821
  }
2811
- if (!Guards46.isNullOrEmpty(policy.tenantId)) {
2822
+ if (!Guards47.isNullOrEmpty(policy.tenantId)) {
2812
2823
  Policies.add("tenantId");
2813
2824
  }
2814
2825
  }
@@ -2857,10 +2868,10 @@ var init_auth_utils = __esm({
2857
2868
  strategies.push(TOKENS4.TENANT_AUTHORIZATION_PIPELINE);
2858
2869
  }
2859
2870
  }
2860
- if (!Guards46.isNullOrEmpty(opts.customAuthorizationStrategy)) {
2871
+ if (!Guards47.isNullOrEmpty(opts.customAuthorizationStrategy)) {
2861
2872
  const customStrategies = opts.customAuthorizationStrategy;
2862
2873
  customStrategies.forEach((strategyToken, index) => {
2863
- if (Guards46.isDefined(strategyToken)) {
2874
+ if (Guards47.isDefined(strategyToken)) {
2864
2875
  const token = `CUSTOM_AUTHORIZATION_STRATEGY_${index}`;
2865
2876
  container.addSingleton(token, (c) => {
2866
2877
  return strategyToken(c);
@@ -3063,7 +3074,7 @@ var init_db_module = __esm({
3063
3074
  "use strict";
3064
3075
  DbModule = class {
3065
3076
  async configure(container, opts) {
3066
- const { Guards: Guards46, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3077
+ const { Guards: Guards47, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3067
3078
  const { DbUtils: DbUtils2 } = await Promise.resolve().then(() => (init_db_utils(), db_utils_exports));
3068
3079
  const db = opts.enableSqlLite ? await DbUtils2.addSqlLite(opts) : await DbUtils2.addDbClient(opts);
3069
3080
  const { TransactionState: TransactionState2 } = await Promise.resolve().then(() => (init_transaction_state(), transaction_state_exports));
@@ -3080,7 +3091,7 @@ var init_db_module = __esm({
3080
3091
  return new Proxy(db, {
3081
3092
  get(_target, prop, receiver) {
3082
3093
  const activeState = ttx.state;
3083
- if (Guards46.isDefined(activeState)) {
3094
+ if (Guards47.isDefined(activeState)) {
3084
3095
  if (prop === "transaction") {
3085
3096
  return activeState.transaction.bind(activeState);
3086
3097
  }
@@ -3117,14 +3128,14 @@ var init_http_utils = __esm({
3117
3128
  */
3118
3129
  async addAxios(container, opts) {
3119
3130
  const { NodeAxiosFactory: NodeAxiosFactory2 } = await Promise.resolve().then(() => (init_factories(), factories_exports));
3120
- const { Guards: Guards46 } = await import("@xeno-js/shared");
3121
- if (!Guards46.isDefined(opts.token)) {
3131
+ const { Guards: Guards47 } = await import("@xeno-js/shared");
3132
+ if (!Guards47.isDefined(opts.token)) {
3122
3133
  throw new Error("HttpConfig.token is required and must be defined.");
3123
3134
  }
3124
3135
  container.addSingleton(opts.token, () => {
3125
3136
  const factory = new NodeAxiosFactory2();
3126
3137
  const instance = factory.create(opts.client);
3127
- if (!Guards46.hasMethod(instance, "get") || !Guards46.hasMethod(instance, "post") || !Guards46.hasMethod(instance, "put") || !Guards46.hasMethod(instance, "patch") || !Guards46.hasMethod(instance, "delete")) {
3138
+ if (!Guards47.hasMethod(instance, "get") || !Guards47.hasMethod(instance, "post") || !Guards47.hasMethod(instance, "put") || !Guards47.hasMethod(instance, "patch") || !Guards47.hasMethod(instance, "delete")) {
3128
3139
  throw new Error(
3129
3140
  "The created HTTP client instance does not implement the required methods of IHttpClient."
3130
3141
  );
@@ -3151,8 +3162,8 @@ var init_http_utils = __esm({
3151
3162
  });
3152
3163
  },
3153
3164
  async addAllowOrigin(container, opts) {
3154
- const { Guards: Guards46 } = await import("@xeno-js/shared");
3155
- if (Guards46.isNullOrEmpty(opts)) throw new Error("At least an allow origin must be passed");
3165
+ const { Guards: Guards47 } = await import("@xeno-js/shared");
3166
+ if (Guards47.isNullOrEmpty(opts)) throw new Error("At least an allow origin must be passed");
3156
3167
  const { TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3157
3168
  const { AllowOrigin: AllowOrigin2 } = await Promise.resolve().then(() => (init_services(), services_exports));
3158
3169
  const allowOrigin = [];
@@ -3212,13 +3223,13 @@ var init_validation_utils = __esm({
3212
3223
  * @link https://github.com/xeno-js/xeno-js
3213
3224
  */
3214
3225
  async addValidation(container, opts, logger) {
3215
- const { Guards: Guards46, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3216
- if (!Guards46.isDefined(opts.zod) && Guards46.isNullOrEmpty(opts.customValidationStrategy)) {
3226
+ const { Guards: Guards47, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3227
+ if (!Guards47.isDefined(opts.zod) && Guards47.isNullOrEmpty(opts.customValidationStrategy)) {
3217
3228
  return [];
3218
3229
  }
3219
3230
  const pipelines = [];
3220
3231
  const validationStrategies = [];
3221
- if (Guards46.isDefined(opts.zod)) {
3232
+ if (Guards47.isDefined(opts.zod)) {
3222
3233
  const config = opts.zod;
3223
3234
  const { ZodValidatorFactory: ZodValidatorFactory2 } = await Promise.resolve().then(() => (init_zod_validator_factory(), zod_validator_factory_exports));
3224
3235
  container.addSingleton(TOKENS4.ZOD_VALIDATOR, () => {
@@ -3232,9 +3243,9 @@ var init_validation_utils = __esm({
3232
3243
  validationStrategies.push(TOKENS4.SCHEMA_VALIDATION_STRATEGY);
3233
3244
  }
3234
3245
  const customValidationFactory = [];
3235
- if (!Guards46.isNullOrEmpty(opts.customValidationStrategy)) {
3246
+ if (!Guards47.isNullOrEmpty(opts.customValidationStrategy)) {
3236
3247
  for (const strategyToken of opts.customValidationStrategy) {
3237
- if (Guards46.isDefined(strategyToken)) {
3248
+ if (Guards47.isDefined(strategyToken)) {
3238
3249
  customValidationFactory.push(strategyToken);
3239
3250
  }
3240
3251
  }
@@ -3337,8 +3348,8 @@ var init_pipeline_utils = __esm({
3337
3348
  */
3338
3349
  async addCommand(container, opts) {
3339
3350
  const pipelines = [];
3340
- const { Guards: Guards46, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3341
- if (Guards46.isDefined(opts.idempotency)) {
3351
+ const { Guards: Guards47, TOKENS: TOKENS4 } = await import("@xeno-js/shared");
3352
+ if (Guards47.isDefined(opts.idempotency)) {
3342
3353
  const { IdempotencyStore: IdempotencyStore2 } = await Promise.resolve().then(() => (init_idempotency_store(), idempotency_store_exports));
3343
3354
  container.addSingleton(
3344
3355
  TOKENS4.IDEMPOTENCY_STORE,
@@ -3358,7 +3369,7 @@ var init_pipeline_utils = __esm({
3358
3369
  });
3359
3370
  pipelines.push(TOKENS4.IDEMPOTENCY_PIPELINE);
3360
3371
  }
3361
- if (Guards46.isDefined(opts.concurrency)) {
3372
+ if (Guards47.isDefined(opts.concurrency)) {
3362
3373
  const { ConcurrencyRetryPipeline: ConcurrencyRetryPipeline2 } = await Promise.resolve().then(() => (init_application(), application_exports));
3363
3374
  container.addSingleton(TOKENS4.CONCURRENCY_RETRY_PIPELINE, () => {
3364
3375
  const config = opts.concurrency;
@@ -3438,13 +3449,13 @@ var init_cqrs_module = __esm({
3438
3449
  return new PerformancePipeline2(logger, thresholdMs);
3439
3450
  });
3440
3451
  pipelines.push(TOKENS4.PERFORMANCE_PIPELINE);
3441
- const { Guards: Guards46 } = await import("@xeno-js/shared");
3442
- if (Guards46.isDefined(opts.authorization.policies) || Guards46.isDefined(opts.authorization.customAuthorizationStrategy)) {
3452
+ const { Guards: Guards47 } = await import("@xeno-js/shared");
3453
+ if (Guards47.isDefined(opts.authorization.policies) || Guards47.isDefined(opts.authorization.customAuthorizationStrategy)) {
3443
3454
  const { AuthUtils: AuthUtils2 } = await Promise.resolve().then(() => (init_auth_utils(), auth_utils_exports));
3444
3455
  const authPipelines = await AuthUtils2.addAuthZ(container, opts.authorization);
3445
3456
  pipelines.push(...authPipelines);
3446
3457
  }
3447
- if (Guards46.isDefined(opts.validation.zod) || Guards46.isDefined(opts.validation.customValidationStrategy)) {
3458
+ if (Guards47.isDefined(opts.validation.zod) || Guards47.isDefined(opts.validation.customValidationStrategy)) {
3448
3459
  const { ValidationUtils: ValidationUtils2 } = await Promise.resolve().then(() => (init_validation_utils(), validation_utils_exports));
3449
3460
  const logger = container.resolve(TOKENS4.LOGGER);
3450
3461
  const validationPipelines = await ValidationUtils2.addValidation(
@@ -3456,11 +3467,11 @@ var init_cqrs_module = __esm({
3456
3467
  }
3457
3468
  const commandPipelines = pipelines;
3458
3469
  const queryPipelines = pipelines;
3459
- if ((Guards46.isDefined(opts.commandBus.idempotency) || opts.queryBus.isEnabled) && opts.isCache) {
3470
+ if ((Guards47.isDefined(opts.commandBus.idempotency) || opts.queryBus.isEnabled) && opts.isCache) {
3460
3471
  const { CacheUtils: CacheUtils2 } = await Promise.resolve().then(() => (init_cache_utils(), cache_utils_exports));
3461
3472
  await CacheUtils2.addCache(container, { inMemory: true, redis: void 0 });
3462
3473
  }
3463
- if (Guards46.isDefined(opts.commandBus.idempotency) || Guards46.isDefined(opts.commandBus.concurrency)) {
3474
+ if (Guards47.isDefined(opts.commandBus.idempotency) || Guards47.isDefined(opts.commandBus.concurrency)) {
3464
3475
  const { PipelineUtils: PipelineUtils2 } = await Promise.resolve().then(() => (init_pipeline_utils(), pipeline_utils_exports));
3465
3476
  const newCommandPipelines = await PipelineUtils2.addCommand(container, {
3466
3477
  ...opts.commandBus,
@@ -3649,7 +3660,10 @@ var init_allow_method_middleware = __esm({
3649
3660
  spanId: tracing?.spanId ?? GuidHelper6.generate(),
3650
3661
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
3651
3662
  },
3652
- STATUS_CODES4.NOT_ALLOWED
3663
+ STATUS_CODES4.NOT_ALLOWED,
3664
+ {
3665
+ Allow: this._allowMethod.getMethods(req.path)
3666
+ }
3653
3667
  );
3654
3668
  }
3655
3669
  return await next();
@@ -3788,11 +3802,13 @@ var init_cors_middleware = __esm({
3788
3802
  "src/presentation/middlewares/cors.middleware.ts"() {
3789
3803
  "use strict";
3790
3804
  CORSMiddleware = class {
3791
- constructor(_requestContext) {
3805
+ constructor(_requestContext, _withCredentials = "false") {
3792
3806
  this._requestContext = _requestContext;
3807
+ this._withCredentials = _withCredentials;
3793
3808
  }
3794
3809
  _requestContext;
3795
- async execute(req, _headers, next) {
3810
+ _withCredentials;
3811
+ async execute(_req, _headers, next) {
3796
3812
  const { network } = this._requestContext.getContext() ?? {};
3797
3813
  const origin = network?.origin;
3798
3814
  const response = await next();
@@ -3800,7 +3816,7 @@ var init_cors_middleware = __esm({
3800
3816
  response.headers = {
3801
3817
  ...response.headers ?? {},
3802
3818
  "Access-Control-Allow-Origin": origin,
3803
- "Access-Control-Allow-Credentials": "true",
3819
+ "Access-Control-Allow-Credentials": this._withCredentials,
3804
3820
  "Vary": "Origin"
3805
3821
  };
3806
3822
  return response;
@@ -3951,10 +3967,16 @@ var init_options_middleware = __esm({
3951
3967
  "src/presentation/middlewares/options.middleware.ts"() {
3952
3968
  "use strict";
3953
3969
  OptionsMiddleware = class {
3954
- constructor(_requestContext) {
3970
+ constructor(_requestContext, _alloewMethod, _allowHeaders = [], _withCredentials = "false") {
3955
3971
  this._requestContext = _requestContext;
3972
+ this._alloewMethod = _alloewMethod;
3973
+ this._allowHeaders = _allowHeaders;
3974
+ this._withCredentials = _withCredentials;
3956
3975
  }
3957
3976
  _requestContext;
3977
+ _alloewMethod;
3978
+ _allowHeaders;
3979
+ _withCredentials;
3958
3980
  async execute(req, _headers, next) {
3959
3981
  if (req.method.toUpperCase() === "OPTIONS") {
3960
3982
  const network = this._requestContext.getNetworkContext();
@@ -3962,11 +3984,11 @@ var init_options_middleware = __esm({
3962
3984
  const headers = {};
3963
3985
  if (Guards39.isDefined(origin)) {
3964
3986
  headers["Access-Control-Allow-Origin"] = origin;
3965
- headers["Access-Control-Allow-Credentials"] = "true";
3987
+ headers["Access-Control-Allow-Credentials"] = this._withCredentials;
3966
3988
  headers["Vary"] = "Origin";
3967
3989
  }
3968
- headers["Access-Control-Allow-Methods"] = "POST,GET,PUT,PATCH,DELETE,OPTIONS";
3969
- headers["Access-Control-Allow-Headers"] = "X-CSRF-Token, Accept, Accept-Version, Content-Type, Authorization, X-Correlation-Id";
3990
+ headers["Access-Control-Allow-Methods"] = this._alloewMethod.getMethods(req.path);
3991
+ headers["Access-Control-Allow-Headers"] = this._allowHeaders.join(", ");
3970
3992
  return HttpHelper7.success(null, STATUS_CODES8.NO_CONTENT, {}, headers);
3971
3993
  }
3972
3994
  return await next();
@@ -3976,32 +3998,42 @@ var init_options_middleware = __esm({
3976
3998
  });
3977
3999
 
3978
4000
  // src/presentation/middlewares/rate-limiter.middleware.ts
3979
- import { ERROR_CODES as ERROR_CODES7, Guards as Guards40, GuidHelper as GuidHelper10, HttpHelper as HttpHelper8, STATUS_CODES as STATUS_CODES9 } from "@xeno-js/shared";
4001
+ import {
4002
+ ERROR_CODE_MESSAGES as ERROR_CODE_MESSAGES6,
4003
+ ERROR_CODES as ERROR_CODES7,
4004
+ Guards as Guards40,
4005
+ GuidHelper as GuidHelper10,
4006
+ HttpHelper as HttpHelper8,
4007
+ STATUS_CODES as STATUS_CODES9
4008
+ } from "@xeno-js/shared";
3980
4009
  var RateLimitMiddleware;
3981
4010
  var init_rate_limiter_middleware = __esm({
3982
4011
  "src/presentation/middlewares/rate-limiter.middleware.ts"() {
3983
4012
  "use strict";
3984
4013
  RateLimitMiddleware = class {
3985
- constructor(_ctxAccessor, _cache, _logger, _opts) {
4014
+ constructor(_ctxAccessor, _cache, _keyBuilder, _logger, _opts) {
3986
4015
  this._ctxAccessor = _ctxAccessor;
3987
4016
  this._cache = _cache;
4017
+ this._keyBuilder = _keyBuilder;
3988
4018
  this._logger = _logger;
3989
4019
  this._opts = _opts;
3990
4020
  }
3991
4021
  _ctxAccessor;
3992
4022
  _cache;
4023
+ _keyBuilder;
3993
4024
  _logger;
3994
4025
  _opts;
3995
4026
  async execute(req, _headers, next) {
4027
+ const cacheKey = this._keyBuilder.buildRateLimitKey(req.path);
3996
4028
  const { network, tracing } = this._ctxAccessor.getContext() ?? {};
3997
- if (!Guards40.isDefined(network?.clientIp))
4029
+ if (!Guards40.isDefined(cacheKey))
3998
4030
  return HttpHelper8.error(
3999
4031
  {
4000
4032
  success: false,
4001
4033
  error: {
4002
4034
  code: ERROR_CODES7.SYSTEM_ERROR,
4003
- message: "IP undefined. Please contact the administrator.",
4004
- details: `IP undefined. Please contact the administrator.`,
4035
+ message: ERROR_CODE_MESSAGES6[ERROR_CODES7.SYSTEM_ERROR],
4036
+ details: `Bad Request: Unable to identify client context for rate limiting.`,
4005
4037
  path: req.path
4006
4038
  },
4007
4039
  correlationId: tracing?.correlationId ?? GuidHelper10.generate(),
@@ -4015,18 +4047,16 @@ var init_rate_limiter_middleware = __esm({
4015
4047
  "Retry-After": [String(this._opts.windowSeconds)]
4016
4048
  }
4017
4049
  );
4018
- const clientIp = network?.clientIp;
4019
- const cacheKey = `rate_limit:${clientIp}`;
4020
4050
  const currentHits = await this._cache.increment(cacheKey, this._opts.windowSeconds);
4021
4051
  if (currentHits > this._opts.maxRequests) {
4022
- this._logger.warn(`[RateLimit] IP ${clientIp} blocked on ${req.path}`);
4052
+ this._logger.warn(`[RateLimit] key ${cacheKey} has been blocked on ${req.path}`);
4023
4053
  return HttpHelper8.error(
4024
4054
  {
4025
4055
  success: false,
4026
4056
  error: {
4027
4057
  code: ERROR_CODES7.TOO_MANY_REQUESTS,
4028
- message: "Rate limit exceeded.",
4029
- details: `IP ${clientIp} throttled.`,
4058
+ message: ERROR_CODE_MESSAGES6[ERROR_CODES7.TOO_MANY_REQUESTS],
4059
+ details: `Rate limit exceeded. Key ${cacheKey} throttled.`,
4030
4060
  path: req.path
4031
4061
  },
4032
4062
  correlationId: tracing?.correlationId ?? GuidHelper10.generate(),
@@ -4107,7 +4137,7 @@ var init_context_mapper = __esm({
4107
4137
 
4108
4138
  // src/presentation/middlewares/request.middleware.ts
4109
4139
  import {
4110
- ERROR_CODE_MESSAGES as ERROR_CODE_MESSAGES6,
4140
+ ERROR_CODE_MESSAGES as ERROR_CODE_MESSAGES7,
4111
4141
  ERROR_CODES as ERROR_CODES8,
4112
4142
  GUEST as GUEST3,
4113
4143
  GuidHelper as GuidHelper11,
@@ -4176,7 +4206,7 @@ var init_request_middleware = __esm({
4176
4206
  success: false,
4177
4207
  error: {
4178
4208
  code: ERROR_CODES8.SYSTEM_ERROR,
4179
- message: ERROR_CODE_MESSAGES6[ERROR_CODES8.SYSTEM_ERROR],
4209
+ message: ERROR_CODE_MESSAGES7[ERROR_CODES8.SYSTEM_ERROR],
4180
4210
  details: `[Fatal System Error] Exception caught during request handling on path: ${req.path}`,
4181
4211
  path: req.path
4182
4212
  },
@@ -4234,13 +4264,57 @@ var init_presentation = __esm({
4234
4264
  }
4235
4265
  });
4236
4266
 
4267
+ // src/infrastructure/cache/rate-limit-key-builder.cache.ts
4268
+ import { Guards as Guards42 } from "@xeno-js/shared";
4269
+ var RateLimitKeyBuilder;
4270
+ var init_rate_limit_key_builder_cache = __esm({
4271
+ "src/infrastructure/cache/rate-limit-key-builder.cache.ts"() {
4272
+ "use strict";
4273
+ RateLimitKeyBuilder = class {
4274
+ constructor(_contextAccessor) {
4275
+ this._contextAccessor = _contextAccessor;
4276
+ }
4277
+ _contextAccessor;
4278
+ buildRateLimitKey(resource) {
4279
+ const ctx = this._contextAccessor.getContext();
4280
+ const tenantId = ctx?.identity?.tenantId;
4281
+ const userId = ctx?.identity?.userId;
4282
+ const clientIp = ctx?.network?.clientIp;
4283
+ if (!Guards42.isNullOrEmpty(tenantId) && !Guards42.isNullOrEmpty(userId))
4284
+ return `ratelimit:tenant:${tenantId}:user:${userId}:${resource}`;
4285
+ if (!Guards42.isNullOrEmpty(tenantId) && !Guards42.isNullOrEmpty(clientIp))
4286
+ return `ratelimit:tenant:${tenantId}:ip:${clientIp}:${resource}`;
4287
+ if (!Guards42.isNullOrEmpty(userId)) return `ratelimit:user:${userId}:${resource}`;
4288
+ if (!Guards42.isNullOrEmpty(clientIp)) return `ratelimit:ip:${clientIp}:${resource}`;
4289
+ return void 0;
4290
+ }
4291
+ };
4292
+ }
4293
+ });
4294
+
4295
+ // src/infrastructure/cache/index.ts
4296
+ var cache_exports = {};
4297
+ __export(cache_exports, {
4298
+ InMemoryCacheExtended: () => InMemoryCacheExtended,
4299
+ RateLimitKeyBuilder: () => RateLimitKeyBuilder,
4300
+ RedisCache: () => RedisCache
4301
+ });
4302
+ var init_cache = __esm({
4303
+ "src/infrastructure/cache/index.ts"() {
4304
+ "use strict";
4305
+ init_inmemory_cache();
4306
+ init_rate_limit_key_builder_cache();
4307
+ init_redis_cache();
4308
+ }
4309
+ });
4310
+
4237
4311
  // src/infrastructure/modules/middleware.module.ts
4238
4312
  var middleware_module_exports = {};
4239
4313
  __export(middleware_module_exports, {
4240
4314
  MiddlewareModule: () => MiddlewareModule
4241
4315
  });
4242
4316
  import {
4243
- Guards as Guards42
4317
+ Guards as Guards43
4244
4318
  } from "@xeno-js/shared";
4245
4319
  var MiddlewareModule;
4246
4320
  var init_middleware_module = __esm({
@@ -4289,10 +4363,12 @@ var init_middleware_module = __esm({
4289
4363
  c.resolve(TOKENS4.LOGGER)
4290
4364
  )
4291
4365
  );
4292
- if (!Guards42.isNullOrEmpty(opts.allowOrigins)) {
4293
- const withCredentials = Guards42.isDefined(opts.httpConfig.withCredentials) ? opts.httpConfig.withCredentials : false;
4294
- if (withCredentials && opts.allowOrigins.includes("*"))
4295
- throw new Error("Wildcard CORS origin is not allowed when withCredentials is set to true");
4366
+ if (!Guards43.isNullOrEmpty(opts.allowOrigins)) {
4367
+ const withCredentials2 = opts.httpConfig.withCredentials ?? false;
4368
+ if (withCredentials2 && opts.allowOrigins.includes("*"))
4369
+ throw new Error(
4370
+ "Wildcard CORS origin is not allowed when withCredentials is set to true in addHttpCore"
4371
+ );
4296
4372
  const { AllowOrigin: AllowOrigin2 } = await Promise.resolve().then(() => (init_services(), services_exports));
4297
4373
  container.addSingleton("ALLOW_ORIGIN", () => {
4298
4374
  return new AllowOrigin2(opts.allowOrigins);
@@ -4307,22 +4383,28 @@ var init_middleware_module = __esm({
4307
4383
  });
4308
4384
  middlewares.push(TOKENS4.ALLOW_ORIGIN_MIDDLEWARE);
4309
4385
  }
4386
+ const withCredentials = Guards43.isDefined(opts.httpConfig.withCredentials) && opts.httpConfig.withCredentials ? "true" : "false";
4310
4387
  if (opts.optionsMiddleware) {
4311
4388
  const { OptionsMiddleware: OptionsMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4312
4389
  container.addSingleton(
4313
4390
  TOKENS4.OPTIONS_MIDDLEWARE,
4314
- (c) => new OptionsMiddleware2(c.resolve(TOKENS4.NETWORK_CONTEXT_ACCESSOR))
4391
+ (c) => new OptionsMiddleware2(
4392
+ c.resolve(TOKENS4.NETWORK_CONTEXT_ACCESSOR),
4393
+ c.resolve(TOKENS4.ALLOW_METHOD),
4394
+ opts.allowHeaders,
4395
+ withCredentials
4396
+ )
4315
4397
  );
4316
4398
  middlewares.push(TOKENS4.OPTIONS_MIDDLEWARE);
4317
4399
  }
4318
4400
  if (opts.cors) {
4319
4401
  const { CORSMiddleware: CORSMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4320
4402
  container.addSingleton(TOKENS4.CORS_MIDDLEWARE, (c) => {
4321
- return new CORSMiddleware2(c.resolve(TOKENS4.CONTEXT_ACCESSOR));
4403
+ return new CORSMiddleware2(c.resolve(TOKENS4.CONTEXT_ACCESSOR), withCredentials);
4322
4404
  });
4323
4405
  middlewares.push(TOKENS4.CORS_MIDDLEWARE);
4324
4406
  }
4325
- if (Guards42.isDefined(opts.routeRegistry)) {
4407
+ if (Guards43.isDefined(opts.routeRegistry)) {
4326
4408
  const registry = opts.routeRegistry;
4327
4409
  const { AllowMethodFactory: AllowMethodFactory2 } = await Promise.resolve().then(() => (init_factories(), factories_exports));
4328
4410
  container.addSingleton(TOKENS4.ALLOW_METHOD, () => new AllowMethodFactory2().create(registry));
@@ -4346,7 +4428,38 @@ var init_middleware_module = __esm({
4346
4428
  );
4347
4429
  });
4348
4430
  middlewares.push(TOKENS4.AUTH_MIDDLEWARE);
4349
- if (Guards42.isDefined(opts.csrf)) {
4431
+ if (Guards43.isDefined(opts.rateLimite.maxRequests) || Guards43.isDefined(opts.rateLimite.windowSeconds)) {
4432
+ const maxRequests = opts.rateLimite.maxRequests ?? 30;
4433
+ Guards43.throwIfNegative(maxRequests, "MaxRequests must be positive");
4434
+ Guards43.throwIfNotInteger(maxRequests, "MaxRequests must be an integer");
4435
+ const windowSeconds = opts.rateLimite.windowSeconds ?? 30;
4436
+ Guards43.throwIfNegative(windowSeconds, "WindowSeconds must be positive");
4437
+ Guards43.throwIfNotInteger(windowSeconds, "WindowSeconds must be an integer");
4438
+ if (!opts.isCache) {
4439
+ const { CacheUtils: CacheUtils2 } = await Promise.resolve().then(() => (init_cache_utils(), cache_utils_exports));
4440
+ await CacheUtils2.addCache(container, { inMemory: true, redis: void 0 });
4441
+ }
4442
+ const { RateLimitKeyBuilder: RateLimitKeyBuilder2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
4443
+ container.addSingleton(
4444
+ "RATE_LIMIT_KEY_BUILDER",
4445
+ (c) => new RateLimitKeyBuilder2(c.resolve(TOKENS4.REQUEST_CONTEXT))
4446
+ );
4447
+ const { RateLimitMiddleware: RateLimitMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4448
+ container.addSingleton(TOKENS4.RATE_LIMITER_MIDDLEWARE, (c) => {
4449
+ return new RateLimitMiddleware2(
4450
+ c.resolve(TOKENS4.CONTEXT_ACCESSOR),
4451
+ c.resolve(TOKENS4.CACHE),
4452
+ c.resolve("RATE_LIMIT_KEY_BUILDER"),
4453
+ c.resolve(TOKENS4.LOGGER),
4454
+ {
4455
+ maxRequests,
4456
+ windowSeconds
4457
+ }
4458
+ );
4459
+ });
4460
+ middlewares.push(TOKENS4.RATE_LIMITER_MIDDLEWARE);
4461
+ }
4462
+ if (Guards43.isDefined(opts.csrf)) {
4350
4463
  const csrf = opts.csrf;
4351
4464
  const { CsrfTokenService: CsrfTokenService2 } = await Promise.resolve().then(() => (init_services(), services_exports));
4352
4465
  container.addSingleton("CSRF_TOKEN_SERVICE", (c) => {
@@ -4370,31 +4483,6 @@ var init_middleware_module = __esm({
4370
4483
  });
4371
4484
  middlewares.push(TOKENS4.CSRF_MIDDLEWARE);
4372
4485
  }
4373
- if (Guards42.isDefined(opts.rateLimite.maxRequests) || Guards42.isDefined(opts.rateLimite.windowSeconds)) {
4374
- const maxRequests = opts.rateLimite.maxRequests ?? 30;
4375
- Guards42.throwIfNegative(maxRequests, "MaxRequests must be positive");
4376
- Guards42.throwIfNotInteger(maxRequests, "MaxRequests must be an integer");
4377
- const windowSeconds = opts.rateLimite.windowSeconds ?? 30;
4378
- Guards42.throwIfNegative(windowSeconds, "WindowSeconds must be positive");
4379
- Guards42.throwIfNotInteger(windowSeconds, "WindowSeconds must be an integer");
4380
- if (!opts.isCache) {
4381
- const { CacheUtils: CacheUtils2 } = await Promise.resolve().then(() => (init_cache_utils(), cache_utils_exports));
4382
- await CacheUtils2.addCache(container, { inMemory: true, redis: void 0 });
4383
- }
4384
- const { RateLimitMiddleware: RateLimitMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4385
- container.addSingleton(TOKENS4.RATE_LIMITER_MIDDLEWARE, (c) => {
4386
- return new RateLimitMiddleware2(
4387
- c.resolve(TOKENS4.CONTEXT_ACCESSOR),
4388
- c.resolve(TOKENS4.CACHE),
4389
- c.resolve(TOKENS4.LOGGER),
4390
- {
4391
- maxRequests,
4392
- windowSeconds
4393
- }
4394
- );
4395
- });
4396
- middlewares.push(TOKENS4.RATE_LIMITER_MIDDLEWARE);
4397
- }
4398
4486
  const { CompositeMiddleware: CompositeMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4399
4487
  container.addSingleton(TOKENS4.MIDDLEWARE, (c) => {
4400
4488
  const resolvedMiddleware = middlewares.map(
@@ -4464,7 +4552,7 @@ __export(index_exports, {
4464
4552
  init_application();
4465
4553
 
4466
4554
  // src/infrastructure/builder/app.builder.ts
4467
- import { Guards as Guards43, LOG_LEVEL as LOG_LEVEL6, TOKENS as TOKENS3 } from "@xeno-js/shared";
4555
+ import { Guards as Guards44, LOG_LEVEL as LOG_LEVEL6, TOKENS as TOKENS3 } from "@xeno-js/shared";
4468
4556
 
4469
4557
  // src/infrastructure/configuration/configuration.ts
4470
4558
  import { Guards as Guards13 } from "@xeno-js/shared";
@@ -4776,6 +4864,7 @@ var AppBuilder = class {
4776
4864
  trustedIpHeader: void 0,
4777
4865
  trustedProxies: [],
4778
4866
  allowOrigins: [],
4867
+ allowHeaders: [],
4779
4868
  cors: true
4780
4869
  };
4781
4870
  _httpConfig = {
@@ -4858,7 +4947,7 @@ var AppBuilder = class {
4858
4947
  pino: { config: void 0 },
4859
4948
  customLoggers: void 0
4860
4949
  };
4861
- if (Guards43.isDefined(setupAction) && Guards43.isDefined(config))
4950
+ if (Guards44.isDefined(setupAction) && Guards44.isDefined(config))
4862
4951
  setupAction(config, this._configuration);
4863
4952
  this._modules.push({
4864
4953
  priority: 3,
@@ -4884,7 +4973,7 @@ var AppBuilder = class {
4884
4973
  addCache(setupAction) {
4885
4974
  if (this._isCacheModuleQueued) return this;
4886
4975
  this._isCacheModuleQueued = true;
4887
- if (Guards43.isDefined(setupAction)) setupAction(this._config, this._configuration);
4976
+ if (Guards44.isDefined(setupAction)) setupAction(this._config, this._configuration);
4888
4977
  this._modules.push({
4889
4978
  priority: 3,
4890
4979
  name: "CacheModule",
@@ -4993,7 +5082,7 @@ var AppBuilder = class {
4993
5082
  * @link https://github.com/xeno-js/xeno-js
4994
5083
  */
4995
5084
  addPipeline(setupAction) {
4996
- if (Guards43.isDefined(setupAction)) {
5085
+ if (Guards44.isDefined(setupAction)) {
4997
5086
  setupAction(this._pipelineConfig, this._configuration);
4998
5087
  }
4999
5088
  this._queuePipelineModule();
@@ -5127,7 +5216,7 @@ var AppBuilder = class {
5127
5216
  console.error(`\u{1F449} Module: **${queued.name}**`);
5128
5217
  console.error(`\u{1F4DD} Reason: ${errorMessage}
5129
5218
  `);
5130
- if (error instanceof Error && Guards43.isDefined(error.stack)) {
5219
+ if (error instanceof Error && Guards44.isDefined(error.stack)) {
5131
5220
  console.error(error.stack);
5132
5221
  }
5133
5222
  throw new Error(`Bootstrap failed at [${queued.name}]: ${errorMessage}`, { cause: error });
@@ -5219,8 +5308,8 @@ var AppBuilder = class {
5219
5308
  }
5220
5309
  };
5221
5310
 
5222
- // src/infrastructure/cache/index.ts
5223
- init_redis_cache();
5311
+ // src/infrastructure/index.ts
5312
+ init_cache();
5224
5313
 
5225
5314
  // src/infrastructure/context/index.ts
5226
5315
  init_request_context();
@@ -5257,7 +5346,7 @@ init_validation_utils();
5257
5346
 
5258
5347
  // src/infrastructure/repositories/read-dao.ts
5259
5348
  import { AppError as AppError16, Result as Result17 } from "@xeno-js/shared";
5260
- import { Guards as Guards44 } from "@xeno-js/shared";
5349
+ import { Guards as Guards45 } from "@xeno-js/shared";
5261
5350
  var ReadDao = class {
5262
5351
  /**
5263
5352
  * Constructs a new ReadDao instance.
@@ -5279,7 +5368,7 @@ var ReadDao = class {
5279
5368
  async findById(id, ctx, signal) {
5280
5369
  AppError16.throwIfAborted(signal, "ReadDao.findById");
5281
5370
  const result = await this._dataSource.findById(id, ctx, signal);
5282
- if (Guards44.isNullOrEmpty(result)) return Result17.ok();
5371
+ if (Guards45.isNullOrEmpty(result)) return Result17.ok();
5283
5372
  const entity = this._mapper.toEntity(result);
5284
5373
  return Result17.ok(entity);
5285
5374
  }
@@ -5293,7 +5382,7 @@ var ReadDao = class {
5293
5382
 
5294
5383
  // src/infrastructure/repositories/repository.ts
5295
5384
  import { AppError as AppError17, Result as Result18 } from "@xeno-js/shared";
5296
- import { Guards as Guards45 } from "@xeno-js/shared";
5385
+ import { Guards as Guards46 } from "@xeno-js/shared";
5297
5386
  var Repository = class {
5298
5387
  /**
5299
5388
  * Constructs a new Repository instance.
@@ -5315,7 +5404,7 @@ var Repository = class {
5315
5404
  async findById(id, ctx, signal) {
5316
5405
  AppError17.throwIfAborted(signal, "Repository.findById");
5317
5406
  const result = await this._dataSource.findById(id, ctx, signal);
5318
- if (Guards45.isNullOrEmpty(result)) return Result18.ok();
5407
+ if (Guards46.isNullOrEmpty(result)) return Result18.ok();
5319
5408
  const entity = this._mapper.toEntity(result);
5320
5409
  return Result18.ok(entity);
5321
5410
  }
@@ -5382,4 +5471,14 @@ export {
5382
5471
  * @link https://github.com/xeno-js/xeno-js
5383
5472
  * @license MIT
5384
5473
  */
5474
+ /**
5475
+ * @description The RateLimitKeyBuilder class implements the IRateLimitKeyBuilder interface, providing a method to build rate limit keys based on the user's identity. This class utilizes an instance of IIdentityAccessor to retrieve the current user's identity, allowing for the creation of tenant-specific rate limit keys in multi-tenant applications. If a tenant ID is present in the identity, the rate limit key is prefixed with the tenant ID; otherwise, it defaults to a public rate limit key. This approach ensures that rate limit data is appropriately scoped to the user's context, preventing data leakage between tenants.
5476
+ *
5477
+ * @author Xeno
5478
+ * @version 1.0.0
5479
+ * @since 2025-09-30
5480
+ * @link https://github.com/xeno-js/xeno-vue
5481
+ * @copyright Xeno
5482
+ * @license MIT
5483
+ */
5385
5484
  //# sourceMappingURL=index.js.map