@riocrypto/common-server 1.0.2275 → 1.0.2278

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.
@@ -47,6 +47,7 @@
47
47
  /// <reference types="mongoose/types/virtuals" />
48
48
  /// <reference types="mongoose" />
49
49
  /// <reference types="mongoose/types/inferschematype" />
50
+ /// <reference types="mongoose/types/inferrawdoctype" />
50
51
  /// <reference types="mongoose/types/inferschematype" />
51
52
  /// <reference types="mongoose/types/inferrawdoctype" />
52
53
  import { BankAccountDoc } from "@riocrypto/common-server";
@@ -47,6 +47,7 @@
47
47
  /// <reference types="mongoose/types/virtuals" />
48
48
  /// <reference types="mongoose" />
49
49
  /// <reference types="mongoose/types/inferschematype" />
50
+ /// <reference types="mongoose/types/inferrawdoctype" />
50
51
  /// <reference types="mongoose/types/inferschematype" />
51
52
  /// <reference types="mongoose/types/inferrawdoctype" />
52
53
  import { CryptoAddressDoc } from "@riocrypto/common-server";
@@ -47,6 +47,7 @@
47
47
  /// <reference types="mongoose/types/virtuals" />
48
48
  /// <reference types="mongoose" />
49
49
  /// <reference types="mongoose/types/inferschematype" />
50
+ /// <reference types="mongoose/types/inferrawdoctype" />
50
51
  /// <reference types="mongoose/types/inferschematype" />
51
52
  /// <reference types="mongoose/types/inferrawdoctype" />
52
53
  import { OrderDoc } from "@riocrypto/common-server";
@@ -47,6 +47,7 @@
47
47
  /// <reference types="mongoose/types/virtuals" />
48
48
  /// <reference types="mongoose" />
49
49
  /// <reference types="mongoose/types/inferschematype" />
50
+ /// <reference types="mongoose/types/inferrawdoctype" />
50
51
  /// <reference types="mongoose/types/inferschematype" />
51
52
  /// <reference types="mongoose/types/inferrawdoctype" />
52
53
  import { UserDoc } from "@riocrypto/common-server";
package/build/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./middlewares/set-trace";
7
7
  export * from "./middlewares/require-min-role";
8
8
  export * from "./middlewares/require-min-admin-role";
9
9
  export * from "./middlewares/verify-csrf-token";
10
+ export * from "./middlewares/dynamic-rate-limiter";
10
11
  export * from "./services/apiKey";
11
12
  export * from "./services/password";
12
13
  export * from "./services/logger";
@@ -91,6 +92,7 @@ export * from "./models/STP-settings";
91
92
  export * from "./models/dashboard-push-notification-subscription";
92
93
  export * from "./models/webauthn-credential";
93
94
  export * from "./models/admin-webauthn-credential";
95
+ export * from "./models/custom-rate-limit";
94
96
  export * from "./clients/axios-with-logging";
95
97
  export * from "./clients/slack-client";
96
98
  export * from "./clients/fireblocks-client";
package/build/index.js CHANGED
@@ -23,6 +23,7 @@ __exportStar(require("./middlewares/set-trace"), exports);
23
23
  __exportStar(require("./middlewares/require-min-role"), exports);
24
24
  __exportStar(require("./middlewares/require-min-admin-role"), exports);
25
25
  __exportStar(require("./middlewares/verify-csrf-token"), exports);
26
+ __exportStar(require("./middlewares/dynamic-rate-limiter"), exports);
26
27
  __exportStar(require("./services/apiKey"), exports);
27
28
  __exportStar(require("./services/password"), exports);
28
29
  __exportStar(require("./services/logger"), exports);
@@ -107,6 +108,7 @@ __exportStar(require("./models/STP-settings"), exports);
107
108
  __exportStar(require("./models/dashboard-push-notification-subscription"), exports);
108
109
  __exportStar(require("./models/webauthn-credential"), exports);
