mock-config-server 3.2.0 → 3.3.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.
Files changed (47) hide show
  1. package/README.md +153 -3
  2. package/dist/bin/validateMockServerConfig/helpers/isDescriptorValueValid/isDescriptorValueValid.d.ts +2 -1
  3. package/dist/bin/validateMockServerConfig/helpers/isDescriptorValueValid/isDescriptorValueValid.js +30 -7
  4. package/dist/bin/validateMockServerConfig/validateGraphqlConfig/validateGraphqlConfig.js +9 -3
  5. package/dist/bin/validateMockServerConfig/validateGraphqlConfig/validateRoutes/validateRoutes.js +67 -18
  6. package/dist/bin/validateMockServerConfig/validateQueue/validateQueue.d.ts +1 -0
  7. package/dist/bin/validateMockServerConfig/validateQueue/validateQueue.js +29 -0
  8. package/dist/bin/validateMockServerConfig/validateRestConfig/validateRoutes/validateRoutes.js +67 -18
  9. package/dist/bin/validateMockServerConfig/validateSettings/validateSettings.d.ts +1 -0
  10. package/dist/bin/validateMockServerConfig/validateSettings/validateSettings.js +34 -0
  11. package/dist/src/core/database/createDatabaseRoutes/helpers/createNestedDatabaseRoutes/createNestedDatabaseRoutes.js +45 -2
  12. package/dist/src/core/database/createDatabaseRoutes/helpers/filter/filter.d.ts +2 -1
  13. package/dist/src/core/database/createDatabaseRoutes/helpers/pagination/pagination.d.ts +13 -0
  14. package/dist/src/core/database/createDatabaseRoutes/helpers/pagination/pagination.js +36 -0
  15. package/dist/src/core/database/createDatabaseRoutes/helpers/sort/sort.d.ts +2 -0
  16. package/dist/src/core/database/createDatabaseRoutes/helpers/sort/sort.js +42 -0
  17. package/dist/src/core/graphql/createGraphQLRoutes/createGraphQLRoutes.d.ts +7 -1
  18. package/dist/src/core/graphql/createGraphQLRoutes/createGraphQLRoutes.js +65 -24
  19. package/dist/src/core/middlewares/notFoundMiddleware/notFoundMiddleware.js +1 -3
  20. package/dist/src/core/middlewares/requestInterceptorMiddleware/requestInterceptorMiddleware.d.ts +7 -1
  21. package/dist/src/core/middlewares/requestInterceptorMiddleware/requestInterceptorMiddleware.js +6 -2
  22. package/dist/src/core/rest/createRestRoutes/createRestRoutes.d.ts +7 -1
  23. package/dist/src/core/rest/createRestRoutes/createRestRoutes.js +55 -12
  24. package/dist/src/server/createDatabaseMockServer/createDatabaseMockServer.js +4 -1
  25. package/dist/src/server/createGraphQLMockServer/createGraphQLMockServer.js +11 -4
  26. package/dist/src/server/createMockServer/createMockServer.js +28 -9
  27. package/dist/src/server/createRestMockServer/createRestMockServer.js +11 -4
  28. package/dist/src/server/index.d.ts +3 -3
  29. package/dist/src/server/index.js +23 -23
  30. package/dist/src/static/views/components/header/index.js +1 -1
  31. package/dist/src/static/views/features/scheme/index.js +31 -31
  32. package/dist/src/static/views/features/tab/index.js +12 -12
  33. package/dist/src/utils/helpers/entities/isEntityDescriptor/isEntityDescriptor.d.ts +2 -1
  34. package/dist/src/utils/helpers/graphql/getGraphQLInput/getGraphQLInput.d.ts +7 -2
  35. package/dist/src/utils/helpers/graphql/getGraphQLInput/getGraphQLInput.js +6 -4
  36. package/dist/src/utils/helpers/graphql/parseQuery/parseQuery.d.ts +1 -1
  37. package/dist/src/utils/helpers/graphql/parseQuery/parseQuery.js +1 -1
  38. package/dist/src/utils/helpers/interceptors/callResponseInterceptors/callResponseInterceptors.js +19 -10
  39. package/dist/src/utils/types/graphql.d.ts +60 -51
  40. package/dist/src/utils/types/index.d.ts +1 -0
  41. package/dist/src/utils/types/index.js +11 -0
  42. package/dist/src/utils/types/interceptors.d.ts +1 -1
  43. package/dist/src/utils/types/rest.d.ts +47 -40
  44. package/dist/src/utils/types/utils.d.ts +8 -0
  45. package/dist/src/utils/types/utils.js +1 -0
  46. package/dist/src/utils/types/values.d.ts +0 -1
  47. package/package.json +1 -1
