@webex/webex-core 2.59.2 → 2.59.3-next.1

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 (189) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +79 -79
  3. package/babel.config.js +3 -3
  4. package/dist/config.js +24 -24
  5. package/dist/config.js.map +1 -1
  6. package/dist/credentials-config.js +56 -56
  7. package/dist/credentials-config.js.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/interceptors/auth.js +28 -28
  10. package/dist/interceptors/auth.js.map +1 -1
  11. package/dist/interceptors/default-options.js +24 -24
  12. package/dist/interceptors/default-options.js.map +1 -1
  13. package/dist/interceptors/embargo.js +9 -9
  14. package/dist/interceptors/embargo.js.map +1 -1
  15. package/dist/interceptors/network-timing.js +19 -19
  16. package/dist/interceptors/network-timing.js.map +1 -1
  17. package/dist/interceptors/payload-transformer.js +19 -19
  18. package/dist/interceptors/payload-transformer.js.map +1 -1
  19. package/dist/interceptors/rate-limit.js +40 -40
  20. package/dist/interceptors/rate-limit.js.map +1 -1
  21. package/dist/interceptors/redirect.js +13 -13
  22. package/dist/interceptors/redirect.js.map +1 -1
  23. package/dist/interceptors/request-event.js +23 -23
  24. package/dist/interceptors/request-event.js.map +1 -1
  25. package/dist/interceptors/request-logger.js +13 -13
  26. package/dist/interceptors/request-logger.js.map +1 -1
  27. package/dist/interceptors/request-timing.js +23 -23
  28. package/dist/interceptors/request-timing.js.map +1 -1
  29. package/dist/interceptors/response-logger.js +19 -19
  30. package/dist/interceptors/response-logger.js.map +1 -1
  31. package/dist/interceptors/user-agent.js +29 -29
  32. package/dist/interceptors/user-agent.js.map +1 -1
  33. package/dist/interceptors/webex-tracking-id.js +15 -15
  34. package/dist/interceptors/webex-tracking-id.js.map +1 -1
  35. package/dist/interceptors/webex-user-agent.js +13 -13
  36. package/dist/interceptors/webex-user-agent.js.map +1 -1
  37. package/dist/lib/batcher.js +83 -83
  38. package/dist/lib/batcher.js.map +1 -1
  39. package/dist/lib/credentials/credentials.js +103 -103
  40. package/dist/lib/credentials/credentials.js.map +1 -1
  41. package/dist/lib/credentials/grant-errors.js +17 -17
  42. package/dist/lib/credentials/grant-errors.js.map +1 -1
  43. package/dist/lib/credentials/index.js +2 -2
  44. package/dist/lib/credentials/index.js.map +1 -1
  45. package/dist/lib/credentials/scope.js +11 -11
  46. package/dist/lib/credentials/scope.js.map +1 -1
  47. package/dist/lib/credentials/token-collection.js +2 -2
  48. package/dist/lib/credentials/token-collection.js.map +1 -1
  49. package/dist/lib/credentials/token.js +145 -145
  50. package/dist/lib/credentials/token.js.map +1 -1
  51. package/dist/lib/page.js +49 -49
  52. package/dist/lib/page.js.map +1 -1
  53. package/dist/lib/services/constants.js.map +1 -1
  54. package/dist/lib/services/index.js +2 -2
  55. package/dist/lib/services/index.js.map +1 -1
  56. package/dist/lib/services/interceptors/server-error.js +9 -9
  57. package/dist/lib/services/interceptors/server-error.js.map +1 -1
  58. package/dist/lib/services/interceptors/service.js +24 -24
  59. package/dist/lib/services/interceptors/service.js.map +1 -1
  60. package/dist/lib/services/metrics.js.map +1 -1
  61. package/dist/lib/services/service-catalog.js +104 -104
  62. package/dist/lib/services/service-catalog.js.map +1 -1
  63. package/dist/lib/services/service-fed-ramp.js.map +1 -1
  64. package/dist/lib/services/service-host.js +134 -134
  65. package/dist/lib/services/service-host.js.map +1 -1
  66. package/dist/lib/services/service-registry.js +175 -175
  67. package/dist/lib/services/service-registry.js.map +1 -1
  68. package/dist/lib/services/service-state.js +38 -38
  69. package/dist/lib/services/service-state.js.map +1 -1
  70. package/dist/lib/services/service-url.js +31 -31
  71. package/dist/lib/services/service-url.js.map +1 -1
  72. package/dist/lib/services/services.js +245 -245
  73. package/dist/lib/services/services.js.map +1 -1
  74. package/dist/lib/stateless-webex-plugin.js +28 -28
  75. package/dist/lib/stateless-webex-plugin.js.map +1 -1
  76. package/dist/lib/storage/decorators.js +27 -27
  77. package/dist/lib/storage/decorators.js.map +1 -1
  78. package/dist/lib/storage/errors.js +4 -4
  79. package/dist/lib/storage/errors.js.map +1 -1
  80. package/dist/lib/storage/index.js.map +1 -1
  81. package/dist/lib/storage/make-webex-plugin-store.js +44 -44
  82. package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
  83. package/dist/lib/storage/make-webex-store.js +40 -40
  84. package/dist/lib/storage/make-webex-store.js.map +1 -1
  85. package/dist/lib/storage/memory-store-adapter.js +9 -9
  86. package/dist/lib/storage/memory-store-adapter.js.map +1 -1
  87. package/dist/lib/webex-core-plugin-mixin.js +13 -13
  88. package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
  89. package/dist/lib/webex-http-error.js +9 -9
  90. package/dist/lib/webex-http-error.js.map +1 -1
  91. package/dist/lib/webex-internal-core-plugin-mixin.js +13 -13
  92. package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
  93. package/dist/lib/webex-plugin.js +36 -36
  94. package/dist/lib/webex-plugin.js.map +1 -1
  95. package/dist/plugins/logger.js +9 -9
  96. package/dist/plugins/logger.js.map +1 -1
  97. package/dist/webex-core.js +104 -104
  98. package/dist/webex-core.js.map +1 -1
  99. package/dist/webex-internal-core.js +12 -12
  100. package/dist/webex-internal-core.js.map +1 -1
  101. package/jest.config.js +3 -3
  102. package/package.json +20 -19
  103. package/process +1 -1
  104. package/src/config.js +90 -90
  105. package/src/credentials-config.js +212 -212
  106. package/src/index.js +62 -62
  107. package/src/interceptors/auth.js +186 -186
  108. package/src/interceptors/default-options.js +55 -55
  109. package/src/interceptors/embargo.js +43 -43
  110. package/src/interceptors/network-timing.js +54 -54
  111. package/src/interceptors/payload-transformer.js +55 -55
  112. package/src/interceptors/rate-limit.js +169 -169
  113. package/src/interceptors/redirect.js +106 -106
  114. package/src/interceptors/request-event.js +93 -93
  115. package/src/interceptors/request-logger.js +78 -78
  116. package/src/interceptors/request-timing.js +65 -65
  117. package/src/interceptors/response-logger.js +98 -98
  118. package/src/interceptors/user-agent.js +77 -77
  119. package/src/interceptors/webex-tracking-id.js +73 -73
  120. package/src/interceptors/webex-user-agent.js +79 -79
  121. package/src/lib/batcher.js +307 -307
  122. package/src/lib/credentials/credentials.js +552 -552
  123. package/src/lib/credentials/grant-errors.js +92 -92
  124. package/src/lib/credentials/index.js +16 -16
  125. package/src/lib/credentials/scope.js +34 -34
  126. package/src/lib/credentials/token-collection.js +17 -17
  127. package/src/lib/credentials/token.js +559 -559
  128. package/src/lib/page.js +159 -159
  129. package/src/lib/services/constants.js +9 -9
  130. package/src/lib/services/index.js +26 -26
  131. package/src/lib/services/interceptors/server-error.js +48 -48
  132. package/src/lib/services/interceptors/service.js +101 -101
  133. package/src/lib/services/metrics.js +4 -4
  134. package/src/lib/services/service-catalog.js +435 -435
  135. package/src/lib/services/service-fed-ramp.js +4 -4
  136. package/src/lib/services/service-host.js +267 -267
  137. package/src/lib/services/service-registry.js +465 -465
  138. package/src/lib/services/service-state.js +78 -78
  139. package/src/lib/services/service-url.js +124 -124
  140. package/src/lib/services/services.js +1018 -1018
  141. package/src/lib/stateless-webex-plugin.js +98 -98
  142. package/src/lib/storage/decorators.js +220 -220
  143. package/src/lib/storage/errors.js +15 -15
  144. package/src/lib/storage/index.js +10 -10
  145. package/src/lib/storage/make-webex-plugin-store.js +211 -211
  146. package/src/lib/storage/make-webex-store.js +140 -140
  147. package/src/lib/storage/memory-store-adapter.js +79 -79
  148. package/src/lib/webex-core-plugin-mixin.js +114 -114
  149. package/src/lib/webex-http-error.js +61 -61
  150. package/src/lib/webex-internal-core-plugin-mixin.js +107 -107
  151. package/src/lib/webex-plugin.js +222 -222
  152. package/src/plugins/logger.js +60 -60
  153. package/src/webex-core.js +745 -745
  154. package/src/webex-internal-core.js +46 -46
  155. package/test/integration/spec/credentials/credentials.js +139 -139
  156. package/test/integration/spec/credentials/token.js +102 -102
  157. package/test/integration/spec/services/service-catalog.js +838 -838
  158. package/test/integration/spec/services/services.js +1221 -1221
  159. package/test/integration/spec/webex-core.js +178 -178
  160. package/test/unit/spec/_setup.js +44 -44
  161. package/test/unit/spec/credentials/credentials.js +1017 -1017
  162. package/test/unit/spec/credentials/token.js +441 -441
  163. package/test/unit/spec/interceptors/auth.js +521 -521
  164. package/test/unit/spec/interceptors/default-options.js +84 -84
  165. package/test/unit/spec/interceptors/embargo.js +144 -144
  166. package/test/unit/spec/interceptors/network-timing.js +49 -49
  167. package/test/unit/spec/interceptors/payload-transformer.js +155 -155
  168. package/test/unit/spec/interceptors/rate-limit.js +302 -302
  169. package/test/unit/spec/interceptors/redirect.js +102 -102
  170. package/test/unit/spec/interceptors/request-timing.js +92 -92
  171. package/test/unit/spec/interceptors/user-agent.js +76 -76
  172. package/test/unit/spec/interceptors/webex-tracking-id.js +76 -76
  173. package/test/unit/spec/interceptors/webex-user-agent.js +159 -159
  174. package/test/unit/spec/lib/batcher.js +330 -330
  175. package/test/unit/spec/lib/page.js +148 -148
  176. package/test/unit/spec/lib/webex-plugin.js +48 -48
  177. package/test/unit/spec/services/interceptors/server-error.js +204 -204
  178. package/test/unit/spec/services/interceptors/service.js +188 -188
  179. package/test/unit/spec/services/service-catalog.js +194 -194
  180. package/test/unit/spec/services/service-host.js +260 -260
  181. package/test/unit/spec/services/service-registry.js +747 -747
  182. package/test/unit/spec/services/service-state.js +60 -60
  183. package/test/unit/spec/services/service-url.js +258 -258
  184. package/test/unit/spec/services/services.js +348 -348
  185. package/test/unit/spec/storage/persist.js +50 -50
  186. package/test/unit/spec/storage/storage-adapter.js +12 -12
  187. package/test/unit/spec/storage/wait-for-value.js +81 -81
  188. package/test/unit/spec/webex-core.js +253 -253
  189. package/test/unit/spec/webex-internal-core.js +91 -91