109
110
  __exportStar(require("./models/admin-webauthn-credential"), exports);
111
+ __exportStar(require("./models/custom-rate-limit"), exports);
110
112
  __exportStar(require("./clients/axios-with-logging"), exports);
111
113
  __exportStar(require("./clients/slack-client"), exports);
112
114
  __exportStar(require("./clients/fireblocks-client"), exports);
@@ -0,0 +1,10 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ import { Options as RateLimitOptions } from "express-rate-limit";
3
+ import { Mongoose } from "mongoose";
4
+ export interface DynamicRateLimiterOptions extends Partial<RateLimitOptions> {
5
+ windowMs: number;
6
+ max: number;
7
+ mongooseConnection: Mongoose;
8
+ cacheTtlMs?: number;
9
+ }
10
+ export declare function createDynamicRateLimiter(options: DynamicRateLimiterOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.createDynamicRateLimiter = void 0;
27
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
28
+ // Removed path-to-regexp import
29
+ // Adjust the import path according to your project structure
30
+ const custom_rate_limit_1 = require("../models/custom-rate-limit");
31
+ // Cache for rate limiter instances
32
+ const limiterInstanceCache = new Map();
33
+ // Cache for compiled RegExp objects from path strings
34
+ // Key: regex string pattern, Value: compiled RegExp object
35
+ const regexCache = new Map();
36
+ // In-memory cache for custom IP rules
37
+ let customIpRulesCache = new Map();
38
+ let lastCacheRefreshTime = 0;
39
+ const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
40
+ function refreshCustomIpRulesCache(CustomRateLimit, filePathForLog) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ try {
43
+ const allRules = yield CustomRateLimit.find({}).lean();
44
+ const newCache = new Map();
45
+ allRules.forEach((rule) => {
46
+ if (rule.ipAddress) {
47
+ // Pre-compile and cache regexes when rules are loaded/refreshed
48
+ if (rule.routes && Array.isArray(rule.routes)) {
49
+ rule.routes.forEach((routeRule) => {
50
+ // Use any temporarily if lean typing is tricky
51
+ if (typeof routeRule.path === "string" &&
52
+ !regexCache.has(routeRule.path)) {
53
+ try {
54
+ regexCache.set(routeRule.path, new RegExp(routeRule.path));
55
+ }
56
+ catch (e) {
57
+ console.error(`[DynamicRateLimiter Refresh] Failed to compile regex: '${routeRule.path}' for IP ${rule.ipAddress}. Skipping rule path. Error:`, e);
58
+ // Optionally mark the rule path as invalid or handle differently
59
+ }
60
+ }
61
+ });
62
+ }
63
+ newCache.set(rule.ipAddress, rule);
64
+ }
65
+ });
66
+ customIpRulesCache = newCache;
67
+ lastCacheRefreshTime = Date.now();
68
+ }
69
+ catch (error) {
70
+ console.error(`[DynamicRateLimiter ${filePathForLog}] Error refreshing custom IP rules cache:`, error);
71
+ }
72
+ });
73
+ }
74
+ function createDynamicRateLimiter(options) {
75
+ const { windowMs: defaultWindowMs, max: defaultMax, mongooseConnection, cacheTtlMs = DEFAULT_CACHE_TTL_MS, message, standardHeaders, legacyHeaders, skip, requestPropertyName } = options, otherRateLimitOptions = __rest(options, ["windowMs", "max", "mongooseConnection", "cacheTtlMs", "message", "standardHeaders", "legacyHeaders", "skip", "requestPropertyName"]);
76
+ if (!mongooseConnection) {
77
+ throw new Error("[DynamicRateLimiter] Mongoose connection is required.");
78
+ }
79
+ const CustomRateLimit = (0, custom_rate_limit_1.buildCustomRateLimit)(mongooseConnection);
80
+ // Initial cache load (regex compilation happens here too)
81
+ refreshCustomIpRulesCache(CustomRateLimit, "initialization");
82
+ return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
83
+ try {
84
+ // Refresh cache if stale
85
+ if (Date.now() - lastCacheRefreshTime > cacheTtlMs ||
86
+ (customIpRulesCache.size === 0 && lastCacheRefreshTime === 0)) {
87
+ yield refreshCustomIpRulesCache(CustomRateLimit, req.path);
88
+ }
89
+ let clientIp = req.ip;
90
+ let normalizedIp;
91
+ if (clientIp) {
92
+ // Normalize IPv4-mapped IPv6 addresses (::ffff:x.x.x.x)
93
+ if (clientIp.startsWith("::ffff:")) {
94
+ normalizedIp = clientIp.substring(7);
95
+ }
96
+ else {
97
+ normalizedIp = clientIp;
98
+ }
99
+ }
100
+ let currentLimit = defaultMax;
101
+ let currentWindowMs = defaultWindowMs;
102
+ let ruleIdentifier = "default"; // Start with default identifier
103
+ let customRuleDoc;
104
+ let matchingRule = undefined;
105
+ if (normalizedIp) {
106
+ customRuleDoc = customIpRulesCache.get(normalizedIp);
107
+ }
108
+ if (customRuleDoc &&
109
+ customRuleDoc.routes &&
110
+ customRuleDoc.routes.length > 0) {
111
+ // Find the first specific rule that matches the request path and method
112
+ matchingRule = customRuleDoc.routes.find((rule) => {
113
+ const methodMatch = rule.action === "*" || rule.action === req.method.toUpperCase();
114
+ if (!methodMatch)
115
+ return false;
116
+ const regex = regexCache.get(rule.path);
117
+ if (!regex)
118
+ return false; // Should have been compiled on refresh
119
+ return regex.test(req.path);
120
+ });
121
+ if (matchingRule) {
122
+ // Apply limit and window from the *specific matching rule*
123
+ currentLimit = matchingRule.limit;
124
+ currentWindowMs = matchingRule.windowMs;
125
+ // Create a more specific identifier including the matched rule path/action
126
+ ruleIdentifier = `custom_ip:${normalizedIp}_rule:${matchingRule.action}:${matchingRule.path}`;
127
+ }
128
+ // If no specific rule in the array matches, we just fall through
129
+ // and the defaults (currentLimit = defaultMax etc.) will be used.
130
+ }
131
+ // If customRuleDoc is undefined or routes array is empty, defaults apply.
132
+ // Generate cache key for the limiter instance. This will be unique for:
133
+ // - Default limit (if no rule found/matched)
134
+ // - Each specific matching rule (due to unique ruleIdentifier)
135
+ const limiterCacheKey = `${currentLimit}-${currentWindowMs}-${ruleIdentifier}`;
136
+ let selectedLimiter = limiterInstanceCache.get(limiterCacheKey);
137
+ if (!selectedLimiter) {
138
+ // Create a new limiter instance with the determined limit/window
139
+ selectedLimiter = (0, express_rate_limit_1.default)(Object.assign({ windowMs: currentWindowMs, max: currentLimit, keyGenerator: (request) => {
140
+ let ipForKey = request.ip;
141
+ if (ipForKey === null || ipForKey === void 0 ? void 0 : ipForKey.startsWith("::ffff:")) {
142
+ ipForKey = ipForKey.substring(7);
143
+ }
144
+ return ipForKey || "unknown_ip_for_rate_limit";
145
+ }, message: message, standardHeaders: standardHeaders, legacyHeaders: legacyHeaders, skip: skip, requestPropertyName: requestPropertyName }, otherRateLimitOptions));
146
+ limiterInstanceCache.set(limiterCacheKey, selectedLimiter);
147
+ }
148
+ return selectedLimiter(req, res, next);
149
+ }
150
+ catch (error) {
151
+ console.error(`[DynamicRateLimiter ${req.path}] Error in rate limiting middleware (IP: ${req.ip}):`, error);
152
+ next();
153
+ }
154
+ });
155
+ }
156
+ exports.createDynamicRateLimiter = createDynamicRateLimiter;
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Mongoose, Model, Document } from "mongoose";
3
4
  import { AdminAuthDoc } from "./admin-auth";