package/README.md CHANGED
@@ -73,7 +73,7 @@ $ npx mock-config-server
73
73
  - `baseUrl?` {string} part of the url that will be substituted at the beginning of graphql request url (default: `'/'`)
74
74
  - `configs` {Array<GraphQLRequestConfig>} configs for mock requests, [read](#configs)
75
75
  - `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors)
76
- - `database?` Database config for mock requests [read](#Database)
76
+ - `database?` Database config for mock requests [read](#database)
77
77
  - `data` {Object | string} initial data for database
78
78
  - `routes?` {Object | string} map of custom routes for database
79
79
  - `staticPath?` {StaticPath} entity for working with static files, [read](#static-path)
@@ -99,13 +99,16 @@ Configs are the fundamental part of the mock server. These configs are easy to f
99
99
  ##### GraphQL request config
100
100
 
101
101
  - `operationType` {query | mutation} graphql operation type
102
- - `operationName` {string} graphql operation name
102
+ - `operationName?` {string | RegExp} graphql operation name
103
+ - `query?`: {string} graphql query as string
103
104
  - `routes` {GraphQLRouteConfig[]} request routes
104
105
  - `data` {any} mock data of request
105
106
  - `entities?` Object<headers | cookies | query | variables> object that helps in data retrieval
106
107
  - `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors)
107
108
  - `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors)
108
109
 
110
+ > Every graphql config should contain `operationName` or `query` or both of them
111
+
109
112
  ##### Rest example
110
113
 
111
114
  ```javascript
