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

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 +19 -20
  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,435 +1,435 @@
1
- import Url from 'url';
2
-
3
- import AmpState from 'ampersand-state';
4
-
5
- import ServiceUrl from './service-url';
6
-
7
- /* eslint-disable no-underscore-dangle */
8
- /**
9
- * @class
10
- */
11
- const ServiceCatalog = AmpState.extend({
12
- namespace: 'ServiceCatalog',
13
-
14
- props: {
15
- serviceGroups: [
16
- 'object',
17
- true,
18
- () => ({
19
- discovery: [],
20
- override: [],
21
- preauth: [],
22
- postauth: [],
23
- signin: [],
24
- }),
25
- ],
26
- status: [
27
- 'object',
28
- true,
29
- () => ({
30
- discovery: {
31
- ready: false,
32
- collecting: false,
33
- },
34
- override: {
35
- ready: false,
36
- collecting: false,
37
- },
38
- preauth: {
39
- ready: false,
40
- collecting: false,
41
- },
42
- postauth: {
43
- ready: false,
44
- collecting: false,
45
- },
46
- signin: {
47
- ready: false,
48
- collecting: false,
49
- },
50
- }),
51
- ],
52
- isReady: ['boolean', false, false],
53
- allowedDomains: ['array', false, () => []],
54
- },
55
-
56
- /**
57
- * @private
58
- * Search the service url array to locate a `ServiceUrl`
59
- * class object based on its name.
60
- * @param {string} name
61
- * @param {string} [serviceGroup]
62
- * @returns {ServiceUrl}
63
- */
64
- _getUrl(name, serviceGroup) {
65
- const serviceUrls =
66
- typeof serviceGroup === 'string'
67
- ? this.serviceGroups[serviceGroup] || []
68
- : [
69
- ...this.serviceGroups.override,
70
- ...this.serviceGroups.postauth,
71
- ...this.serviceGroups.signin,
72
- ...this.serviceGroups.preauth,
73
- ...this.serviceGroups.discovery,
74
- ];
75
-
76
- return serviceUrls.find((serviceUrl) => serviceUrl.name === name);
77
- },
78
-
79
- /**
80
- * @private
81
- * Generate an array of `ServiceUrl`s that is organized from highest auth
82
- * level to lowest auth level.
83
- * @returns {Array<ServiceUrl>} - array of `ServiceUrl`s
84
- */
85
- _listServiceUrls() {
86
- return [
87
- ...this.serviceGroups.override,
88
- ...this.serviceGroups.postauth,
89
- ...this.serviceGroups.signin,
90
- ...this.serviceGroups.preauth,
91
- ...this.serviceGroups.discovery,
92
- ];
93
- },
94
-
95
- /**
96
- * @private
97
- * Safely load one or more `ServiceUrl`s into this `Services` instance.
98
- * @param {string} serviceGroup
99
- * @param {Array<ServiceUrl>} services
100
- * @returns {Services}
101
- */
102
- _loadServiceUrls(serviceGroup, services) {
103
- // declare namespaces outside of loop
104
- let existingService;
105
-
106
- services.forEach((service) => {
107
- existingService = this._getUrl(service.name, serviceGroup);
108
-
109
- if (!existingService) {
110
- this.serviceGroups[serviceGroup].push(service);
111
- }
112
- });
113
-
114
- return this;
115
- },
116
-
117
- /**
118
- * @private
119
- * Safely unload one or more `ServiceUrl`s into this `Services` instance
120
- * @param {string} serviceGroup
121
- * @param {Array<ServiceUrl>} services
122
- * @returns {Services}
123
- */
124
- _unloadServiceUrls(serviceGroup, services) {
125
- // declare namespaces outside of loop
126
- let existingService;
127
-
128
- services.forEach((service) => {
129
- existingService = this._getUrl(service.name, serviceGroup);
130
-
131
- if (existingService) {
132
- this.serviceGroups[serviceGroup].splice(
133
- this.serviceGroups[serviceGroup].indexOf(existingService),
134
- 1
135
- );
136
- }
137
- });
138
-
139
- return this;
140
- },
141
-
142
- /**
143
- * Clear all collected catalog data and reset catalog status.
144
- *
145
- * @returns {void}
146
- */
147
- clean() {
148
- this.serviceGroups.preauth.length = 0;
149
- this.serviceGroups.signin.length = 0;
150
- this.serviceGroups.postauth.length = 0;
151
- this.status.preauth = {ready: false};
152
- this.status.signin = {ready: false};
153
- this.status.postauth = {ready: false};
154
- },
155
-
156
- /**
157
- * Search over all service groups to find a cluster id based
158
- * on a given url.
159
- * @param {string} url - Must be parsable by `Url`
160
- * @returns {string} - ClusterId of a given url
161
- */
162
- findClusterId(url) {
163
- const incomingUrlObj = Url.parse(url);
164
- let serviceUrlObj;
165
-
166
- for (const key of Object.keys(this.serviceGroups)) {
167
- for (const service of this.serviceGroups[key]) {
168
- serviceUrlObj = Url.parse(service.defaultUrl);
169
-
170
- for (const host of service.hosts) {
171
- if (incomingUrlObj.hostname === host.host && host.id) {
172
- return host.id;
173
- }
174
- }
175
-
176
- if (serviceUrlObj.hostname === incomingUrlObj.hostname && service.hosts.length > 0) {
177
- // no exact match, so try to grab the first home cluster
178
- for (const host of service.hosts) {
179
- if (host.homeCluster) {
180
- return host.id;
181
- }
182
- }
183
-
184
- // no match found still, so return the first entry
185
- return service.hosts[0].id;
186
- }
187
- }
188
- }
189
-
190
- return undefined;
191
- },
192
-
193
- /**
194
- * Search over all service groups and return a service value from a provided
195
- * clusterId. Currently, this method will return either a service name, or a
196
- * service url depending on the `value` parameter. If the `value` parameter
197
- * is set to `name`, it will return a service name to be utilized within the
198
- * Services plugin methods.
199
- * @param {object} params
200
- * @param {string} params.clusterId - clusterId of found service
201
- * @param {boolean} [params.priorityHost = true] - returns priority host url if true
202
- * @param {string} [params.serviceGroup] - specify service group
203
- * @returns {object} service
204
- * @returns {string} service.name
205
- * @returns {string} service.url
206
- */
207
- findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup} = {}) {
208
- const serviceUrls =
209
- typeof serviceGroup === 'string'
210
- ? this.serviceGroups[serviceGroup] || []
211
- : [
212
- ...this.serviceGroups.override,
213
- ...this.serviceGroups.postauth,
214
- ...this.serviceGroups.signin,
215
- ...this.serviceGroups.preauth,
216
- ...this.serviceGroups.discovery,
217
- ];
218
-
219
- const identifiedServiceUrl = serviceUrls.find((serviceUrl) =>
220
- serviceUrl.hosts.find((host) => host.id === clusterId)
221
- );
222
-
223
- if (identifiedServiceUrl) {
224
- return {
225
- name: identifiedServiceUrl.name,
226
- url: identifiedServiceUrl.get(priorityHost, clusterId),
227
- };
228
- }
229
-
230
- return undefined;
231
- },
232
-
233
- /**
234
- * Find a service based on the provided url.
235
- * @param {string} url - Must be parsable by `Url`
236
- * @returns {serviceUrl} - ServiceUrl assocated with provided url
237
- */
238
- findServiceUrlFromUrl(url) {
239
- const incomingUrlObj = Url.parse(url);
240
- const serviceUrls = [
241
- ...this.serviceGroups.discovery,
242
- ...this.serviceGroups.preauth,
243
- ...this.serviceGroups.signin,
244
- ...this.serviceGroups.postauth,
245
- ...this.serviceGroups.override,
246
- ];
247
-
248
- return serviceUrls.find((serviceUrl) => {
249
- if (incomingUrlObj.hostname === Url.parse(serviceUrl.defaultUrl).hostname) {
250
- return true;
251
- }
252
-
253
- if (serviceUrl.hosts.find((host) => host.host === incomingUrlObj.hostname)) {
254
- return true;
255
- }
256
-
257
- return false;
258
- });
259
- },
260
-
261
- /**
262
- * Finds an allowed domain that matches a specific url.
263
- *
264
- * @param {string} url - The url to match the allowed domains against.
265
- * @returns {string} - The matching allowed domain.
266
- */
267
- findAllowedDomain(url) {
268
- const urlObj = Url.parse(url);
269
-
270
- if (!urlObj.host) {
271
- return undefined;
272
- }
273
-
274
- return this.allowedDomains.find((allowedDomain) => urlObj.host.includes(allowedDomain));
275
- },
276
-
277
- /**
278
- * Get a service url from the current services list by name.
279
- * @param {string} name
280
- * @param {boolean} priorityHost
281
- * @param {string} serviceGroup
282
- * @returns {string}
283
- */
284
- get(name, priorityHost, serviceGroup) {
285
- const serviceUrl = this._getUrl(name, serviceGroup);
286
-
287
- return serviceUrl ? serviceUrl.get(priorityHost) : undefined;
288
- },
289
-
290
- /**
291
- * Get the current allowed domains list.
292
- *
293
- * @returns {Array<string>} - the current allowed domains list.
294
- */
295
- getAllowedDomains() {
296
- return [...this.allowedDomains];
297
- },
298
-
299
- /**
300
- * Creates an object where the keys are the service names
301
- * and the values are the service urls.
302
- * @param {boolean} priorityHost - use the highest priority if set to `true`
303
- * @param {string} [serviceGroup]
304
- * @returns {Record<string, string>}
305
- */
306
- list(priorityHost, serviceGroup) {
307
- const output = {};
308
-
309
- const serviceUrls =
310
- typeof serviceGroup === 'string'
311
- ? this.serviceGroups[serviceGroup] || []
312
- : [
313
- ...this.serviceGroups.discovery,
314
- ...this.serviceGroups.preauth,
315
- ...this.serviceGroups.signin,
316
- ...this.serviceGroups.postauth,
317
- ...this.serviceGroups.override,
318
- ];
319
-
320
- if (serviceUrls) {
321
- serviceUrls.forEach((serviceUrl) => {
322
- output[serviceUrl.name] = serviceUrl.get(priorityHost);
323
- });
324
- }
325
-
326
- return output;
327
- },
328
-
329
- /**
330
- * Mark a priority host service url as failed.
331
- * This will mark the host associated with the
332
- * `ServiceUrl` to be removed from the its
333
- * respective host array, and then return the next
334
- * viable host from the `ServiceUrls` host array,
335
- * or the `ServiceUrls` default url if no other priority
336
- * hosts are available, or if `noPriorityHosts` is set to
337
- * `true`.
338
- * @param {string} url
339
- * @param {boolean} noPriorityHosts
340
- * @returns {string}
341
- */
342
- markFailedUrl(url, noPriorityHosts) {
343
- const serviceUrl = this._getUrl(
344
- Object.keys(this.list()).find((key) => this._getUrl(key).failHost(url))
345
- );
346
-
347
- if (!serviceUrl) {
348
- return undefined;
349
- }
350
-
351
- return noPriorityHosts ? serviceUrl.get(false) : serviceUrl.get(true);
352
- },
353
-
354
- /**
355
- * Set the allowed domains for the catalog.
356
- *
357
- * @param {Array<string>} allowedDomains - allowed domains to be assigned.
358
- * @returns {void}
359
- */
360
- setAllowedDomains(allowedDomains) {
361
- this.allowedDomains = [...allowedDomains];
362
- },
363
-
364
- /**
365
- * Update the current list of `ServiceUrl`s against a provided
366
- * service hostmap.
367
- * @emits ServiceCatalog#preauthorized
368
- * @emits ServiceCatalog#postauthorized
369
- * @param {string} serviceGroup
370
- * @param {object} serviceHostmap
371
- * @returns {Services}
372
- */
373
- updateServiceUrls(serviceGroup, serviceHostmap) {
374
- const currentServiceUrls = this.serviceGroups[serviceGroup];
375
-
376
- const unusedUrls = currentServiceUrls.filter((serviceUrl) =>
377
- serviceHostmap.every((item) => item.name !== serviceUrl.name)
378
- );
379
-
380
- this._unloadServiceUrls(serviceGroup, unusedUrls);
381
-
382
- serviceHostmap.forEach((serviceObj) => {
383
- const service = this._getUrl(serviceObj.name, serviceGroup);
384
-
385
- if (service) {
386
- service.defaultUrl = serviceObj.defaultUrl;
387
- service.hosts = serviceObj.hosts || [];
388
- } else {
389
- this._loadServiceUrls(serviceGroup, [
390
- new ServiceUrl({
391
- ...serviceObj,
392
- }),
393
- ]);
394
- }
395
- });
396
-
397
- this.status[serviceGroup].ready = true;
398
- this.trigger(serviceGroup);
399
-
400
- return this;
401
- },
402
-
403
- /**
404
- * Wait until the service catalog is available,
405
- * or reject after a timeout of 60 seconds.
406
- * @param {string} serviceGroup
407
- * @param {number} [timeout] - in seconds
408
- * @returns {Promise<void>}
409
- */
410
- waitForCatalog(serviceGroup, timeout) {
411
- return new Promise((resolve, reject) => {
412
- if (this.status[serviceGroup].ready) {
413
- resolve();
414
- }
415
-
416
- const timeoutTimer = setTimeout(
417
- () =>
418
- reject(
419
- new Error(
420
- `services: timeout occured while waiting for '${serviceGroup}' catalog to populate`
421
- )
422
- ),
423
- timeout ? timeout * 1000 : 60000
424
- );
425
-
426
- this.once(serviceGroup, () => {
427
- clearTimeout(timeoutTimer);
428
- resolve();
429
- });
430
- });
431
- },
432
- });
433
- /* eslint-enable no-underscore-dangle */
434
-
435
- export default ServiceCatalog;
1
+ import Url from 'url';
2
+
3
+ import AmpState from 'ampersand-state';
4
+
5
+ import ServiceUrl from './service-url';
6
+
7
+ /* eslint-disable no-underscore-dangle */
8
+ /**
9
+ * @class
10
+ */
11
+ const ServiceCatalog = AmpState.extend({
12
+ namespace: 'ServiceCatalog',
13
+
14
+ props: {
15
+ serviceGroups: [
16
+ 'object',
17
+ true,
18
+ () => ({
19
+ discovery: [],
20
+ override: [],
21
+ preauth: [],
22
+ postauth: [],
23
+ signin: [],
24
+ }),
25
+ ],
26
+ status: [
27
+ 'object',
28
+ true,
29
+ () => ({
30
+ discovery: {
31
+ ready: false,
32
+ collecting: false,
33
+ },
34
+ override: {
35
+ ready: false,
36
+ collecting: false,
37
+ },
38
+ preauth: {
39
+ ready: false,
40
+ collecting: false,
41
+ },
42
+ postauth: {
43
+ ready: false,
44
+ collecting: false,
45
+ },
46
+ signin: {
47
+ ready: false,
48
+ collecting: false,
49
+ },
50
+ }),
51
+ ],
52
+ isReady: ['boolean', false, false],
53
+ allowedDomains: ['array', false, () => []],
54
+ },
55
+
56
+ /**
57
+ * @private
58
+ * Search the service url array to locate a `ServiceUrl`
59
+ * class object based on its name.
60
+ * @param {string} name
61
+ * @param {string} [serviceGroup]
62
+ * @returns {ServiceUrl}
63
+ */
64
+ _getUrl(name, serviceGroup) {
65
+ const serviceUrls =
66
+ typeof serviceGroup === 'string'
67
+ ? this.serviceGroups[serviceGroup] || []
68
+ : [
69
+ ...this.serviceGroups.override,
70
+ ...this.serviceGroups.postauth,
71
+ ...this.serviceGroups.signin,
72
+ ...this.serviceGroups.preauth,
73
+ ...this.serviceGroups.discovery,
74
+ ];
75
+
76
+ return serviceUrls.find((serviceUrl) => serviceUrl.name === name);
77
+ },
78
+
79
+ /**
80
+ * @private
81
+ * Generate an array of `ServiceUrl`s that is organized from highest auth
82
+ * level to lowest auth level.
83
+ * @returns {Array<ServiceUrl>} - array of `ServiceUrl`s
84
+ */
85
+ _listServiceUrls() {
86
+ return [
87
+ ...this.serviceGroups.override,
88
+ ...this.serviceGroups.postauth,
89
+ ...this.serviceGroups.signin,
90
+ ...this.serviceGroups.preauth,
91
+ ...this.serviceGroups.discovery,
92
+ ];
93
+ },
94
+
95
+ /**
96
+ * @private
97
+ * Safely load one or more `ServiceUrl`s into this `Services` instance.
98
+ * @param {string} serviceGroup
99
+ * @param {Array<ServiceUrl>} services
100
+ * @returns {Services}
101
+ */
102
+ _loadServiceUrls(serviceGroup, services) {
103
+ // declare namespaces outside of loop
104
+ let existingService;
105
+
106
+ services.forEach((service) => {
107
+ existingService = this._getUrl(service.name, serviceGroup);
108
+
109
+ if (!existingService) {
110
+ this.serviceGroups[serviceGroup].push(service);
111
+ }
112
+ });
113
+
114
+ return this;
115
+ },
116
+
117
+ /**
118
+ * @private
119
+ * Safely unload one or more `ServiceUrl`s into this `Services` instance
120
+ * @param {string} serviceGroup
121
+ * @param {Array<ServiceUrl>} services
122
+ * @returns {Services}
123
+ */
124
+ _unloadServiceUrls(serviceGroup, services) {
125
+ // declare namespaces outside of loop
126
+ let existingService;
127
+
128
+ services.forEach((service) => {
129
+ existingService = this._getUrl(service.name, serviceGroup);
130
+
131
+ if (existingService) {
132
+ this.serviceGroups[serviceGroup].splice(
133
+ this.serviceGroups[serviceGroup].indexOf(existingService),
134
+ 1
135
+ );
136
+ }
137
+ });
138
+
139
+ return this;
140
+ },
141
+
142
+ /**
143
+ * Clear all collected catalog data and reset catalog status.
144
+ *
145
+ * @returns {void}
146
+ */
147
+ clean() {
148
+ this.serviceGroups.preauth.length = 0;
149
+ this.serviceGroups.signin.length = 0;
150
+ this.serviceGroups.postauth.length = 0;
151
+ this.status.preauth = {ready: false};
152
+ this.status.signin = {ready: false};
153
+ this.status.postauth = {ready: false};
154
+ },
155
+
156
+ /**
157
+ * Search over all service groups to find a cluster id based
158
+ * on a given url.
159
+ * @param {string} url - Must be parsable by `Url`
160
+ * @returns {string} - ClusterId of a given url
161
+ */
162
+ findClusterId(url) {
163
+ const incomingUrlObj = Url.parse(url);
164
+ let serviceUrlObj;
165
+
166
+ for (const key of Object.keys(this.serviceGroups)) {
167
+ for (const service of this.serviceGroups[key]) {
168
+ serviceUrlObj = Url.parse(service.defaultUrl);
169
+
170
+ for (const host of service.hosts) {
171
+ if (incomingUrlObj.hostname === host.host && host.id) {
172
+ return host.id;
173
+ }
174
+ }
175
+
176
+ if (serviceUrlObj.hostname === incomingUrlObj.hostname && service.hosts.length > 0) {
177
+ // no exact match, so try to grab the first home cluster
178
+ for (const host of service.hosts) {
179
+ if (host.homeCluster) {
180
+ return host.id;
181
+ }
182
+ }
183
+
184
+ // no match found still, so return the first entry
185
+ return service.hosts[0].id;
186
+ }
187
+ }
188
+ }
189
+
190
+ return undefined;
191
+ },
192
+
193
+ /**
194
+ * Search over all service groups and return a service value from a provided
195
+ * clusterId. Currently, this method will return either a service name, or a
196
+ * service url depending on the `value` parameter. If the `value` parameter
197
+ * is set to `name`, it will return a service name to be utilized within the
198
+ * Services plugin methods.
199
+ * @param {object} params
200
+ * @param {string} params.clusterId - clusterId of found service
201
+ * @param {boolean} [params.priorityHost = true] - returns priority host url if true
202
+ * @param {string} [params.serviceGroup] - specify service group
203
+ * @returns {object} service
204
+ * @returns {string} service.name
205
+ * @returns {string} service.url
206
+ */
207
+ findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup} = {}) {
208
+ const serviceUrls =
209
+ typeof serviceGroup === 'string'
210
+ ? this.serviceGroups[serviceGroup] || []
211
+ : [
212
+ ...this.serviceGroups.override,
213
+ ...this.serviceGroups.postauth,
214
+ ...this.serviceGroups.signin,
215
+ ...this.serviceGroups.preauth,
216
+ ...this.serviceGroups.discovery,
217
+ ];
218
+
219
+ const identifiedServiceUrl = serviceUrls.find((serviceUrl) =>
220
+ serviceUrl.hosts.find((host) => host.id === clusterId)
221
+ );
222
+
223
+ if (identifiedServiceUrl) {
224
+ return {
225
+ name: identifiedServiceUrl.name,
226
+ url: identifiedServiceUrl.get(priorityHost, clusterId),
227
+ };
228
+ }
229
+
230
+ return undefined;
231
+ },
232
+
233
+ /**
234
+ * Find a service based on the provided url.
235
+ * @param {string} url - Must be parsable by `Url`
236
+ * @returns {serviceUrl} - ServiceUrl assocated with provided url
237
+ */
238
+ findServiceUrlFromUrl(url) {
239
+ const incomingUrlObj = Url.parse(url);
240
+ const serviceUrls = [
241
+ ...this.serviceGroups.discovery,
242
+ ...this.serviceGroups.preauth,
243
+ ...this.serviceGroups.signin,
244
+ ...this.serviceGroups.postauth,
245
+ ...this.serviceGroups.override,
246
+ ];
247
+
248
+ return serviceUrls.find((serviceUrl) => {
249
+ if (incomingUrlObj.hostname === Url.parse(serviceUrl.defaultUrl).hostname) {
250
+ return true;
251
+ }
252
+
253
+ if (serviceUrl.hosts.find((host) => host.host === incomingUrlObj.hostname)) {
254
+ return true;
255
+ }
256
+
257
+ return false;
258
+ });
259
+ },
260
+
261
+ /**
262
+ * Finds an allowed domain that matches a specific url.
263
+ *
264
+ * @param {string} url - The url to match the allowed domains against.
265
+ * @returns {string} - The matching allowed domain.
266
+ */
267
+ findAllowedDomain(url) {
268
+ const urlObj = Url.parse(url);
269
+
270
+ if (!urlObj.host) {
271
+ return undefined;
272
+ }
273
+
274
+ return this.allowedDomains.find((allowedDomain) => urlObj.host.includes(allowedDomain));
275
+ },
276
+
277
+ /**
278
+ * Get a service url from the current services list by name.
279
+ * @param {string} name
280
+ * @param {boolean} priorityHost
281
+ * @param {string} serviceGroup
282
+ * @returns {string}
283
+ */
284
+ get(name, priorityHost, serviceGroup) {
285
+ const serviceUrl = this._getUrl(name, serviceGroup);
286
+
287
+ return serviceUrl ? serviceUrl.get(priorityHost) : undefined;
288
+ },
289
+
290
+ /**
291
+ * Get the current allowed domains list.
292
+ *
293
+ * @returns {Array<string>} - the current allowed domains list.
294
+ */
295
+ getAllowedDomains() {
296
+ return [...this.allowedDomains];
297
+ },
298
+
299
+ /**
300
+ * Creates an object where the keys are the service names
301
+ * and the values are the service urls.
302
+ * @param {boolean} priorityHost - use the highest priority if set to `true`
303
+ * @param {string} [serviceGroup]
304
+ * @returns {Record<string, string>}
305
+ */
306
+ list(priorityHost, serviceGroup) {
307
+ const output = {};
308
+
309
+ const serviceUrls =
310
+ typeof serviceGroup === 'string'
311
+ ? this.serviceGroups[serviceGroup] || []
312
+ : [
313
+ ...this.serviceGroups.discovery,
314
+ ...this.serviceGroups.preauth,
315
+ ...this.serviceGroups.signin,
316
+ ...this.serviceGroups.postauth,
317
+ ...this.serviceGroups.override,
318
+ ];
319
+
320
+ if (serviceUrls) {
321
+ serviceUrls.forEach((serviceUrl) => {
322
+ output[serviceUrl.name] = serviceUrl.get(priorityHost);
323
+ });
324
+ }
325
+
326
+ return output;
327
+ },
328
+
329
+ /**
330
+ * Mark a priority host service url as failed.
331
+ * This will mark the host associated with the
332
+ * `ServiceUrl` to be removed from the its
333
+ * respective host array, and then return the next
334
+ * viable host from the `ServiceUrls` host array,
335
+ * or the `ServiceUrls` default url if no other priority
336
+ * hosts are available, or if `noPriorityHosts` is set to
337
+ * `true`.
338
+ * @param {string} url
339
+ * @param {boolean} noPriorityHosts
340
+ * @returns {string}
341
+ */
342
+ markFailedUrl(url, noPriorityHosts) {
343
+ const serviceUrl = this._getUrl(
344
+ Object.keys(this.list()).find((key) => this._getUrl(key).failHost(url))
345
+ );
346
+
347
+ if (!serviceUrl) {
348
+ return undefined;
349
+ }
350
+
351
+ return noPriorityHosts ? serviceUrl.get(false) : serviceUrl.get(true);
352
+ },
353
+
354
+ /**
355
+ * Set the allowed domains for the catalog.
356
+ *
357
+ * @param {Array<string>} allowedDomains - allowed domains to be assigned.
358
+ * @returns {void}
359
+ */
360
+ setAllowedDomains(allowedDomains) {
361
+ this.allowedDomains = [...allowedDomains];
362
+ },
363
+
364
+ /**
365
+ * Update the current list of `ServiceUrl`s against a provided
366
+ * service hostmap.
367
+ * @emits ServiceCatalog#preauthorized
368
+ * @emits ServiceCatalog#postauthorized
369
+ * @param {string} serviceGroup
370
+ * @param {object} serviceHostmap
371
+ * @returns {Services}
372
+ */
373
+ updateServiceUrls(serviceGroup, serviceHostmap) {
374
+ const currentServiceUrls = this.serviceGroups[serviceGroup];
375
+
376
+ const unusedUrls = currentServiceUrls.filter((serviceUrl) =>
377
+ serviceHostmap.every((item) => item.name !== serviceUrl.name)
378
+ );
379
+
380
+ this._unloadServiceUrls(serviceGroup, unusedUrls);
381
+
382
+ serviceHostmap.forEach((serviceObj) => {
383
+ const service = this._getUrl(serviceObj.name, serviceGroup);
384
+
385
+ if (service) {
386
+ service.defaultUrl = serviceObj.defaultUrl;
387
+ service.hosts = serviceObj.hosts || [];
388
+ } else {
389
+ this._loadServiceUrls(serviceGroup, [
390
+ new ServiceUrl({
391
+ ...serviceObj,
392
+ }),
393
+ ]);
394
+ }
395
+ });
396
+
397
+ this.status[serviceGroup].ready = true;
398
+ this.trigger(serviceGroup);
399
+
400
+ return this;
401
+ },
402
+
403
+ /**
404
+ * Wait until the service catalog is available,
405
+ * or reject after a timeout of 60 seconds.
406
+ * @param {string} serviceGroup
407
+ * @param {number} [timeout] - in seconds
408
+ * @returns {Promise<void>}
409
+ */
410
+ waitForCatalog(serviceGroup, timeout) {
411
+ return new Promise((resolve, reject) => {
412
+ if (this.status[serviceGroup].ready) {
413
+ resolve();
414
+ }
415
+
416
+ const timeoutTimer = setTimeout(
417
+ () =>
418
+ reject(
419
+ new Error(
420
+ `services: timeout occured while waiting for '${serviceGroup}' catalog to populate`
421
+ )
422
+ ),
423
+ timeout ? timeout * 1000 : 60000
424
+ );
425
+
426
+ this.once(serviceGroup, () => {
427
+ clearTimeout(timeoutTimer);
428
+ resolve();
429
+ });
430
+ });
431
+ },
432
+ });
433
+ /* eslint-enable no-underscore-dangle */
434
+
435
+ export default ServiceCatalog;