4
5
  export interface AdminWebAuthnCredentialAttrs {
@@ -0,0 +1,22 @@
1
+ import mongoose from "mongoose";
2
+ interface RouteRule {
3
+ path: string;
4
+ action: string;
5
+ limit: number;
6
+ windowMs: number;
7
+ }
8
+ interface CustomRateLimitAttrs {
9
+ createdAt: Date;
10
+ ipAddress: string;
11
+ routes: RouteRule[];
12
+ }
13
+ interface CustomRateLimitDoc extends mongoose.Document {
14
+ createdAt: Date;
15
+ ipAddress: string;
16
+ routes: RouteRule[];
17
+ }
18
+ interface CustomRateLimitModel extends mongoose.Model<CustomRateLimitDoc> {
19
+ build(attrs: CustomRateLimitAttrs): CustomRateLimitDoc;
20
+ }
21
+ declare const buildCustomRateLimit: (mongoose: typeof mongoose) => CustomRateLimitModel;
22
+ export { buildCustomRateLimit, CustomRateLimitDoc, CustomRateLimitAttrs, RouteRule, };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCustomRateLimit = void 0;
4
+ const buildCustomRateLimit = (mongoose) => {
5
+ if (mongoose.models.CustomRateLimit) {
6
+ return mongoose.model("CustomRateLimit");
7
+ }
8
+ // Updated: Define the schema for the nested RouteRule object including limits
9
+ const RouteRuleSchema = new mongoose.Schema({
10
+ path: {
11
+ type: String,
12
+ required: [true, "Path (regex string) is required for a route rule"],
13
+ },
14
+ action: {
15
+ type: String,
16
+ required: [true, "Action (HTTP method) is required for a route rule"],
17
+ uppercase: true,
18
+ // enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', '*']
19
+ },
20
+ limit: {
21
+ type: Number,
22
+ required: [true, "Limit is required for a specific route rule"],
23
+ min: [0, "Limit cannot be negative"], // Allow 0 for blocking?
24
+ },
25
+ windowMs: {
26
+ type: Number,
27
+ required: [true, "windowMs is required for a specific route rule"],
28
+ min: [1000, "windowMs must be at least 1000 (1 second)"],
29
+ },
30
+ }, { _id: false });
31
+ const CustomRateLimitSchema = new mongoose.Schema({
32
+ createdAt: {
33
+ type: mongoose.Schema.Types.Date,
34
+ default: Date.now,
35
+ },
36
+ ipAddress: {
37
+ type: String,
38
+ required: true,
39
+ // Add index for faster IP lookups
40
+ index: true,
41
+ },
42
+ // Removed limit and windowMs from top level schema
43
+ routes: {
44
+ type: [RouteRuleSchema],
45
+ required: true,
46
+ // Default to empty array. If empty, default limiter settings apply.
47
+ default: [],
48
+ },
49
+ }, {
50
+ toJSON: {
51
+ transform(doc, ret) {
52
+ ret.id = ret._id;
53
+ delete ret._id;
54
+ delete ret.__v;
55
+ },
56
+ },
57
+ });
58
+ CustomRateLimitSchema.statics.build = (attrs) => {
59
+ var _a;
60
+ return new CustomRateLimit(Object.assign(Object.assign({}, attrs), { createdAt: (_a = attrs.createdAt) !== null && _a !== void 0 ? _a : new Date() }));
61
+ };
62
+ const CustomRateLimit = mongoose.model("CustomRateLimit", CustomRateLimitSchema);
63
+ return CustomRateLimit;
64
+ };
65
+ exports.buildCustomRateLimit = buildCustomRateLimit;
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Mongoose, Model, Document } from "mongoose";
3
4
  import { AuthDoc } from "./auth";