@@ -270,6 +273,35 @@ const mockServerConfig = {
270
273
  module.exports = mockServerConfig;
271
274
  ```
272
275
 
276
+ Also you can use array as value for REST body and GraphQL variables entities: in this case mock-config-server will iterate
277
+ over array until `checkMode=equals` finds a match or return 404
278
+
279
+ ```javascript
280
+ /** @type {import('mock-config-server').MockServerConfig} */
281
+ const mockServerConfig = {
282
+ rest: {
283
+ baseUrl: '/api',
284
+ configs: [
285
+ {
286
+ path: '/user',
287
+ method: 'post',
288
+ routes: [
289
+ {
290
+ entities: {
291
+ // if body equals to { key1: 'value1' } or ['value1'] then mock-config-server return data
292
+ body: [{ key1: 'value1' }, ['value1']]
293
+ },
294
+ data: 'Some user data'
295
+ }
296
+ ]
297
+ }
298
+ ]
299
+ }
300
+ };
301
+
302
+ module.exports = mockServerConfig;
303
+ ```
304
+
273
305
  `function checkMode` is the most powerful way to describe your `entities` logic, but in most cases you will be fine using other `checkModes`.
274
306
 
275
307
  `Function value` has the following signature `(actualValue, checkFunction) => boolean`.
@@ -381,6 +413,66 @@ const mockServerConfig = {
381
413
  module.exports = mockServerConfig;
382
414
  ```
383
415
 
416
+ #### Polling
417
+
418
+ Routes support polling for data. To add polling for data, you must specify the `polling setting` and change `data` property to `queue`.
419
+
420
+ > After receiving the last value from polling, the queue is reset and the next request will return the first value from the queue.
421
+
422
+ ```javascript
423
+ /** @type {import('mock-config-server').MockServerConfig} */
424
+ const mockServerConfig = {
425
+ rest: {
426
+ baseUrl: '/api',
427
+ configs: [
428
+ {
429
+ path: '/user',
430
+ method: 'get',
431
+ routes: [
432
+ {
433
+ settings: { polling: true },
434
+ queue: [
435
+ { data: { emoji: '🦁', name: 'Nursultan' } },
436
+ { data: { emoji: '☄', name: 'Dmitriy' } }
437
+ ]
438
+ }
439
+ ]
440
+ }
441
+ ]
442
+ }
443
+ };
444
+
445
+ export default mockServerConfig;
446
+ ```
447
+
448
+ Using the additional `time` properties in milliseconds, you can specify how much time certain data should be returned
449
+
450
+ ```javascript
451
+ /** @type {import('mock-config-server').MockServerConfig} */
452
+ const mockServerConfig = {
453
+ rest: {
454
+ baseUrl: '/api',
455
+ configs: [
456
+ {
457
+ path: '/user',
458
+ method: 'get',
459
+ routes: [
460
+ {
461
+ settings: { polling: true },
462
+ queue: [
463
+ { time: 5000, data: { emoji: '🦁', name: 'Nursultan' } },
464
+ { data: { emoji: '☄', name: 'Dmitriy' } }
465
+ ]
466
+ }
467
+ ]
468
+ }
469
+ ]
470
+ }
471
+ };
472
+
473
+ export default mockServerConfig;
474
+ ```
475
+
384
476
  #### Static Path
385
477
 
386
478
  Entity for connecting statics to the server, like HTML, JSON, PNG, etc.
@@ -547,6 +639,64 @@ GET /users?id=1&id=2
547
639
  GET /users?author.name=siberiacancode
548
640
  ```
549
641
 
642
+ ### Pagination
643
+
644
+ > Use \_page and optionally \_limit to paginate returned data.
645
+
646
+ ```
647
+ GET /users?_page=1
648
+ GET /users?_page=1&_limit=5
649
+ ```
650
+
651
+ > **\_limit** is 10 by default
652
+
653
+ The returned data has the format:
654
+
655
+ ```
656
+ {
657
+ _link: Link,
658
+ results: Data[]
659
+ }
660
+ ```
661
+
662
+ In the **Link** header you'll get **count**, **pages**, **next** and **prev** links.
663
+
664
+ #### Link
665
+
666
+ - `count` {number} total count of elements
667
+ - `pages` {number} count of pages
668
+ - `next` {string | null} query string for next link
669
+ - `prev` {string | null} query string for prev link
670
+
671
+ ### Sort
672
+
673
+ > Use \_sort and \_order, use . to access deep properties
674
+
675
+ ```
676
+ GET /users?_sort=name
677
+ GET /users/1/transfers?_sort=id&_order=asc
678
+ GET /users?_sort=address.city&_order=desc
679
+ ```
680
+
681
+ > **\_order** is 'asc' by default
682
+
683
+ For multiple fields:
684
+
685
+ ```
686
+ GET /users?_sort=id&_order=desc&_sort=name&_order=asc
687
+ ```
688
+
689
+ ### Slice
690
+
691
+ > X-Total-Count header is included in the response
692
+
693
+ ```
694
+ GET /users?_begin=20
695
+ GET /users?_begin=20&_end=30
696
+ ```
697
+
698
+ Works exactly as [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice), \_begin and \_end are optional
699
+
550
700
  ### File example
551
701
 
552
702
  ```javascript
@@ -601,7 +751,7 @@ Examples:
601
751
  <br />
602
752
  <sub style="font-size:13px"><b>👹 MiaInturi</b></sub>
603
753
  </a>
604
- </td>
754
+ </td>
605
755
  <td align="center" style="word-wrap: break-word; width: 100.0; height: 100.0">
606
756
  <a href="https://github.com/RiceWithMeat">
607
757
  <img src="https://avatars.githubusercontent.com/u/47690223?v=4"
@@ -1 +1,2 @@
1
- export declare const isDescriptorValueValid: (checkMode: unknown, value: unknown, entityName?: unknown) => boolean;
1
+ import type { CheckMode } from '../../../../src/utils/types';
2
+ export declare const isDescriptorValueValid: (checkMode: CheckMode, value: unknown) => boolean | undefined;
@@ -5,16 +5,39 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.isDescriptorValueValid = void 0;
7
7
  var _constants = require("../../../../src/utils/constants");
8
- const isDescriptorValueValid = (checkMode, value, entityName) => {
9
- if (_constants.CHECK_ACTUAL_VALUE_CHECK_MODES.includes(checkMode)) return typeof value === 'undefined';
10
- if (_constants.COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES.includes(checkMode)) {
11
- if (entityName === 'body' || entityName === 'variables') {
12
- return typeof value === 'object' && value !== null && typeof value !== 'function' && !(value instanceof RegExp);
8
+ var _helpers = require("../../../../src/utils/helpers");
9
+ // important:
10
+ // should validate all properties over nesting
11
+ const isObjectOrArrayValid = value => {
12
+ if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string' || value === null) {
13
+ return true;
14
+ }
15
+ if (Array.isArray(value)) {
16
+ return value.every(isObjectOrArrayValid);
17
+ }
18
+ if ((0, _helpers.isPlainObject)(value)) {
19
+ for (const key in value) {
20
+ if (!isObjectOrArrayValid(value[key])) {
21
+ return false;
22
+ }
13
23
  }
24
+ return true;
25
+ }
26
+ return false;
27
+ };
28
+ const isDescriptorValueValid = (checkMode, value) => {
29
+ if (_constants.CHECK_ACTUAL_VALUE_CHECK_MODES.includes(checkMode)) {
30
+ return typeof value === 'undefined';
31
+ }
32
+ if (_constants.COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES.includes(checkMode)) {
33
+ const isValueObjectOrArray = (0, _helpers.isPlainObject)(value) || Array.isArray(value);
34
+ if (isValueObjectOrArray) return isObjectOrArrayValid(value);
35
+ return typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string' || value === null;
36
+ }
37
+ if (_constants.COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES.includes(checkMode)) {
14
38
  return typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string';
15
39
  }
16
- if (checkMode === 'function') return typeof value === 'function';
40
+ if (checkMode === 'function') return typeof value === 'function' && value.length <= 2;
17
41
  if (checkMode === 'regExp') return value instanceof RegExp;
18
- throw new Error('Invalid checkMode');
19
42
  };
20
43
  exports.isDescriptorValueValid = isDescriptorValueValid;
@@ -14,15 +14,21 @@ const validateConfigs = configs => {
14
14
  configs.forEach((config, index) => {
15
15
  const {
16
16
  operationType,
17
- operationName
17
+ operationName,
18
+ query
18
19
  } = config;
20
+ if (typeof operationName === 'undefined' && typeof query === 'undefined') {
21
+ throw new Error(`configs[${index}]`);
22
+ }
19
23
  if (operationType !== 'query' && operationType !== 'mutation') {
20
24
  throw new Error(`configs[${index}].operationType`);
21
25
  }
22
- const isOperationNameStringOrRegExp = typeof operationName === 'string' || operationName instanceof RegExp;
23
- if (!isOperationNameStringOrRegExp) {
26
+ if (typeof operationName !== 'undefined' && typeof operationName !== 'string' && !(operationName instanceof RegExp)) {
24
27
  throw new Error(`configs[${index}].operationName`);
25
28
  }
29
+ if (typeof query !== 'undefined' && typeof query !== 'string') {
30
+ throw new Error(`configs[${index}].query`);
31
+ }
26
32
  try {
27
33
  (0, _validateRoutes.validateRoutes)(config.routes, operationType);
28
34
  (0, _validateInterceptors.validateInterceptors)(config.interceptors);
@@ -7,30 +7,44 @@ exports.validateRoutes = void 0;
7
7
  var _helpers = require("../../../../src/utils/helpers");
8
8
  var _helpers2 = require("../../helpers");
9
9
  var _validateInterceptors = require("../../validateInterceptors/validateInterceptors");
10
+ var _validateQueue = require("../../validateQueue/validateQueue");
11
+ var _validateSettings = require("../../validateSettings/validateSettings");
10
12
  const ALLOWED_ENTITIES_BY_OPERATION_TYPE = {
11
13
  query: ['headers', 'cookies', 'query', 'variables'],
12
14
  mutation: ['headers', 'cookies', 'query', 'variables']
13
15
  };
14
16
  const validateEntity = (entity, entityName) => {
15
- const {
16
- checkMode: topLevelCheckMode,
17
- value: topLevelValue
18
- } = (0, _helpers.convertToEntityDescriptor)(entity);
19
17
  const isVariables = entityName === 'variables';
20
- const isTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity);
21
- if (isTopLevelDescriptor && isVariables) {
22
- if (!(0, _helpers2.isCheckModeValid)(topLevelCheckMode, 'variables')) {
18
+ const isEntityTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity);
19
+ if (isEntityTopLevelDescriptor) {
20
+ if (!isVariables) {
21
+ throw new Error(entityName);
22
+ }
23
+ if (!(0, _helpers2.isCheckModeValid)(entity.checkMode, 'variables')) {
23
24
  throw new Error('variables.checkMode');
24
25
  }
25
- if (!(0, _helpers2.isDescriptorValueValid)(topLevelCheckMode, topLevelValue, 'variables')) {
26
- const errorMessage = 'variables.value';
27
- throw new Error(errorMessage);
26
+ const isDescriptorValueObjectOrArray = (0, _helpers.isPlainObject)(entity.value) || Array.isArray(entity.value);
27
+ if (!isDescriptorValueObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(entity.checkMode, entity.value)) {
28
+ throw new Error('variables.value');
29
+ }
30
+ return;
31
+ }
32
+ const isEntityArray = Array.isArray(entity);
33
+ if (isEntityArray) {
34
+ if (!isVariables) {
35
+ throw new Error(entityName);
28
36
  }
37
+ entity.forEach((entityElement, index) => {
38
+ const isEntityElementObjectOrArray = (0, _helpers.isPlainObject)(entityElement) || Array.isArray(entityElement);
39
+ if (!isEntityElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)('equals', entityElement)) {
40
+ throw new Error(`${entityName}[${index}]`);
41
+ }
42
+ });
43
+ return;
29
44
  }
30
- const isEntityObject = (0, _helpers.isPlainObject)(entity) && !(entity instanceof RegExp);
31
- const isEntityArray = Array.isArray(entity) && isVariables;
32
- if (isEntityObject || isEntityArray) {
33
- Object.entries(topLevelValue).forEach(([key, valueOrDescriptor]) => {
45
+ const isEntityObject = (0, _helpers.isPlainObject)(entity);
46
+ if (isEntityObject) {
47
+ Object.entries(entity).forEach(([key, valueOrDescriptor]) => {
34
48
  const {
35
49
  checkMode,
36
50
  value
@@ -41,15 +55,25 @@ const validateEntity = (entity, entityName) => {
41
55
  const isDescriptor = (0, _helpers.isEntityDescriptor)(valueOrDescriptor);
42
56
  const errorMessage = `${entityName}.${key}${isDescriptor ? '.value' : ''}`;
43
57
  const isValueArray = Array.isArray(value);
44
- if (isValueArray && !isVariables) {
58
+ if (isValueArray) {
45
59
  value.forEach((element, index) => {
46
- if (!(0, _helpers2.isDescriptorValueValid)(checkMode, element)) {
60
+ if (isVariables) {
61
+ if ((0, _helpers2.isDescriptorValueValid)(checkMode, element)) return;
62
+ throw new Error(`${errorMessage}[${index}]`);
63
+ }
64
+ const isElementObjectOrArray = (0, _helpers.isPlainObject)(element) || Array.isArray(element);
65
+ if (isElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(checkMode, element)) {
47
66
  throw new Error(`${errorMessage}[${index}]`);
48
67
  }
49
68
  });
50
69
  return;
51
70
  }
52
- if (!(0, _helpers2.isDescriptorValueValid)(checkMode, value)) {
71
+ if (isVariables) {
72
+ if ((0, _helpers2.isDescriptorValueValid)(checkMode, value)) return;
73
+ throw new Error(errorMessage);
74
+ }
75
+ const isValueObject = (0, _helpers.isPlainObject)(value);
76
+ if (isValueObject || !(0, _helpers2.isDescriptorValueValid)(checkMode, value)) {
53
77
  throw new Error(errorMessage);
54
78
  }
55
79
  });
@@ -84,10 +108,35 @@ const validateRoutes = (routes, operationType) => {
84
108
  const isRouteObject = (0, _helpers.isPlainObject)(route);
85
109
  if (isRouteObject) {
86
110
  const isRouteHasDataProperty = ('data' in route);
87
- if (!isRouteHasDataProperty) {
111
+ const isRouteHasQueueProperty = ('queue' in route);
112
+ if (!isRouteHasDataProperty && !isRouteHasQueueProperty) {
113
+ throw new Error(`routes[${index}]`);
114
+ }
115
+ if (isRouteHasDataProperty && isRouteHasQueueProperty) {
88
116
  throw new Error(`routes[${index}]`);
89
117
  }
118
+ const {
119
+ settings
120
+ } = route;
121
+ const isRouteSettingsObject = (0, _helpers.isPlainObject)(settings);
122
+ if (isRouteHasQueueProperty) {
123
+ try {
124
+ (0, _validateQueue.validateQueue)(route.queue);
125
+ if (!isRouteSettingsObject) {
126
+ throw new Error('settings');
127
+ }
128
+ if (!(isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling)) {
129
+ throw new Error('settings.polling');
130
+ }
131
+ } catch (error) {
132
+ throw new Error(`routes[${index}].${error.message}`);
133
+ }
134
+ }
135
+ if (isRouteHasDataProperty && isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling) {
136
+ throw new Error(`routes[${index}].settings.polling`);
137
+ }
90
138
  try {
139
+ (0, _validateSettings.validateSettings)(route.settings);
91
140
  validateEntities(route.entities, operationType);
92
141
  (0, _validateInterceptors.validateInterceptors)(route.interceptors);
93
142
  } catch (error) {
@@ -0,0 +1 @@
1
+ export declare const validateQueue: (queue: unknown) => void;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.validateQueue = void 0;
7
+ var _helpers = require("../../../src/utils/helpers");
8
+ const validateQueue = queue => {
9
+ const isQueueArray = Array.isArray(queue);
10
+ if (!isQueueArray) {
11
+ throw new Error('queue');
12
+ }
13
+ queue.forEach((queueElement, index) => {
14
+ const isQueueElementObject = (0, _helpers.isPlainObject)(queueElement);
15
+ if (isQueueElementObject) {
16
+ const isQueueElementDataProperty = ('data' in queueElement);
17
+ if (!isQueueElementDataProperty) {
18
+ throw new Error(`queue[${index}].data`);
19
+ }
20
+ const isQueueElementTimeProperty = ('time' in queueElement);
21
+ if (isQueueElementTimeProperty && typeof queueElement.time !== 'number') {
22
+ throw new Error(`queue[${index}].time`);
23
+ }
24
+ return;
25
+ }
26
+ throw new Error(`queue[${index}]`);
27
+ });
28
+ };
29
+ exports.validateQueue = validateQueue;
@@ -7,6 +7,8 @@ exports.validateRoutes = void 0;
7
7
  var _helpers = require("../../../../src/utils/helpers");
8
8
  var _helpers2 = require("../../helpers");
9
9
  var _validateInterceptors = require("../../validateInterceptors/validateInterceptors");
10
+ var _validateQueue = require("../../validateQueue/validateQueue");
11
+ var _validateSettings = require("../../validateSettings/validateSettings");
10
12
  const ALLOWED_ENTITIES_BY_METHOD = {
11
13
  get: ['headers', 'cookies', 'query', 'params'],
12
14
  delete: ['headers', 'cookies', 'query', 'params'],
@@ -16,25 +18,37 @@ const ALLOWED_ENTITIES_BY_METHOD = {
16
18
  options: ['headers', 'cookies', 'query', 'params']
17
19
  };
18
20
  const validateEntity = (entity, entityName) => {
19
- const {
20
- checkMode: topLevelCheckMode,
21
- value: topLevelValue
22
- } = (0, _helpers.convertToEntityDescriptor)(entity);
23
21
  const isBody = entityName === 'body';
24
- const isTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity);
25
- if (isTopLevelDescriptor && isBody) {
26
- if (!(0, _helpers2.isCheckModeValid)(topLevelCheckMode, 'body')) {
22
+ const isEntityTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity);
23
+ if (isEntityTopLevelDescriptor) {
24
+ if (!isBody) {
25
+ throw new Error(entityName);
26
+ }
27
+ if (!(0, _helpers2.isCheckModeValid)(entity.checkMode, 'body')) {
27
28
  throw new Error('body.checkMode');
28
29
  }
29
- if (!(0, _helpers2.isDescriptorValueValid)(topLevelCheckMode, topLevelValue, 'body')) {
30
- const errorMessage = 'body.value';
31
- throw new Error(errorMessage);
30
+ const isDescriptorValueObjectOrArray = (0, _helpers.isPlainObject)(entity.value) || Array.isArray(entity.value);
31
+ if (!isDescriptorValueObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(entity.checkMode, entity.value)) {
32
+ throw new Error('body.value');
33
+ }
34
+ return;
35
+ }
36
+ const isEntityArray = Array.isArray(entity);
37
+ if (isEntityArray) {
38
+ if (!isBody) {
39
+ throw new Error(entityName);
32
40
  }
41
+ entity.forEach((entityElement, index) => {
42
+ const isEntityElementObjectOrArray = (0, _helpers.isPlainObject)(entityElement) || Array.isArray(entityElement);
43
+ if (!isEntityElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)('equals', entityElement)) {
44
+ throw new Error(`${entityName}[${index}]`);
45
+ }
46
+ });
47
+ return;
33
48
  }
34
- const isEntityObject = (0, _helpers.isPlainObject)(entity) && !(entity instanceof RegExp);
35
- const isEntityArray = Array.isArray(entity) && isBody;
36
- if (isEntityObject || isEntityArray) {
37
- Object.entries(topLevelValue).forEach(([key, valueOrDescriptor]) => {
49
+ const isEntityObject = (0, _helpers.isPlainObject)(entity);
50
+ if (isEntityObject) {
51
+ Object.entries(entity).forEach(([key, valueOrDescriptor]) => {
38
52
  const {
39
53
  checkMode,
40
54
  value
@@ -45,15 +59,25 @@ const validateEntity = (entity, entityName) => {
45
59
  const isDescriptor = (0, _helpers.isEntityDescriptor)(valueOrDescriptor);
46
60
  const errorMessage = `${entityName}.${key}${isDescriptor ? '.value' : ''}`;
47
61
  const isValueArray = Array.isArray(value);
48
- if (isValueArray && !isBody) {
62
+ if (isValueArray) {
49
63
  value.forEach((element, index) => {
50
- if (!(0, _helpers2.isDescriptorValueValid)(checkMode, element)) {
64
+ if (isBody) {
65
+ if ((0, _helpers2.isDescriptorValueValid)(checkMode, element)) return;
66
+ throw new Error(`${errorMessage}[${index}]`);
67
+ }
68
+ const isElementObjectOrArray = (0, _helpers.isPlainObject)(element) || Array.isArray(element);
69
+ if (isElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(checkMode, element)) {
51
70
  throw new Error(`${errorMessage}[${index}]`);
52
71
  }
53
72
  });
54
73
  return;
55
74
  }
56
- if (!(0, _helpers2.isDescriptorValueValid)(checkMode, value)) {
75
+ if (isBody) {
76
+ if ((0, _helpers2.isDescriptorValueValid)(checkMode, value)) return;
77
+ throw new Error(errorMessage);
78
+ }
79
+ const isValueObject = (0, _helpers.isPlainObject)(value);
80
+ if (isValueObject || !(0, _helpers2.isDescriptorValueValid)(checkMode, value)) {
57
81
  throw new Error(errorMessage);
58
82
  }
59
83
  });
@@ -88,10 +112,35 @@ const validateRoutes = (routes, method) => {
88
112
  const isRouteObject = (0, _helpers.isPlainObject)(route);
89
113
  if (isRouteObject) {
90
114
  const isRouteHasDataProperty = ('data' in route);
91
- if (!isRouteHasDataProperty) {
115
+ const isRouteHasQueueProperty = ('queue' in route);
116
+ if (!isRouteHasDataProperty && !isRouteHasQueueProperty) {
117
+ throw new Error(`routes[${index}]`);
118
+ }
119
+ if (isRouteHasDataProperty && isRouteHasQueueProperty) {
92
120
  throw new Error(`routes[${index}]`);
93
121
  }
122
+ const {
123
+ settings
124
+ } = route;
125
+ const isRouteSettingsObject = (0, _helpers.isPlainObject)(settings);
126
+ if (isRouteHasQueueProperty) {
127
+ try {
128
+ (0, _validateQueue.validateQueue)(route.queue);
129
+ if (!isRouteSettingsObject) {
130
+ throw new Error('settings');
131
+ }
132
+ if (!(isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling)) {
133
+ throw new Error('settings.polling');
134
+ }
135
+ } catch (error) {
136
+ throw new Error(`routes[${index}].${error.message}`);
137
+ }
138
+ }
139
+ if (isRouteHasDataProperty && isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling) {
140
+ throw new Error(`routes[${index}].settings.polling`);
141
+ }
94
142
  try {
143
+ (0, _validateSettings.validateSettings)(route.settings);
95
144
  validateEntities(route.entities, method);
96
145
  (0, _validateInterceptors.validateInterceptors)(route.interceptors);
97
146
  } catch (error) {
@@ -0,0 +1 @@
1
+ export declare const validateSettings: (settings: unknown) => void;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.validateSettings = void 0;
7
+ var _helpers = require("../../../src/utils/helpers");
8
+ const ALLOWED_SETTINGS = ['polling'];
9
+ const validateSetting = (setting, settingName) => {
10
+ if (settingName === 'polling' && typeof setting !== 'boolean') {
11
+ throw new Error('polling');
12
+ }
13
+ };
14
+ const validateSettings = settings => {
15
+ const isSettingsObject = (0, _helpers.isPlainObject)(settings);
16
+ if (isSettingsObject) {
17
+ Object.keys(settings).forEach(settingName => {
18
+ const isSettingAllowed = ALLOWED_SETTINGS.includes(settingName);
19
+ if (!isSettingAllowed) {
20
+ throw new Error(`settings.${settingName}`);
21
+ }
22
+ try {
23
+ validateSetting(settings[settingName], settingName);
24
+ } catch (error) {
25
+ throw new Error(`settings.${error.message}`);
26
+ }
27
+ });
28
+ return;
29
+ }
30
+ if (typeof settings !== 'undefined') {
31
+ throw new Error('settings');
32
+ }
33
+ };
34
+ exports.validateSettings = validateSettings;
@@ -6,16 +6,59 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.createNestedDatabaseRoutes = void 0;
7
7
  var _array = require("../array");
8
8
  var _filter = require("../filter/filter");
9
+ var _pagination = require("../pagination/pagination");
10
+ var _sort2 = require("../sort/sort");
9
11
  const createNestedDatabaseRoutes = (router, database, storage) => {
10
12
  Object.keys(database).forEach(key => {
11
13
  const collectionPath = `/${key}`;
12
14
  const itemPath = `/${key}/:id`;
13
15
  router.route(collectionPath).get((request, response) => {
16
+ var _request$query;
14
17
  let data = storage.read(key);
15
18
  if (request.query && Object.keys(request.query).length) {
16
- data = (0, _filter.filter)(data, request.query);
19
+ const {
20
+ _page,
21
+ _limit,
22
+ _begin,
23
+ _end,
24
+ _sort,
25
+ _order,
26
+ ...filters
27
+ } = request.query;
28
+ data = (0, _filter.filter)(data, filters);
29
+ }
30
+ if ((_request$query = request.query) !== null && _request$query !== void 0 && _request$query._page) {
31
+ data = (0, _pagination.pagination)(data, request.query);
32
+ if (data._link) {
33
+ const links = {};
34
+ const fullUrl = `${request.protocol}://${request.get('host')}${request.originalUrl}`;
35
+ if (data._link.first) {
36
+ links.first = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.first}`);
37
+ }
38
+ if (data._link.prev) {
39
+ links.prev = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.prev}`);
40
+ }
41
+ if (data._link.next) {
42
+ links.next = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.next}`);
43
+ }
44
+ if (data._link.last) {
45
+ links.last = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.last}`);
46
+ }
47
+ data._link = {
48
+ ...data._link,
49
+ ...links
50
+ };
51
+ response.links(links);
52
+ }
53
+ }
54
+ if (request.query && request.query._sort) {
55
+ data = (0, _sort2.sort)(data, request.query);
56
+ }
57
+ if (request.query._begin || request.query._end) {
58
+ var _request$query$_begin;
59
+ data = data.slice((_request$query$_begin = request.query._begin) !== null && _request$query$_begin !== void 0 ? _request$query$_begin : 0, request.query._end);
60
+ response.set('X-Total-Count', data.length);
17
61
  }
18
-
19
62
  // ✅ important:
20
63
  // set 'Cache-Control' header for explicit browsers response revalidate
21
64
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
@@ -1 +1,2 @@
1
- export declare const filter: (array: any[], filters: Record<string, string | string[]>) => any[];
1
+ import type { ParsedUrlQuery } from 'node:querystring';
2
+ export declare const filter: (array: any[], filters: ParsedUrlQuery) => any[];