@@ -1,43 +1,43 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {Interceptor} from '@webex/http-core';
6
-
7
- /**
8
- * @class
9
- */
10
- export default class EmbargoInterceptor extends Interceptor {
11
- /**
12
- * @returns {EmbargoInterceptor}
13
- */
14
- static create() {
15
- /* eslint no-invalid-this: [0] */
16
- return new EmbargoInterceptor({webex: this});
17
- }
18
-
19
- /**
20
- * @see Interceptor#onResponseError
21
- * @param {Object} options
22
- * @param {Error} reason
23
- * @returns {Promise}
24
- */
25
- onResponseError(options, reason) {
26
- if (reason.statusCode === 451) {
27
- const {device} = this.webex.internal;
28
- const loggerMessage = [
29
- 'Received `HTTP 451 Unavailable For Legal Reasons`, ',
30
- 'discarding credentials and device registration',
31
- ].join('');
32
-
33
- if (device) {
34
- this.webex.internal.device.clear();
35
- }
36
-
37
- this.webex.credentials.clear();
38
- this.webex.logger.info(loggerMessage);
39
- }
40
-
41
- return Promise.reject(reason);
42
- }
43
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {Interceptor} from '@webex/http-core';
6
+
7
+ /**
8
+ * @class
9
+ */
10
+ export default class EmbargoInterceptor extends Interceptor {
11
+ /**
12
+ * @returns {EmbargoInterceptor}
13
+ */
14
+ static create() {
15
+ /* eslint no-invalid-this: [0] */
16
+ return new EmbargoInterceptor({webex: this});
17
+ }
18
+
19
+ /**
20
+ * @see Interceptor#onResponseError
21
+ * @param {Object} options
22
+ * @param {Error} reason
23
+ * @returns {Promise}
24
+ */
25
+ onResponseError(options, reason) {
26
+ if (reason.statusCode === 451) {
27
+ const {device} = this.webex.internal;
28
+ const loggerMessage = [
29
+ 'Received `HTTP 451 Unavailable For Legal Reasons`, ',
30
+ 'discarding credentials and device registration',
31
+ ].join('');
32
+
33
+ if (device) {
34
+ this.webex.internal.device.clear();
35
+ }
36
+
37
+ this.webex.credentials.clear();
38
+ this.webex.logger.info(loggerMessage);
39
+ }
40
+
41
+ return Promise.reject(reason);
42
+ }
43
+ }
@@ -1,54 +1,54 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {Interceptor} from '@webex/http-core';
6
-
7
- /**
8
- * @class
9
- */
10
- export default class NetworkTimingInterceptor extends Interceptor {
11
- /**
12
- * @param {Object} options
13
- * @returns {NetworkTimingInterceptor}
14
- */
15
- static create(options) {
16
- return new NetworkTimingInterceptor(this, options);
17
- }
18
-
19
- /**
20
- * @see Interceptor#onRequest
21
- * @param {Object} options
22
- * @returns {Object}
23
- */
24
- onRequest(options) {
25
- options.$timings = options.$timings || {};
26
- options.$timings.networkStart = Date.now();
27
-
28
- return options;
29
- }
30
-
31
- /**
32
- * @see Interceptor#onResponse
33
- * @param {Object} options
34
- * @param {HttpResponse} response
35
- * @returns {Object}
36
- */
37
- onResponse(options, response) {
38
- options.$timings.networkEnd = Date.now();
39
-
40
- return response;
41
- }
42
-
43
- /**
44
- * @see Interceptor#onResponseError
45
- * @param {Object} options
46
- * @param {Error} reason
47
- * @returns {Object}
48
- */
49
- onResponseError(options, reason) {
50
- options.$timings.networkEnd = Date.now();
51
-
52
- return Promise.reject(reason);
53
- }
54
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {Interceptor} from '@webex/http-core';
6
+
7
+ /**
8
+ * @class
9
+ */
10
+ export default class NetworkTimingInterceptor extends Interceptor {
11
+ /**
12
+ * @param {Object} options
13
+ * @returns {NetworkTimingInterceptor}
14
+ */
15
+ static create(options) {
16
+ return new NetworkTimingInterceptor(this, options);
17
+ }
18
+
19
+ /**
20
+ * @see Interceptor#onRequest
21
+ * @param {Object} options
22
+ * @returns {Object}
23
+ */
24
+ onRequest(options) {
25
+ options.$timings = options.$timings || {};
26
+ options.$timings.networkStart = Date.now();
27
+
28
+ return options;
29
+ }
30
+
31
+ /**
32
+ * @see Interceptor#onResponse
33
+ * @param {Object} options
34
+ * @param {HttpResponse} response
35
+ * @returns {Object}
36
+ */
37
+ onResponse(options, response) {
38
+ options.$timings.networkEnd = Date.now();
39
+
40
+ return response;
41
+ }
42
+
43
+ /**
44
+ * @see Interceptor#onResponseError
45
+ * @param {Object} options
46
+ * @param {Error} reason
47
+ * @returns {Object}
48
+ */
49
+ onResponseError(options, reason) {
50
+ options.$timings.networkEnd = Date.now();
51
+
52
+ return Promise.reject(reason);
53
+ }
54
+ }
@@ -1,55 +1,55 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {Interceptor} from '@webex/http-core';
6
-
7
- /**
8
- * @class
9
- */
10
- export default class PayloadTransformerInterceptor extends Interceptor {
11
- /**
12
- * @param {Object} options
13
- * @returns {PayloadTransformerInterceptor}
14
- */
15
- static create() {
16
- return new PayloadTransformerInterceptor({webex: this});
17
- }
18
-
19
- /**
20
- * @see Interceptor#onRequest
21
- * @param {Object} options
22
- * @returns {Object}
23
- */
24
- onRequest(options) {
25
- if (options.noTransform) {
26
- return options;
27
- }
28
-
29
- return this.webex.transform('outbound', options);
30
- }
31
-
32
- /**
33
- * @see Interceptor#onResponse
34
- * @param {Object} options
35
- * @param {HttpResponse} response
36
- * @returns {Object}
37
- */
38
- onResponse(options, response) {
39
- if (options.disableTransform) {
40
- return response;
41
- }
42
-
43
- return this.webex.transform('inbound', response);
44
- }
45
-
46
- /**
47
- * @see Interceptor#onResponseError
48
- * @param {Object} options
49
- * @param {Error} reason
50
- * @returns {Object}
51
- */
52
- onResponseError(options, reason) {
53
- return this.webex.transform('inbound', reason).then((r) => Promise.reject(r || reason));
54
- }
55
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {Interceptor} from '@webex/http-core';
6
+
7
+ /**
8
+ * @class
9
+ */
10
+ export default class PayloadTransformerInterceptor extends Interceptor {
11
+ /**
12
+ * @param {Object} options
13
+ * @returns {PayloadTransformerInterceptor}
14
+ */
15
+ static create() {
16
+ return new PayloadTransformerInterceptor({webex: this});
17
+ }
18
+
19
+ /**
20
+ * @see Interceptor#onRequest
21
+ * @param {Object} options
22
+ * @returns {Object}
23
+ */
24
+ onRequest(options) {
25
+ if (options.noTransform) {
26
+ return options;
27
+ }
28
+
29
+ return this.webex.transform('outbound', options);
30
+ }
31
+
32
+ /**
33
+ * @see Interceptor#onResponse
34
+ * @param {Object} options
35
+ * @param {HttpResponse} response
36
+ * @returns {Object}
37
+ */
38
+ onResponse(options, response) {
39
+ if (options.disableTransform) {
40
+ return response;
41
+ }
42
+
43
+ return this.webex.transform('inbound', response);
44
+ }
45
+
46
+ /**
47
+ * @see Interceptor#onResponseError
48
+ * @param {Object} options
49
+ * @param {Error} reason
50
+ * @returns {Object}
51
+ */
52
+ onResponseError(options, reason) {
53
+ return this.webex.transform('inbound', reason).then((r) => Promise.reject(r || reason));
54
+ }
55
+ }
@@ -1,169 +1,169 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {Interceptor} from '@webex/http-core';
6
-
7
- // contains the system time in milliseconds at which the retry after associated with a 429 expires
8
- // mapped by the API name, e.g.: idbroker.webex.com/doStuff would be mapped as 'doStuff'
9
- const rateLimitExpiryTime = new WeakMap();
10
-
11
- // extracts the common identity API being called
12
- const idBrokerRegex = /.*(idbroker|identity)(bts)?.ciscospark.com\/([^/]+)/;
13
-
14
- /**
15
- * @class
16
- */
17
- export default class RateLimitInterceptor extends Interceptor {
18
- /**
19
- * @returns {RateLimitInterceptor}
20
- */
21
- static create() {
22
- return new RateLimitInterceptor({webex: this});
23
- }
24
-
25
- /**
26
- * constructor
27
- * @param {mixed} args
28
- * @returns {Exception}
29
- */
30
- constructor(...args) {
31
- super(...args);
32
- rateLimitExpiryTime.set(this, new Map());
33
- }
34
-
35
- /**
36
- * @see {@link Interceptor#onRequest}
37
- * @param {Object} options
38
- * @returns {Object}
39
- */
40
- onRequest(options) {
41
- if (this.isRateLimited(options.uri)) {
42
- return Promise.reject(new Error(`API rate limited ${options.uri}`));
43
- }
44
-
45
- return Promise.resolve(options);
46
- }
47
-
48
- /**
49
- * @see {@link Interceptor#onResponseError}
50
- * @param {Object} options
51
- * @param {Error} reason
52
- * @returns {Object}
53
- */
54
- onResponseError(options, reason) {
55
- if (
56
- reason.statusCode === 429 &&
57
- (options.uri.includes('idbroker') || options.uri.includes('identity'))
58
- ) {
59
- // set the retry after in the map, setting to milliseconds
60
- this.setRateLimitExpiry(options.uri, this.extractRetryAfterTime(options));
61
- }
62
-
63
- return Promise.reject(reason);
64
- }
65
-
66
- /**
67
- * @param {object} options associated with the request
68
- * @returns {number} retry after time in milliseconds
69
- */
70
- extractRetryAfterTime(options) {
71
- // 1S * 1K === 1MS
72
- const milliMultiplier = 1000;
73
- const retryAfter = options.headers['retry-after'] || null;
74
-
75
- // set 60 retry if no usable time defined
76
- if (retryAfter === null || retryAfter <= 0) {
77
- return 60 * milliMultiplier;
78
- }
79
- // set max to 3600 S (1 hour) if greater than 1 hour
80
- if (retryAfter > 3600) {
81
- return 3600 * milliMultiplier;
82
- }
83
-
84
- return retryAfter * milliMultiplier;
85
- }
86
-
87
- /**
88
- * Set the system time at which the rate limiting
89
- * will expire in the rateLimitExpiryTime map.
90
- * Assumes retryAfter is in milliseconds
91
- * @param {string} uri API issuing the rate limiting
92
- * @param {number} retryAfter milliseconds until rate limiting expires
93
- * @returns {bool} true is value was successfully set
94
- */
95
- setRateLimitExpiry(uri, retryAfter) {
96
- const apiName = this.getApiName(uri);
97
-
98
- if (!apiName) {
99
- return false;
100
- }
101
-
102
- const currTimeMilli = new Date().getTime();
103
- const expiry = currTimeMilli + retryAfter;
104
- const dict = rateLimitExpiryTime.get(this);
105
-
106
- return dict.set(apiName, expiry);
107
- }
108
-
109
- /**
110
- * returns true if the API is currently rate limited
111
- * @param {string} uri
112
- * @returns {Boolean} indicates whether or not the API is rate currently rate limited
113
- */
114
- getRateLimitStatus(uri) {
115
- const apiName = this.getApiName(uri);
116
-
117
- if (!apiName) {
118
- return false;
119
- }
120
-
121
- const currTimeMilli = new Date().getTime();
122
- const dict = rateLimitExpiryTime.get(this);
123
- const expiryTime = dict.get(apiName);
124
-
125
- // if no rate limit expiry has been registered in the map, return false.
126
- if (expiryTime === undefined) {
127
- return false;
128
- }
129
-
130
- // return true, indicating rate limiting, if the system time is less than the expiry time
131
- return currTimeMilli < dict.get(apiName);
132
- }
133
-
134
- /**
135
- * split the URI and returns the API name of idBroker
136
- * @param {string} uri
137
- * @returns {string}
138
- */
139
- getApiName(uri) {
140
- if (!uri) {
141
- return null;
142
- }
143
-
144
- const results = uri.match(idBrokerRegex);
145
-
146
- if (!results) {
147
- return null;
148
- }
149
-
150
- // group 0 = full match of URL, group 1 = identity or idbroker base
151
- // group 2 = api name
152
- return results[2];
153
- }
154
-
155
- /**
156
- * check URI against list of currently rate limited
157
- * URIs, and determines if retry-after
158
- * @param {String} uri pattern to check
159
- * @returns {bool}
160
- */
161
- isRateLimited(uri) {
162
- // determine if the URI is associated with a common identity API
163
- if (uri && (uri.includes('idbroker') || uri.includes('identity'))) {
164
- return this.getRateLimitStatus(uri);
165
- }
166
-
167
- return false;
168
- }
169
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {Interceptor} from '@webex/http-core';
6
+
7
+ // contains the system time in milliseconds at which the retry after associated with a 429 expires
8
+ // mapped by the API name, e.g.: idbroker.webex.com/doStuff would be mapped as 'doStuff'
9
+ const rateLimitExpiryTime = new WeakMap();
10
+
11
+ // extracts the common identity API being called
12
+ const idBrokerRegex = /.*(idbroker|identity)(bts)?.ciscospark.com\/([^/]+)/;
13
+
14
+ /**
15
+ * @class
16
+ */
17
+ export default class RateLimitInterceptor extends Interceptor {
18
+ /**
19
+ * @returns {RateLimitInterceptor}
20
+ */
21
+ static create() {
22
+ return new RateLimitInterceptor({webex: this});
23
+ }
24
+
25
+ /**
26
+ * constructor
27
+ * @param {mixed} args
28
+ * @returns {Exception}
29
+ */
30
+ constructor(...args) {
31
+ super(...args);
32
+ rateLimitExpiryTime.set(this, new Map());
33
+ }
34
+
35
+ /**
36
+ * @see {@link Interceptor#onRequest}
37
+ * @param {Object} options
38
+ * @returns {Object}
39
+ */
40
+ onRequest(options) {
41
+ if (this.isRateLimited(options.uri)) {
42
+ return Promise.reject(new Error(`API rate limited ${options.uri}`));
43
+ }
44
+
45
+ return Promise.resolve(options);
46
+ }
47
+
48
+ /**
49
+ * @see {@link Interceptor#onResponseError}
50
+ * @param {Object} options
51
+ * @param {Error} reason
52
+ * @returns {Object}
53
+ */
54
+ onResponseError(options, reason) {
55
+ if (
56
+ reason.statusCode === 429 &&
57
+ (options.uri.includes('idbroker') || options.uri.includes('identity'))
58
+ ) {
59
+ // set the retry after in the map, setting to milliseconds
60
+ this.setRateLimitExpiry(options.uri, this.extractRetryAfterTime(options));
61
+ }
62
+
63
+ return Promise.reject(reason);
64
+ }
65
+
66
+ /**
67
+ * @param {object} options associated with the request
68
+ * @returns {number} retry after time in milliseconds
69
+ */
70
+ extractRetryAfterTime(options) {
71
+ // 1S * 1K === 1MS
72
+ const milliMultiplier = 1000;
73
+ const retryAfter = options.headers['retry-after'] || null;
74
+
75
+ // set 60 retry if no usable time defined
76
+ if (retryAfter === null || retryAfter <= 0) {
77
+ return 60 * milliMultiplier;
78
+ }
79
+ // set max to 3600 S (1 hour) if greater than 1 hour
80
+ if (retryAfter > 3600) {
81
+ return 3600 * milliMultiplier;
82
+ }
83
+
84
+ return retryAfter * milliMultiplier;
85
+ }
86
+
87
+ /**
88
+ * Set the system time at which the rate limiting
89
+ * will expire in the rateLimitExpiryTime map.
90
+ * Assumes retryAfter is in milliseconds
91
+ * @param {string} uri API issuing the rate limiting
92
+ * @param {number} retryAfter milliseconds until rate limiting expires
93
+ * @returns {bool} true is value was successfully set
94
+ */
95
+ setRateLimitExpiry(uri, retryAfter) {
96
+ const apiName = this.getApiName(uri);
97
+
98
+ if (!apiName) {
99
+ return false;
100
+ }
101
+
102
+ const currTimeMilli = new Date().getTime();
103
+ const expiry = currTimeMilli + retryAfter;
104
+ const dict = rateLimitExpiryTime.get(this);
105
+
106
+ return dict.set(apiName, expiry);
107
+ }
108
+
109
+ /**
110
+ * returns true if the API is currently rate limited
111
+ * @param {string} uri
112
+ * @returns {Boolean} indicates whether or not the API is rate currently rate limited
113
+ */
114
+ getRateLimitStatus(uri) {
115
+ const apiName = this.getApiName(uri);
116
+
117
+ if (!apiName) {
118
+ return false;
119
+ }
120
+
121
+ const currTimeMilli = new Date().getTime();
122
+ const dict = rateLimitExpiryTime.get(this);
123
+ const expiryTime = dict.get(apiName);
124
+
125
+ // if no rate limit expiry has been registered in the map, return false.
126
+ if (expiryTime === undefined) {
127
+ return false;
128
+ }
129
+
130
+ // return true, indicating rate limiting, if the system time is less than the expiry time
131
+ return currTimeMilli < dict.get(apiName);
132
+ }
133
+
134
+ /**
135
+ * split the URI and returns the API name of idBroker
136
+ * @param {string} uri
137
+ * @returns {string}
138
+ */
139
+ getApiName(uri) {
140
+ if (!uri) {
141
+ return null;
142
+ }
143
+
144
+ const results = uri.match(idBrokerRegex);
145
+
146
+ if (!results) {
147
+ return null;
148
+ }
149
+
150
+ // group 0 = full match of URL, group 1 = identity or idbroker base
151
+ // group 2 = api name
152
+ return results[2];
153
+ }
154
+
155
+ /**
156
+ * check URI against list of currently rate limited
157
+ * URIs, and determines if retry-after
158
+ * @param {String} uri pattern to check
159
+ * @returns {bool}
160
+ */
161
+ isRateLimited(uri) {
162
+ // determine if the URI is associated with a common identity API
163
+ if (uri && (uri.includes('idbroker') || uri.includes('identity'))) {
164
+ return this.getRateLimitStatus(uri);
165
+ }
166
+
167
+ return false;
168
+ }
169
+ }