4
5
  export interface WebAuthnCredentialAttrs {
@@ -14,8 +14,10 @@ const winston_1 = require("winston");
14
14
  class LoggerService {
15
15
  constructor() {
16
16
  this.maskSensitiveData = (0, winston_1.format)((info) => {
17
+ var _a, _b, _c, _d, _e;
17
18
  // Mask sensitive headers
18
- if (info.meta && info.meta.req && info.meta.req.headers) {
19
+ if ((_b = (_a = info.meta) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.headers) {
20
+ // Use optional chaining
19
21
  const headers = info.meta.req.headers;
20
22
  const headerKeysToMask = [
21
23
  "x-api-key",
@@ -24,7 +26,8 @@ class LoggerService {
24
26
  ];
25
27
  headerKeysToMask.forEach((key) => {
26
28
  if (headers[key]) {
27
- headers[key] = this.maskValue(headers[key]); // Use maskValue function
29
+ // Type assertion might be needed if headers[key] is not strictly string
30
+ headers[key] = this.maskValue(String(headers[key]));
28
31
  }
29
32
  });
30
33
  // Mask cookies specifically
@@ -38,22 +41,26 @@ class LoggerService {
38
41
  key === "refreshToken" ||
39
42
  key === "adminRefreshToken" ||
40
43
  key === "phoneVerifiedJWT") {
41
- return `${key}=${this.maskValue(value, true)}`; // Mask the sensitive cookie
44
+ return `${key}=${this.maskValue(value, true)}`;
42
45
  }
43
- return cookie; // Return unmodified if not sensitive
46
+ return cookie;
44
47
  })
45
48
  .join("; ");
46
49
  }
47
50
  }
48
51
  // Mask sensitive request body fields
49
- if (info.meta && info.meta.req && info.meta.req.body) {
52
+ if (((_d = (_c = info.meta) === null || _c === void 0 ? void 0 : _c.req) === null || _d === void 0 ? void 0 : _d.body) &&
53
+ typeof info.meta.req.body === "object" &&
54
+ info.meta.req.body !== null) {
55
+ const requestBody = info.meta.req.body; // Type assertion
50
56
  const requestBodyFieldsToMaskWithLastFour = [
51
57
  "accountNumber",
52
58
  "routingNumber",
53
59
  ];
54
60
  requestBodyFieldsToMaskWithLastFour.forEach((field) => {
55
- if (info.meta.req.body.hasOwnProperty(field)) {
56
- info.meta.req.body[field] = this.maskValue(info.meta.req.body[field], true);
61
+ if (requestBody.hasOwnProperty(field) &&
62
+ typeof requestBody[field] === "string") {
63
+ requestBody[field] = this.maskValue(requestBody[field], true);
57
64
  }
58
65
  });
59
66
  const requestBodyFieldsToMaskWithoutLastFour = [
@@ -64,26 +71,34 @@ class LoggerService {
64
71
  "authenticatorCode",
65
72
  ];
66
73
  requestBodyFieldsToMaskWithoutLastFour.forEach((field) => {
67
- if (info.meta.req.body.hasOwnProperty(field)) {
68
- info.meta.req.body[field] = this.maskValue(info.meta.req.body[field]);
74
+ if (requestBody.hasOwnProperty(field) &&
75
+ typeof requestBody[field] === "string") {
76
+ requestBody[field] = this.maskValue(requestBody[field]);
69
77
  }
70
78
  });
71
79
  }
72
80
  // Mask sensitive response body fields
73
- if (info.meta && info.meta.res && info.meta.res.body) {
81
+ const resAsAny = (_e = info.meta) === null || _e === void 0 ? void 0 : _e.res;
82
+ if ((resAsAny === null || resAsAny === void 0 ? void 0 : resAsAny.body) &&
83
+ typeof resAsAny.body === "object" &&
84
+ resAsAny.body !== null) {
85
+ const responseBody = resAsAny.body; // Keep this assertion for object access
74
86
  const responseBodyFieldsToMask = ["secret", "value"];
75
87
  responseBodyFieldsToMask.forEach((field) => {
76
- if (info.meta.res.body.hasOwnProperty(field)) {
77
- info.meta.res.body[field] = this.maskValue(info.meta.res.body[field]); // Use maskValue function
88
+ if (responseBody.hasOwnProperty(field) &&
89
+ typeof responseBody[field] === "string") {
90
+ responseBody[field] = this.maskValue(responseBody[field]);
78
91
  }
79
92
  });
80
93
  }
81
94
  return info;
82
95
  });
83
96
  this.requestMethodFilter = (0, winston_1.format)((info) => {
97
+ var _a, _b;
84
98
  const allowedMethods = ["POST", "PATCH", "DELETE"];
85
99
  // Only apply filter if req.method is defined
86
- if (info.meta && info.meta.req && info.meta.req.method) {
100
+ if ((_b = (_a = info.meta) === null || _a === void 0 ? void 0 : _a.req) === null || _b === void 0 ? void 0 : _b.method) {
101
+ // Use optional chaining
87
102
  if (allowedMethods.includes(info.meta.req.method)) {
88
103
  return info;
89
104
  }
@@ -96,41 +111,41 @@ class LoggerService {
96
111
  });
97
112
  // Custom format to handle CustomError serialization
98
113
  this.handleCustomErrorFormat = (0, winston_1.format)((info) => {
114
+ var _a, _b, _c;
99
115
  let error;
100
116
  // express-winston errorLogger often puts the error in info.message or info.meta.err
101
117
  if (info.message instanceof Error) {
102
118
  error = info.message;
103
119
  }
104
- else if (info.meta && info.meta.err instanceof Error) {
120
+ else if (((_a = info.meta) === null || _a === void 0 ? void 0 : _a.err) instanceof Error) {
121
+ // Use optional chaining
105
122
  error = info.meta.err;
106
123
  }
107
124
  else if (info.level === "error" &&
108
125
  info.message &&
109
126
  typeof info.message === "object" &&
110
- info.message.stack) {
111
- // Sometimes the error object might be directly in message for non-express-winston logs
127
+ info.message.stack // Type assertion to check for stack
128
+ ) {
112
129
  error = info.message;
113
130
  }
114
131
  if (error instanceof common_1.CustomError) {
115
- // Replace the error object/message with serialized details
116
- // Log serialized errors under 'errorDetails' and keep original message if it's just a string
117
132
  info.errorDetails = error.serializeErrors();
118
133
  if (typeof info.message === "object") {
119
- info.message = error.message; // Keep the original error message string
134
+ info.message = error.message;
120
135
  }
121
- // Prevent Winston from trying to serialize the original complex error object
122
- if (info.meta && info.meta.err) {
136
+ if ((_b = info.meta) === null || _b === void 0 ? void 0 : _b.err) {
137
+ // Use optional chaining
123
138
  delete info.meta.err;
124
139
  }
125
140
  }
126
141
  else if (error) {
127
- // For generic errors, ensure the stack is included if available
128
142
  info.errorMessage = error.message;
129
143
  info.errorStack = error.stack;
130
144
  if (typeof info.message === "object") {
131
145
  info.message = error.message;
132
146
  }
133
- if (info.meta && info.meta.err) {
147
+ if ((_c = info.meta) === null || _c === void 0 ? void 0 : _c.err) {
148
+ // Use optional chaining
134
149
  delete info.meta.err;
135
150
  }
136
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2275",
3
+ "version": "1.0.2278",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -34,6 +34,7 @@
34
34
  "crypto-js": "^4.2.0",
35
35
  "csurf": "^1.11.0",
36
36
  "express": "^4.21.1",
37
+ "express-rate-limit": "^7.5.0",
37
38
  "express-validator": "^6.14.2",
38
39
  "fireblocks-sdk": "^5.13.0",
39
40
  "googleapis": "^135.1.0",