@xeno-js/core 0.1.5 → 0.1.7

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,14 +4264,56 @@ 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
- import {
4243
- Guards as Guards42
4244
- } from "@xeno-js/shared";
4316
+ import { Guards as Guards43 } from "@xeno-js/shared";
4245
4317
  var MiddlewareModule;
4246
4318
  var init_middleware_module = __esm({
4247
4319
  "src/infrastructure/modules/middleware.module.ts"() {
@@ -4289,10 +4361,11 @@ var init_middleware_module = __esm({
4289
4361
  c.resolve(TOKENS4.LOGGER)
4290
4362
  )
4291
4363
  );
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");
4364
+ if (!Guards43.isNullOrEmpty(opts.allowOrigins)) {
4365
+ if (opts.withCredentials && opts.allowOrigins.includes("*"))
4366
+ throw new Error(
4367
+ "Wildcard CORS origin is not allowed when withCredentials is set to true in addHttpCore"
4368
+ );
4296
4369
  const { AllowOrigin: AllowOrigin2 } = await Promise.resolve().then(() => (init_services(), services_exports));
4297
4370
  container.addSingleton("ALLOW_ORIGIN", () => {
4298
4371
  return new AllowOrigin2(opts.allowOrigins);
@@ -4307,22 +4380,28 @@ var init_middleware_module = __esm({
4307
4380
  });
4308
4381
  middlewares.push(TOKENS4.ALLOW_ORIGIN_MIDDLEWARE);
4309
4382
  }
4383
+ const withCredentials = opts.withCredentials ? "true" : "false";
4310
4384
  if (opts.optionsMiddleware) {
4311
4385
  const { OptionsMiddleware: OptionsMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4312
4386
  container.addSingleton(
4313
4387
  TOKENS4.OPTIONS_MIDDLEWARE,
4314
- (c) => new OptionsMiddleware2(c.resolve(TOKENS4.NETWORK_CONTEXT_ACCESSOR))
4388
+ (c) => new OptionsMiddleware2(
4389
+ c.resolve(TOKENS4.NETWORK_CONTEXT_ACCESSOR),
4390
+ c.resolve(TOKENS4.ALLOW_METHOD),
4391
+ opts.allowHeaders,
4392
+ withCredentials
4393
+ )
4315
4394
  );
4316
4395
  middlewares.push(TOKENS4.OPTIONS_MIDDLEWARE);
4317
4396
  }
4318
4397
  if (opts.cors) {
4319
4398
  const { CORSMiddleware: CORSMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4320
4399
  container.addSingleton(TOKENS4.CORS_MIDDLEWARE, (c) => {
4321
- return new CORSMiddleware2(c.resolve(TOKENS4.CONTEXT_ACCESSOR));
4400
+ return new CORSMiddleware2(c.resolve(TOKENS4.CONTEXT_ACCESSOR), withCredentials);
4322
4401
  });
4323
4402
  middlewares.push(TOKENS4.CORS_MIDDLEWARE);
4324
4403
  }
4325
- if (Guards42.isDefined(opts.routeRegistry)) {
4404
+ if (Guards43.isDefined(opts.routeRegistry)) {
4326
4405
  const registry = opts.routeRegistry;
4327
4406
  const { AllowMethodFactory: AllowMethodFactory2 } = await Promise.resolve().then(() => (init_factories(), factories_exports));
4328
4407
  container.addSingleton(TOKENS4.ALLOW_METHOD, () => new AllowMethodFactory2().create(registry));
@@ -4346,7 +4425,38 @@ var init_middleware_module = __esm({
4346
4425
  );
4347
4426
  });
4348
4427
  middlewares.push(TOKENS4.AUTH_MIDDLEWARE);
4349
- if (Guards42.isDefined(opts.csrf)) {
4428
+ if (Guards43.isDefined(opts.rateLimite.maxRequests) || Guards43.isDefined(opts.rateLimite.windowSeconds)) {
4429
+ const maxRequests = opts.rateLimite.maxRequests ?? 30;
4430
+ Guards43.throwIfNegative(maxRequests, "MaxRequests must be positive");
4431
+ Guards43.throwIfNotInteger(maxRequests, "MaxRequests must be an integer");
4432
+ const windowSeconds = opts.rateLimite.windowSeconds ?? 30;
4433
+ Guards43.throwIfNegative(windowSeconds, "WindowSeconds must be positive");
4434
+ Guards43.throwIfNotInteger(windowSeconds, "WindowSeconds must be an integer");
4435
+ if (!opts.isCache) {
4436
+ const { CacheUtils: CacheUtils2 } = await Promise.resolve().then(() => (init_cache_utils(), cache_utils_exports));
4437
+ await CacheUtils2.addCache(container, { inMemory: true, redis: void 0 });
4438
+ }
4439
+ const { RateLimitKeyBuilder: RateLimitKeyBuilder2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
4440
+ container.addSingleton(
4441
+ "RATE_LIMIT_KEY_BUILDER",
4442
+ (c) => new RateLimitKeyBuilder2(c.resolve(TOKENS4.REQUEST_CONTEXT))
4443
+ );
4444
+ const { RateLimitMiddleware: RateLimitMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4445
+ container.addSingleton(TOKENS4.RATE_LIMITER_MIDDLEWARE, (c) => {
4446
+ return new RateLimitMiddleware2(
4447
+ c.resolve(TOKENS4.CONTEXT_ACCESSOR),
4448
+ c.resolve(TOKENS4.CACHE),
4449
+ c.resolve("RATE_LIMIT_KEY_BUILDER"),
4450
+ c.resolve(TOKENS4.LOGGER),
4451
+ {
4452
+ maxRequests,
4453
+ windowSeconds
4454
+ }
4455
+ );
4456
+ });
4457
+ middlewares.push(TOKENS4.RATE_LIMITER_MIDDLEWARE);
4458
+ }
4459
+ if (Guards43.isDefined(opts.csrf)) {
4350
4460
  const csrf = opts.csrf;
4351
4461
  const { CsrfTokenService: CsrfTokenService2 } = await Promise.resolve().then(() => (init_services(), services_exports));
4352
4462
  container.addSingleton("CSRF_TOKEN_SERVICE", (c) => {
@@ -4370,31 +4480,6 @@ var init_middleware_module = __esm({
4370
4480
  });
4371
4481
  middlewares.push(TOKENS4.CSRF_MIDDLEWARE);
4372
4482
  }
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
4483
  const { CompositeMiddleware: CompositeMiddleware2 } = await Promise.resolve().then(() => (init_presentation(), presentation_exports));
4399
4484
  container.addSingleton(TOKENS4.MIDDLEWARE, (c) => {
4400
4485
  const resolvedMiddleware = middlewares.map(
@@ -4464,7 +4549,7 @@ __export(index_exports, {
4464
4549
  init_application();
4465
4550
 
4466
4551
  // src/infrastructure/builder/app.builder.ts
4467
- import { Guards as Guards43, LOG_LEVEL as LOG_LEVEL6, TOKENS as TOKENS3 } from "@xeno-js/shared";
4552
+ import { Guards as Guards44, LOG_LEVEL as LOG_LEVEL6, TOKENS as TOKENS3 } from "@xeno-js/shared";
4468
4553
 
4469
4554
  // src/infrastructure/configuration/configuration.ts
4470
4555
  import { Guards as Guards13 } from "@xeno-js/shared";
@@ -4776,7 +4861,9 @@ var AppBuilder = class {
4776
4861
  trustedIpHeader: void 0,
4777
4862
  trustedProxies: [],
4778
4863
  allowOrigins: [],
4779
- cors: true
4864
+ allowHeaders: [],
4865
+ cors: true,
4866
+ withCredentials: true
4780
4867
  };
4781
4868
  _httpConfig = {
4782
4869
  dataSourceToken: void 0,
@@ -4858,7 +4945,7 @@ var AppBuilder = class {
4858
4945
  pino: { config: void 0 },
4859
4946
  customLoggers: void 0
4860
4947
  };
4861
- if (Guards43.isDefined(setupAction) && Guards43.isDefined(config))
4948
+ if (Guards44.isDefined(setupAction) && Guards44.isDefined(config))
4862
4949
  setupAction(config, this._configuration);
4863
4950
  this._modules.push({
4864
4951
  priority: 3,
@@ -4884,7 +4971,7 @@ var AppBuilder = class {
4884
4971
  addCache(setupAction) {
4885
4972
  if (this._isCacheModuleQueued) return this;
4886
4973
  this._isCacheModuleQueued = true;
4887
- if (Guards43.isDefined(setupAction)) setupAction(this._config, this._configuration);
4974
+ if (Guards44.isDefined(setupAction)) setupAction(this._config, this._configuration);
4888
4975
  this._modules.push({
4889
4976
  priority: 3,
4890
4977
  name: "CacheModule",
@@ -4993,7 +5080,7 @@ var AppBuilder = class {
4993
5080
  * @link https://github.com/xeno-js/xeno-js
4994
5081
  */
4995
5082
  addPipeline(setupAction) {
4996
- if (Guards43.isDefined(setupAction)) {
5083
+ if (Guards44.isDefined(setupAction)) {
4997
5084
  setupAction(this._pipelineConfig, this._configuration);
4998
5085
  }
4999
5086
  this._queuePipelineModule();
@@ -5127,7 +5214,7 @@ var AppBuilder = class {
5127
5214
  console.error(`\u{1F449} Module: **${queued.name}**`);
5128
5215
  console.error(`\u{1F4DD} Reason: ${errorMessage}
5129
5216
  `);
5130
- if (error instanceof Error && Guards43.isDefined(error.stack)) {
5217
+ if (error instanceof Error && Guards44.isDefined(error.stack)) {
5131
5218
  console.error(error.stack);
5132
5219
  }
5133
5220
  throw new Error(`Bootstrap failed at [${queued.name}]: ${errorMessage}`, { cause: error });
@@ -5189,8 +5276,7 @@ var AppBuilder = class {
5189
5276
  ...this._middlewareConfig,
5190
5277
  isAuth: this._isAuthModuleQueued,
5191
5278
  isLogger: this._isLoggerModuleQueued,
5192
- isCache: this._isCacheModuleQueued || this._isPipelineModuleQueued,
5193
- httpConfig: this._httpConfig.http.client
5279
+ isCache: this._isCacheModuleQueued || this._isPipelineModuleQueued
5194
5280
  });
5195
5281
  }
5196
5282
  });
@@ -5219,8 +5305,8 @@ var AppBuilder = class {
5219
5305
  }
5220
5306
  };
5221
5307
 
5222
- // src/infrastructure/cache/index.ts
5223
- init_redis_cache();
5308
+ // src/infrastructure/index.ts
5309
+ init_cache();
5224
5310
 
5225
5311
  // src/infrastructure/context/index.ts
5226
5312
  init_request_context();
@@ -5257,7 +5343,7 @@ init_validation_utils();
5257
5343
 
5258
5344
  // src/infrastructure/repositories/read-dao.ts
5259
5345
  import { AppError as AppError16, Result as Result17 } from "@xeno-js/shared";
5260
- import { Guards as Guards44 } from "@xeno-js/shared";
5346
+ import { Guards as Guards45 } from "@xeno-js/shared";
5261
5347
  var ReadDao = class {
5262
5348
  /**
5263
5349
  * Constructs a new ReadDao instance.
@@ -5279,7 +5365,7 @@ var ReadDao = class {
5279
5365
  async findById(id, ctx, signal) {
5280
5366
  AppError16.throwIfAborted(signal, "ReadDao.findById");
5281
5367
  const result = await this._dataSource.findById(id, ctx, signal);
5282
- if (Guards44.isNullOrEmpty(result)) return Result17.ok();
5368
+ if (Guards45.isNullOrEmpty(result)) return Result17.ok();
5283
5369
  const entity = this._mapper.toEntity(result);
5284
5370
  return Result17.ok(entity);
5285
5371
  }
@@ -5293,7 +5379,7 @@ var ReadDao = class {
5293
5379
 
5294
5380
  // src/infrastructure/repositories/repository.ts
5295
5381
  import { AppError as AppError17, Result as Result18 } from "@xeno-js/shared";
5296
- import { Guards as Guards45 } from "@xeno-js/shared";
5382
+ import { Guards as Guards46 } from "@xeno-js/shared";
5297
5383
  var Repository = class {
5298
5384
  /**
5299
5385
  * Constructs a new Repository instance.
@@ -5315,7 +5401,7 @@ var Repository = class {
5315
5401
  async findById(id, ctx, signal) {
5316
5402
  AppError17.throwIfAborted(signal, "Repository.findById");
5317
5403
  const result = await this._dataSource.findById(id, ctx, signal);
5318
- if (Guards45.isNullOrEmpty(result)) return Result18.ok();
5404
+ if (Guards46.isNullOrEmpty(result)) return Result18.ok();
5319
5405
  const entity = this._mapper.toEntity(result);
5320
5406
  return Result18.ok(entity);
5321
5407
  }
@@ -5382,4 +5468,14 @@ export {
5382
5468
  * @link https://github.com/xeno-js/xeno-js
5383
5469
  * @license MIT
5384
5470
  */
5471
+ /**
5472
+ * @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.
5473
+ *
5474
+ * @author Xeno
5475
+ * @version 1.0.0
5476
+ * @since 2025-09-30
5477
+ * @link https://github.com/xeno-js/xeno-vue
5478
+ * @copyright Xeno
5479
+ * @license MIT
5480
+ */
5385
5481
  //# sourceMappingURL=index.js.map