@universis/janitor 1.9.0 → 1.10.0

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.esm.js CHANGED
@@ -3,6 +3,7 @@ import { ApplicationService, TraceUtils, ConfigurationStrategy, Args, HttpForbid
3
3
  import { rateLimit } from 'express-rate-limit';
4
4
  import express from 'express';
5
5
  import path from 'path';
6
+ import { BehaviorSubject } from 'rxjs';
6
7
  import slowDown from 'express-slow-down';
7
8
  import { RedisStore } from 'rate-limit-redis';
8
9
  import { Redis } from 'ioredis';
@@ -17,87 +18,71 @@ class RateLimitService extends ApplicationService {
17
18
  */
18
19
  constructor(app) {
19
20
  super(app);
20
- app.serviceRouter.subscribe((serviceRouter) => {
21
- if (serviceRouter == null) {
21
+
22
+ // get proxy address forwarding option
23
+ const proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');
24
+ this.proxyAddressForwarding = typeof proxyAddressForwarding !== 'boolean' ? false : proxyAddressForwarding;
25
+
26
+ /**
27
+ * @type {BehaviorSubject<{ target: RateLimitService }>}
28
+ */
29
+ this.loaded = new BehaviorSubject(null);
30
+
31
+ const serviceContainer = this.getServiceContainer();
32
+ if (serviceContainer == null) {
33
+ TraceUtils.warn(`${this.getServiceName()} is being started but the parent router seems to be unavailable.`);
34
+ return;
35
+ }
36
+ serviceContainer.subscribe((router) => {
37
+ if (router == null) {
22
38
  return;
23
39
  }
24
40
  try {
25
- const addRouter = express.Router();
26
- let serviceConfiguration = app.getConfiguration().getSourceAt('settings/universis/janitor/rateLimit') || {
27
- profiles: [],
28
- paths: []
29
- };
30
- if (serviceConfiguration.extends) {
31
- // get additional configuration
32
- const configurationPath = app.getConfiguration().getConfigurationPath();
33
- const extendsPath = path.resolve(configurationPath, serviceConfiguration.extends);
34
- TraceUtils.log(`@universis/janitor#RateLimitService will try to extend service configuration from ${extendsPath}`);
35
- serviceConfiguration = require(extendsPath);
36
- }
37
- const pathsArray = serviceConfiguration.paths || [];
38
- const profilesArray = serviceConfiguration.profiles || [];
41
+ // set router for further processing
42
+ Object.defineProperty(this, 'router', {
43
+ value: express.Router(),
44
+ writable: false,
45
+ enumerable: false,
46
+ configurable: true
47
+ });
48
+ const serviceConfiguration = this.getServiceConfiguration();
39
49
  // create maps
40
- const paths = new Map(pathsArray);
41
- const profiles = new Map(profilesArray);
50
+ const paths = serviceConfiguration.paths;
42
51
  if (paths.size === 0) {
43
- TraceUtils.warn('@universis/janitor#RateLimitService is being started but the collection of paths is empty.');
44
- }
45
- // get proxy address forwarding option
46
- let proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');
47
- if (typeof proxyAddressForwarding !== 'boolean') {
48
- proxyAddressForwarding = false;
52
+ TraceUtils.warn(`${this.getServiceName()} is being started but the collection of paths is empty.`);
49
53
  }
50
54
  paths.forEach((value, path) => {
51
- let profile;
52
- // get profile
53
- if (value.profile) {
54
- profile = profiles.get(value.profile);
55
- } else {
56
- // or options defined inline
57
- profile = value;
58
- }
59
- if (profile != null) {
60
- const rateLimitOptions = Object.assign({
61
- windowMs: 5 * 60 * 1000, // 5 minutes
62
- limit: 50, // 50 requests
63
- legacyHeaders: true // send headers
64
- }, profile, {
65
- keyGenerator: (req) => {
66
- let remoteAddress;
67
- if (proxyAddressForwarding) {
68
- // get proxy headers or remote address
69
- remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
70
- } else {
71
- // get remote address
72
- remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
73
- }
74
- return `${path}:${remoteAddress}`;
75
- }
55
+ this.set(path, value);
56
+ });
57
+ if (router.stack) {
58
+ router.stack.unshift.apply(router.stack, this.router.stack);
59
+ } else {
60
+ // use router
61
+ router.use(this.router);
62
+ // get router stack (use a workaround for express 4.x)
63
+ const stack = router._router && router._router.stack;
64
+ if (Array.isArray(stack)) {
65
+ // stage #1 find logger middleware (for supporting request logging)
66
+ let index = stack.findIndex((item) => {
67
+ return item.name === 'logger';
76
68
  });
77
- if (typeof rateLimitOptions.store === 'string') {
78
- // load store
79
- const store = rateLimitOptions.store.split('#');
80
- let StoreClass;
81
- if (store.length === 2) {
82
- const storeModule = require(store[0]);
83
- if (Object.prototype.hasOwnProperty.call(storeModule, store[1])) {
84
- StoreClass = storeModule[store[1]];
85
- rateLimitOptions.store = new StoreClass(this, rateLimitOptions);
86
- } else {
87
- throw new Error(`${store} cannot be found or is inaccessible`);
88
- }
89
- } else {
90
- StoreClass = require(store[0]);
91
- // create store
92
- rateLimitOptions.store = new StoreClass(this, rateLimitOptions);
93
- }
69
+ if (index === -1) {
70
+ // stage #2 find expressInit middleware
71
+ index = stack.findIndex((item) => {
72
+ return item.name === 'expressInit';
73
+ });
94
74
  }
95
- addRouter.use(path, rateLimit(rateLimitOptions));
75
+ // if found, move the last middleware to be after expressInit
76
+ if (index > -1) {
77
+ // move the last middleware to be after expressInit
78
+ stack.splice(index + 1, 0, stack.pop());
79
+ }
80
+ } else {
81
+ TraceUtils.warn(`${this.getServiceName()} is being started but the container stack is not available.`);
96
82
  }
97
- });
98
- if (addRouter.stack.length) {
99
- serviceRouter.stack.unshift.apply(serviceRouter.stack, addRouter.stack);
100
83
  }
84
+ // notify that the service is loaded
85
+ this.loaded.next({ target: this });
101
86
  } catch (err) {
102
87
  TraceUtils.error('An error occurred while validating rate limit configuration.');
103
88
  TraceUtils.error(err);
@@ -106,106 +91,218 @@ class RateLimitService extends ApplicationService {
106
91
  });
107
92
  }
108
93
 
94
+ /**
95
+ * Returns the service router that is used to register rate limit middleware.
96
+ * @returns {import('rxjs').BehaviorSubject<import('express').Router | import('express').Application>} The service router.
97
+ */
98
+ getServiceContainer() {
99
+ return this.getApplication() && this.getApplication().serviceRouter;
100
+ }
101
+
102
+ /**
103
+ * Returns the service name.
104
+ * @returns {string} The service name.
105
+ */
106
+ getServiceName() {
107
+ return '@universis/janitor#RateLimitService';
108
+ }
109
+ /**
110
+ * Returns the service configuration.
111
+ * @returns {{extends?: string, profiles?: Array, paths?: Array}} The service configuration.
112
+ */
113
+ getServiceConfiguration() {
114
+ if (this.serviceConfiguration) {
115
+ return this.serviceConfiguration;
116
+ }
117
+ let serviceConfiguration = {
118
+ profiles: [],
119
+ paths: []
120
+ };
121
+ // get service configuration
122
+ const serviceConfigurationSource = this.getApplication().getConfiguration().getSourceAt('settings/universis/janitor/rateLimit');
123
+ if (serviceConfigurationSource) {
124
+ if (typeof serviceConfigurationSource.extends === 'string') {
125
+ // get additional configuration
126
+ const configurationPath = this.getApplication().getConfiguration().getConfigurationPath();
127
+ const extendsPath = path.resolve(configurationPath, serviceConfigurationSource.extends);
128
+ TraceUtils.log(`${this.getServiceName()} will try to extend service configuration using ${extendsPath}`);
129
+ serviceConfiguration = Object.assign({}, {
130
+ profiles: [],
131
+ paths: []
132
+ }, require(extendsPath));
133
+ } else {
134
+ TraceUtils.log(`${this.getServiceName()} will use service configuration from settings/universis/janitor/rateLimit`);
135
+ serviceConfiguration = Object.assign({}, {
136
+ profiles: [],
137
+ paths: []
138
+ }, serviceConfigurationSource);
139
+ }
140
+ }
141
+ const pathsArray = serviceConfiguration.paths || [];
142
+ const profilesArray = serviceConfiguration.profiles || [];
143
+ // create maps
144
+ serviceConfiguration.paths = new Map(pathsArray);
145
+ serviceConfiguration.profiles = new Map(profilesArray);
146
+ // set service configuration
147
+ Object.defineProperty(this, 'serviceConfiguration', {
148
+ value: serviceConfiguration,
149
+ writable: false,
150
+ enumerable: false,
151
+ configurable: true
152
+ });
153
+ return this.serviceConfiguration;
154
+ }
155
+
156
+ /**
157
+ * Sets the rate limit configuration for a specific path.
158
+ * @param {string} path
159
+ * @param {{ profile: string } | import('express-rate-limit').Options} options
160
+ * @returns {RateLimitService} The service instance for chaining.
161
+ */
162
+ set(path, options) {
163
+ let opts;
164
+ // get profile
165
+ if (options.profile) {
166
+ opts = this.serviceConfiguration.profiles.get(options.profile);
167
+ } else {
168
+ // or options defined inline
169
+ opts = options;
170
+ }
171
+ /**
172
+ * @type { import('express-rate-limit').Options }
173
+ */
174
+ const rateLimitOptions = Object.assign({
175
+ windowMs: 5 * 60 * 1000, // 5 minutes
176
+ limit: 50, // 50 requests
177
+ legacyHeaders: true // send headers
178
+ }, opts, {
179
+ keyGenerator: (req) => {
180
+ let remoteAddress;
181
+ if (this.proxyAddressForwarding) {
182
+ // get proxy headers or remote address
183
+ remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
184
+ } else {
185
+ // get remote address
186
+ remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
187
+ }
188
+ return `${path}:${remoteAddress}`;
189
+ }
190
+ });
191
+ if (typeof rateLimitOptions.store === 'undefined') {
192
+ const StoreClass = this.getStoreType();
193
+ if (typeof StoreClass === 'function') {
194
+ rateLimitOptions.store = new StoreClass(this, rateLimitOptions);
195
+ }
196
+ }
197
+ this.router.use(path, rateLimit(rateLimitOptions));
198
+ return this;
199
+ }
200
+
201
+ /**
202
+ * @returns {function} The type of store used for rate limiting.
203
+ */
204
+ getStoreType() {
205
+ const serviceConfiguration = this.getServiceConfiguration();
206
+ if (typeof serviceConfiguration.storeType !== 'string') {
207
+ return;
208
+ }
209
+ let StoreClass;
210
+ const store = serviceConfiguration.storeType.split('#');
211
+ if (store.length === 2) {
212
+ const storeModule = require(store[0]);
213
+ if (Object.prototype.hasOwnProperty.call(storeModule, store[1])) {
214
+ StoreClass = storeModule[store[1]];
215
+ return StoreClass;
216
+ } else {
217
+ throw new Error(`${store} cannot be found or is inaccessible`);
218
+ }
219
+ } else {
220
+ StoreClass = require(store[0]);
221
+ return StoreClass;
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Unsets the rate limit configuration for a specific path.
227
+ * @param {string} path
228
+ * @returns {RateLimitService} The service instance for chaining.
229
+ */
230
+ unset(path) {
231
+ const index = this.router.stack.findIndex((layer) => {
232
+ return layer.route && layer.route.path === path;
233
+ });
234
+ if (index !== -1) {
235
+ this.router.stack.splice(index, 1);
236
+ }
237
+ return this;
238
+ }
239
+
109
240
  }
110
241
 
111
242
  class SpeedLimitService extends ApplicationService {
112
243
  constructor(app) {
113
244
  super(app);
114
245
 
115
- app.serviceRouter.subscribe((serviceRouter) => {
116
- if (serviceRouter == null) {
246
+ // get proxy address forwarding option
247
+ const proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');
248
+ this.proxyAddressForwarding = typeof proxyAddressForwarding !== 'boolean' ? false : proxyAddressForwarding;
249
+
250
+ /**
251
+ * @type {BehaviorSubject<{ target: SpeedLimitService }>}
252
+ */
253
+ this.loaded = new BehaviorSubject(null);
254
+
255
+ const serviceContainer = this.getServiceContainer();
256
+ if (serviceContainer == null) {
257
+ TraceUtils.warn(`${this.getServiceName()} is being started but the parent router seems to be unavailable.`);
258
+ return;
259
+ }
260
+
261
+ serviceContainer.subscribe((router) => {
262
+ if (router == null) {
117
263
  return;
118
264
  }
119
265
  try {
120
- const addRouter = express.Router();
121
- let serviceConfiguration = app.getConfiguration().getSourceAt('settings/universis/janitor/speedLimit') || {
122
- profiles: [],
123
- paths: []
124
- };
125
- if (serviceConfiguration.extends) {
126
- // get additional configuration
127
- const configurationPath = app.getConfiguration().getConfigurationPath();
128
- const extendsPath = path.resolve(configurationPath, serviceConfiguration.extends);
129
- TraceUtils.log(`@universis/janitor#SpeedLimitService will try to extend service configuration from ${extendsPath}`);
130
- serviceConfiguration = require(extendsPath);
131
- }
132
- const pathsArray = serviceConfiguration.paths || [];
133
- const profilesArray = serviceConfiguration.profiles || [];
266
+ // set router for further processing
267
+ Object.defineProperty(this, 'router', {
268
+ value: express.Router(),
269
+ writable: false,
270
+ enumerable: false,
271
+ configurable: true
272
+ });
273
+ const serviceConfiguration = this.getServiceConfiguration();
134
274
  // create maps
135
- const paths = new Map(pathsArray);
136
- const profiles = new Map(profilesArray);
275
+ const paths = serviceConfiguration.paths;
137
276
  if (paths.size === 0) {
138
- TraceUtils.warn('@universis/janitor#SpeedLimitService is being started but the collection of paths is empty.');
139
- }
140
- // get proxy address forwarding option
141
- let proxyAddressForwarding = app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding');
142
- if (typeof proxyAddressForwarding !== 'boolean') {
143
- proxyAddressForwarding = false;
277
+ TraceUtils.warn(`${this.getServiceName()} is being started but the collection of paths is empty.`);
144
278
  }
145
279
  paths.forEach((value, path) => {
146
- let profile;
147
- // get profile
148
- if (value.profile) {
149
- profile = profiles.get(value.profile);
150
- } else {
151
- // or options defined inline
152
- profile = value;
153
- }
154
- if (profile != null) {
155
- const slowDownOptions = Object.assign({
156
- windowMs: 5 * 60 * 1000, // 5 minutes
157
- delayAfter: 20, // 20 requests
158
- delayMs: 500, // 500 ms
159
- maxDelayMs: 10000 // 10 seconds
160
- }, profile, {
161
- keyGenerator: (req) => {
162
- let remoteAddress;
163
- if (proxyAddressForwarding) {
164
- // get proxy headers or remote address
165
- remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
166
- } else {
167
- // get remote address
168
- remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
169
- }
170
- return `${path}:${remoteAddress}`;
171
- }
280
+ this.set(path, value);
281
+ });
282
+ if (router.stack) {
283
+ router.stack.unshift.apply(router.stack, this.router.stack);
284
+ } else {
285
+ // use router
286
+ router.use(this.router);
287
+ // get router stack (use a workaround for express 4.x)
288
+ const stack = router._router && router._router.stack;
289
+ if (Array.isArray(stack)) {
290
+ // stage #1 find logger middleware (for supporting request logging)
291
+ let index = stack.findIndex((item) => {
292
+ return item.name === 'logger';
172
293
  });
173
- if (Array.isArray(slowDownOptions.randomDelayMs)) {
174
- slowDownOptions.delayMs = () => {
175
- const delayMs = Math.floor(Math.random() * (slowDownOptions.randomDelayMs[1] - slowDownOptions.randomDelayMs[0] + 1) + slowDownOptions.randomDelayMs[0]);
176
- return delayMs;
177
- };
178
- }
179
- if (Array.isArray(slowDownOptions.randomMaxDelayMs)) {
180
- slowDownOptions.maxDelayMs = () => {
181
- const maxDelayMs = Math.floor(Math.random() * (slowDownOptions.randomMaxDelayMs[1] - slowDownOptions.randomMaxDelayMs[0] + 1) + slowDownOptions.randomMaxDelayMs[0]);
182
- return maxDelayMs;
183
- };
184
- }
185
- if (typeof slowDownOptions.store === 'string') {
186
- // load store
187
- const store = slowDownOptions.store.split('#');
188
- let StoreClass;
189
- if (store.length === 2) {
190
- const storeModule = require(store[0]);
191
- if (Object.prototype.hasOwnProperty.call(storeModule, store[1])) {
192
- StoreClass = storeModule[store[1]];
193
- slowDownOptions.store = new StoreClass(this, slowDownOptions);
194
- } else {
195
- throw new Error(`${store} cannot be found or is inaccessible`);
196
- }
197
- } else {
198
- StoreClass = require(store[0]);
199
- // create store
200
- slowDownOptions.store = new StoreClass(this, slowDownOptions);
201
- }
294
+ if (index === -1) {
295
+ // stage #2 find expressInit middleware
296
+ index = stack.findIndex((item) => {
297
+ return item.name === 'expressInit';
298
+ });
202
299
  }
203
- addRouter.use(path, slowDown(slowDownOptions));
300
+ } else {
301
+ TraceUtils.warn(`${this.getServiceName()} is being started but the container stack is not available.`);
204
302
  }
205
- });
206
- if (addRouter.stack.length) {
207
- serviceRouter.stack.unshift.apply(serviceRouter.stack, addRouter.stack);
208
303
  }
304
+ // notify that the service is loaded
305
+ this.loaded.next({ target: this });
209
306
  } catch (err) {
210
307
  TraceUtils.error('An error occurred while validating speed limit configuration.');
211
308
  TraceUtils.error(err);
@@ -214,6 +311,163 @@ class SpeedLimitService extends ApplicationService {
214
311
  });
215
312
  }
216
313
 
314
+ /**
315
+ * @returns {function} The type of store used for rate limiting.
316
+ */
317
+ getStoreType() {
318
+ const serviceConfiguration = this.getServiceConfiguration();
319
+ if (typeof serviceConfiguration.storeType !== 'string') {
320
+ return;
321
+ }
322
+ let StoreClass;
323
+ const store = serviceConfiguration.storeType.split('#');
324
+ if (store.length === 2) {
325
+ const storeModule = require(store[0]);
326
+ if (Object.prototype.hasOwnProperty.call(storeModule, store[1])) {
327
+ StoreClass = storeModule[store[1]];
328
+ return StoreClass;
329
+ } else {
330
+ throw new Error(`${store} cannot be found or is inaccessible`);
331
+ }
332
+ } else {
333
+ StoreClass = require(store[0]);
334
+ return StoreClass;
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Returns the service name.
340
+ * @returns {string} The service name.
341
+ */
342
+ getServiceName() {
343
+ return '@universis/janitor#SpeedLimitService';
344
+ }
345
+
346
+ /**
347
+ * Returns the service router that is used to register speed limit middleware.
348
+ * @returns {import('express').Router | import('express').Application} The service router.
349
+ */
350
+ getServiceContainer() {
351
+ return this.getApplication() && this.getApplication().serviceRouter;
352
+ }
353
+
354
+ /**
355
+ * Sets the speed limit configuration for a specific path.
356
+ * @param {string} path
357
+ * @param {{ profile: string } | import('express-slow-down').Options} options
358
+ * @returns {SpeedLimitService} The service instance for chaining.
359
+ */
360
+ set(path, options) {
361
+ let opts;
362
+ // get profile
363
+ if (options.profile) {
364
+ opts = this.serviceConfiguration.profiles.get(options.profile);
365
+ } else {
366
+ // or options defined inline
367
+ opts = options;
368
+ }
369
+ const slowDownOptions = Object.assign({
370
+ windowMs: 5 * 60 * 1000, // 5 minutes
371
+ delayAfter: 20, // 20 requests
372
+ delayMs: 500, // 500 ms
373
+ maxDelayMs: 10000 // 10 seconds
374
+ }, opts, {
375
+ keyGenerator: (req) => {
376
+ let remoteAddress;
377
+ if (this.proxyAddressForwarding) {
378
+ // get proxy headers or remote address
379
+ remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
380
+ } else {
381
+ // get remote address
382
+ remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
383
+ }
384
+ return `${path}:${remoteAddress}`;
385
+ }
386
+ });
387
+ if (Array.isArray(slowDownOptions.randomDelayMs)) {
388
+ slowDownOptions.delayMs = () => {
389
+ const delayMs = Math.floor(Math.random() * (slowDownOptions.randomDelayMs[1] - slowDownOptions.randomDelayMs[0] + 1) + slowDownOptions.randomDelayMs[0]);
390
+ return delayMs;
391
+ };
392
+ }
393
+ if (Array.isArray(slowDownOptions.randomMaxDelayMs)) {
394
+ slowDownOptions.maxDelayMs = () => {
395
+ const maxDelayMs = Math.floor(Math.random() * (slowDownOptions.randomMaxDelayMs[1] - slowDownOptions.randomMaxDelayMs[0] + 1) + slowDownOptions.randomMaxDelayMs[0]);
396
+ return maxDelayMs;
397
+ };
398
+ }
399
+ if (typeof slowDownOptions.store === 'undefined') {
400
+ const StoreClass = this.getStoreType();
401
+ if (typeof StoreClass === 'function') {
402
+ slowDownOptions.store = new StoreClass(this, slowDownOptions);
403
+ }
404
+ }
405
+ this.router.use(path, slowDown(slowDownOptions));
406
+ return this;
407
+ }
408
+
409
+
410
+ /**
411
+ * Unsets the speed limit configuration for a specific path.
412
+ * @param {string} path
413
+ * @return {SpeedLimitService} The service instance for chaining.
414
+ */
415
+ unset(path) {
416
+ const index = this.router.stack.findIndex((layer) => {
417
+ return layer.route && layer.route.path === path;
418
+ });
419
+ if (index !== -1) {
420
+ this.router.stack.splice(index, 1);
421
+ }
422
+ return this;
423
+ }
424
+
425
+ /**
426
+ *
427
+ * @returns {{extends?: string, profiles?: Array, paths?: Array}} The service configuration.
428
+ */
429
+ getServiceConfiguration() {
430
+ if (this.serviceConfiguration) {
431
+ return this.serviceConfiguration;
432
+ }
433
+ let serviceConfiguration = {
434
+ profiles: [],
435
+ paths: []
436
+ };
437
+ // get service configuration
438
+ const serviceConfigurationSource = this.getApplication().getConfiguration().getSourceAt('settings/universis/janitor/speedLimit');
439
+ if (serviceConfigurationSource) {
440
+ if (typeof serviceConfigurationSource.extends === 'string') {
441
+ // get additional configuration
442
+ const configurationPath = this.getApplication().getConfiguration().getConfigurationPath();
443
+ const extendsPath = path.resolve(configurationPath, serviceConfigurationSource.extends);
444
+ TraceUtils.log(`${this.getServiceName()} will try to extend service configuration using ${extendsPath}`);
445
+ serviceConfiguration = Object.assign({}, {
446
+ profiles: [],
447
+ paths: []
448
+ }, require(extendsPath));
449
+ } else {
450
+ TraceUtils.log(`${this.getServiceName()} will use service configuration from settings/universis/janitor/speedLimit`);
451
+ serviceConfiguration = Object.assign({}, {
452
+ profiles: [],
453
+ paths: []
454
+ }, serviceConfigurationSource);
455
+ }
456
+ }
457
+ const profilesArray = serviceConfiguration.profiles || [];
458
+ serviceConfiguration.profiles = new Map(profilesArray);
459
+ const pathsArray = serviceConfiguration.paths || [];
460
+ serviceConfiguration.paths = new Map(pathsArray);
461
+
462
+ Object.defineProperty(this, 'serviceConfiguration', {
463
+ value: serviceConfiguration,
464
+ writable: false,
465
+ enumerable: false,
466
+ configurable: true
467
+ });
468
+ return this.serviceConfiguration;
469
+ }
470
+
217
471
  }
218
472
 
219
473
  function _defineProperty(e, r, t) {
@@ -892,5 +1146,41 @@ class RemoteAddressValidator extends ApplicationService {
892
1146
 
893
1147
  }
894
1148
 
895
- export { DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpRemoteAddrForbiddenError, OAuth2ClientService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
1149
+ class AppRateLimitService extends RateLimitService {
1150
+ /**
1151
+ *
1152
+ * @param {import('@themost/common').ApplicationBase} app
1153
+ */
1154
+ constructor(app) {
1155
+ super(app);
1156
+ }
1157
+
1158
+ getServiceName() {
1159
+ return '@universis/janitor#AppRateLimitService';
1160
+ }
1161
+
1162
+ getServiceContainer() {
1163
+ return this.getApplication() && this.getApplication().container;
1164
+ }
1165
+ }
1166
+
1167
+ class AppSpeedLimitService extends SpeedLimitService {
1168
+ /**
1169
+ *
1170
+ * @param {import('@themost/common').ApplicationBase} app
1171
+ */
1172
+ constructor(app) {
1173
+ super(app);
1174
+ }
1175
+
1176
+ getServiceName() {
1177
+ return '@universis/janitor#AppSpeedLimitService';
1178
+ }
1179
+
1180
+ getServiceContainer() {
1181
+ return this.getApplication() && this.getApplication().container;
1182
+ }
1183
+ }
1184
+
1185
+ export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpRemoteAddrForbiddenError, OAuth2ClientService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
896
1186
  //# sourceMappingURL=index.esm.js.map