@webex/webex-core 3.8.0 → 3.8.1-next.10

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 (79) hide show
  1. package/README.md +87 -27
  2. package/dist/index.js +28 -9
  3. package/dist/index.js.map +1 -1
  4. package/dist/interceptors/redirect.js +18 -0
  5. package/dist/interceptors/redirect.js.map +1 -1
  6. package/dist/lib/batcher.js +1 -1
  7. package/dist/lib/constants.js +10 -1
  8. package/dist/lib/constants.js.map +1 -1
  9. package/dist/lib/credentials/credentials.js +1 -1
  10. package/dist/lib/credentials/token.js +1 -1
  11. package/dist/lib/{services/interceptors → interceptors}/server-error.js +1 -1
  12. package/dist/lib/interceptors/server-error.js.map +1 -0
  13. package/dist/lib/services/index.js +2 -29
  14. package/dist/lib/services/index.js.map +1 -1
  15. package/dist/lib/services/service-host.js +1 -1
  16. package/dist/lib/services/service-host.js.map +1 -1
  17. package/dist/lib/services/service-registry.js +1 -1
  18. package/dist/lib/services/service-registry.js.map +1 -1
  19. package/dist/lib/services/service-state.js +1 -1
  20. package/dist/lib/services/service-state.js.map +1 -1
  21. package/dist/lib/services/services.js +3 -3
  22. package/dist/lib/services/services.js.map +1 -1
  23. package/dist/lib/services-v2/index.js +29 -0
  24. package/dist/lib/services-v2/index.js.map +1 -0
  25. package/dist/lib/services-v2/metrics.js +12 -0
  26. package/dist/lib/services-v2/metrics.js.map +1 -0
  27. package/dist/lib/services-v2/service-catalog.js +347 -0
  28. package/dist/lib/services-v2/service-catalog.js.map +1 -0
  29. package/dist/lib/services-v2/service-detail.js +94 -0
  30. package/dist/lib/services-v2/service-detail.js.map +1 -0
  31. package/dist/lib/services-v2/service-fed-ramp.js +13 -0
  32. package/dist/lib/services-v2/service-fed-ramp.js.map +1 -0
  33. package/dist/lib/services-v2/services-v2.js +974 -0
  34. package/dist/lib/services-v2/services-v2.js.map +1 -0
  35. package/dist/lib/services-v2/types.js +7 -0
  36. package/dist/lib/services-v2/types.js.map +1 -0
  37. package/dist/plugins/logger.js +1 -1
  38. package/dist/webex-core.js +3 -3
  39. package/dist/webex-core.js.map +1 -1
  40. package/package.json +13 -13
  41. package/src/index.js +5 -4
  42. package/src/interceptors/redirect.js +28 -0
  43. package/src/lib/constants.js +29 -1
  44. package/src/lib/{services/interceptors → interceptors}/server-error.js +1 -1
  45. package/src/lib/services/index.js +2 -7
  46. package/src/lib/services/service-host.js +1 -1
  47. package/src/lib/services/service-registry.js +1 -1
  48. package/src/lib/services/service-state.js +1 -1
  49. package/src/lib/services/services.js +2 -2
  50. package/src/lib/services-v2/README.md +3 -0
  51. package/src/lib/services-v2/index.ts +7 -0
  52. package/src/lib/services-v2/metrics.ts +4 -0
  53. package/src/lib/services-v2/service-catalog.ts +361 -0
  54. package/src/lib/services-v2/service-detail.ts +97 -0
  55. package/src/lib/services-v2/service-fed-ramp.ts +5 -0
  56. package/src/lib/services-v2/services-v2.ts +1010 -0
  57. package/src/lib/services-v2/types.ts +73 -0
  58. package/src/webex-core.js +1 -1
  59. package/test/fixtures/host-catalog-v2.ts +157 -0
  60. package/test/integration/spec/services/services.js +23 -10
  61. package/test/integration/spec/services-v2/service-catalog.js +664 -0
  62. package/test/integration/spec/services-v2/services-v2.js +1061 -0
  63. package/test/unit/spec/interceptors/redirect.js +72 -0
  64. package/test/unit/spec/services-v2/service-catalog.ts +288 -0
  65. package/test/unit/spec/services-v2/service-detail.ts +147 -0
  66. package/test/unit/spec/services-v2/services-v2.ts +516 -0
  67. package/dist/lib/services/constants.js +0 -17
  68. package/dist/lib/services/constants.js.map +0 -1
  69. package/dist/lib/services/interceptors/server-error.js.map +0 -1
  70. package/src/lib/services/constants.js +0 -21
  71. /package/dist/lib/{services/interceptors → interceptors}/hostmap.js +0 -0
  72. /package/dist/lib/{services/interceptors → interceptors}/hostmap.js.map +0 -0
  73. /package/dist/lib/{services/interceptors → interceptors}/service.js +0 -0
  74. /package/dist/lib/{services/interceptors → interceptors}/service.js.map +0 -0
  75. /package/dist/lib/{services/metrics.js → metrics.js} +0 -0
  76. /package/dist/lib/{services/metrics.js.map → metrics.js.map} +0 -0
  77. /package/src/lib/{services/interceptors → interceptors}/hostmap.js +0 -0
  78. /package/src/lib/{services/interceptors → interceptors}/service.js +0 -0
  79. /package/src/lib/{services/metrics.js → metrics.js} +0 -0
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import {Interceptor} from '@webex/http-core';
6
- import WebexHttpError from '../../webex-http-error';
6
+ import WebexHttpError from '../webex-http-error';
7
7
  /**
8
8
  * Changes server url when it fails
9
9
  */
@@ -3,10 +3,9 @@
3
3
  */
4
4
  import {registerInternalPlugin} from '../../webex-core';
5
5
 
6
- import * as constants from './constants';
7
6
  import Services from './services';
8
- import ServerErrorInterceptor from './interceptors/server-error';
9
- import ServiceInterceptor from './interceptors/service';
7
+ import ServerErrorInterceptor from '../interceptors/server-error';
8
+ import ServiceInterceptor from '../interceptors/service';
10
9
 
11
10
  registerInternalPlugin('services', Services, {
12
11
  interceptors: {
@@ -15,10 +14,6 @@ registerInternalPlugin('services', Services, {
15
14
  },
16
15
  });
17
16
 
18
- export {constants};
19
- export {default as ServiceInterceptor} from './interceptors/service';
20
- export {default as ServerErrorInterceptor} from './interceptors/server-error';
21
- export {default as HostMapInterceptor} from './interceptors/hostmap';
22
17
  export {default as Services} from './services';
23
18
  export {default as ServiceCatalog} from './service-catalog';
24
19
  export {default as ServiceRegistry} from './service-registry';
@@ -1,6 +1,6 @@
1
1
  import Url from 'url';
2
2
 
3
- import {SERVICE_CATALOGS} from './constants';
3
+ import {SERVICE_CATALOGS} from '../constants';
4
4
 
5
5
  /**
6
6
  * The parameter transfer object for {@link ServiceHost#constructor}.
@@ -1,4 +1,4 @@
1
- import {SERVICE_CATALOGS, SERVICE_CATALOGS_ENUM_TYPES} from './constants';
1
+ import {SERVICE_CATALOGS, SERVICE_CATALOGS_ENUM_TYPES} from '../constants';
2
2
  import ServiceHost from './service-host';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import {SERVICE_CATALOGS} from './constants';
1
+ import {SERVICE_CATALOGS} from '../constants';
2
2
 
3
3
  /**
4
4
  * The state of a specific catalog to be used by {@link ServiceState}.
@@ -3,12 +3,12 @@ import sha256 from 'crypto-js/sha256';
3
3
  import {union, forEach} from 'lodash';
4
4
  import WebexPlugin from '../webex-plugin';
5
5
 
6
- import METRICS from './metrics';
6
+ import METRICS from '../metrics';
7
7
  import ServiceCatalog from './service-catalog';
8
8
  import ServiceRegistry from './service-registry';
9
9
  import ServiceState from './service-state';
10
10
  import fedRampServices from './service-fed-ramp';
11
- import {COMMERCIAL_ALLOWED_DOMAINS} from './constants';
11
+ import {COMMERCIAL_ALLOWED_DOMAINS} from '../constants';
12
12
 
13
13
  const trailingSlashes = /(?:^\/)|(?:\/$)/;
14
14
 
@@ -0,0 +1,3 @@
1
+ [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
2
+
3
+ > Services plugin update for WG4 DNSSec enabled users, this module is a work in progress. Please use at your own risk! This service will be updated many times to enable this feature. Continue to use /services.
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ export {default as ServicesV2} from './services-v2';
6
+ export {default as ServiceCatalogV2} from './service-catalog';
7
+ export {default as ServiceDetail} from './service-detail';
@@ -0,0 +1,4 @@
1
+ // Metrics for service catalog
2
+ export default {
3
+ JS_SDK_SERVICE_NOT_FOUND: 'JS_SDK_SERVICE_NOT_FOUND',
4
+ };
@@ -0,0 +1,361 @@
1
+ import AmpState from 'ampersand-state';
2
+
3
+ import {union} from 'lodash';
4
+ import ServiceDetail from './service-detail';
5
+ import {IServiceDetail, ServiceGroup} from './types';
6
+
7
+ /**
8
+ * @class
9
+ */
10
+ const ServiceCatalog = AmpState.extend({
11
+ namespace: 'ServiceCatalog',
12
+
13
+ props: {
14
+ serviceGroups: [
15
+ 'object',
16
+ true,
17
+ () => ({
18
+ discovery: [],
19
+ override: [],
20
+ preauth: [],
21
+ postauth: [],
22
+ signin: [],
23
+ }),
24
+ ],
25
+ status: [
26
+ 'object',
27
+ true,
28
+ () => ({
29
+ discovery: {
30
+ ready: false,
31
+ collecting: false,
32
+ },
33
+ override: {
34
+ ready: false,
35
+ collecting: false,
36
+ },
37
+ preauth: {
38
+ ready: false,
39
+ collecting: false,
40
+ },
41
+ postauth: {
42
+ ready: false,
43
+ collecting: false,
44
+ },
45
+ signin: {
46
+ ready: false,
47
+ collecting: false,
48
+ },
49
+ }),
50
+ ],
51
+ isReady: ['boolean', false, false],
52
+ allowedDomains: ['array', false, () => []],
53
+ },
54
+
55
+ /**
56
+ * @private
57
+ * Get all service details for a given service group or return all details if no group is specified.
58
+ * @param {ServiceGroup} serviceGroup - The name of the service group to retrieve details for.
59
+ * @returns {Array<IServiceDetail>} - An array of service details.
60
+ */
61
+ _getAllServiceDetails(serviceGroup?: ServiceGroup): Array<IServiceDetail> {
62
+ const serviceDetails =
63
+ typeof serviceGroup === 'string'
64
+ ? this.serviceGroups[serviceGroup] || []
65
+ : [
66
+ ...this.serviceGroups.override,
67
+ ...this.serviceGroups.postauth,
68
+ ...this.serviceGroups.signin,
69
+ ...this.serviceGroups.preauth,
70
+ ...this.serviceGroups.discovery,
71
+ ];
72
+
73
+ return serviceDetails;
74
+ },
75
+
76
+ /**
77
+ * @private
78
+ * Search the service details array to locate a `ServiceDetails`
79
+ * class object based on its id.
80
+ * @param {string} clusterId
81
+ * @param {ServiceGroup} [serviceGroup]
82
+ * @returns {IServiceDetail}
83
+ */
84
+ _getServiceDetail(clusterId: string, serviceGroup?: ServiceGroup): IServiceDetail | undefined {
85
+ const serviceDetails = this._getAllServiceDetails(serviceGroup);
86
+
87
+ return serviceDetails.find((serviceDetail: IServiceDetail) => serviceDetail.id === clusterId);
88
+ },
89
+
90
+ /**
91
+ * @private
92
+ * Safely load one or more `ServiceDetail`s into this `ServiceCatalog` instance.
93
+ * @param {ServiceGroup} serviceGroup
94
+ * @param {Array<ServiceDetail>} serviceDetails
95
+ * @returns {void}
96
+ */
97
+ _loadServiceDetails(serviceGroup: ServiceGroup, serviceDetails: Array<IServiceDetail>): void {
98
+ // declare namespaces outside of loop
99
+ let existingService: IServiceDetail | undefined;
100
+
101
+ serviceDetails.forEach((service) => {
102
+ existingService = this._getServiceDetail(service.id, serviceGroup);
103
+
104
+ if (!existingService) {
105
+ this.serviceGroups[serviceGroup].push(service);
106
+ }
107
+ });
108
+ },
109
+
110
+ /**
111
+ * @private
112
+ * Safely unload one or more `ServiceDetail`s into this `Services` instance
113
+ * @param {ServiceGroup} serviceGroup
114
+ * @param {Array<ServiceDetail>} serviceDetails
115
+ * @returns {void}
116
+ */
117
+ _unloadServiceDetails(serviceGroup: ServiceGroup, serviceDetails: Array<IServiceDetail>): void {
118
+ // declare namespaces outside of loop
119
+ let existingService: IServiceDetail | undefined;
120
+
121
+ serviceDetails.forEach((service) => {
122
+ existingService = this._getServiceDetail(service.id, serviceGroup);
123
+
124
+ if (existingService) {
125
+ this.serviceGroups[serviceGroup].splice(
126
+ this.serviceGroups[serviceGroup].indexOf(existingService),
127
+ 1
128
+ );
129
+ }
130
+ });
131
+ },
132
+
133
+ /**
134
+ * Clear all collected catalog data and reset catalog status.
135
+ *
136
+ * @returns {void}
137
+ */
138
+ clean(): void {
139
+ this.serviceGroups.preauth.length = 0;
140
+ this.serviceGroups.signin.length = 0;
141
+ this.serviceGroups.postauth.length = 0;
142
+ this.status.preauth = {ready: false};
143
+ this.status.signin = {ready: false};
144
+ this.status.postauth = {ready: false};
145
+ },
146
+
147
+ /**
148
+ * Search over all service groups to find a cluster id based
149
+ * on a given url.
150
+ * @param {string} url - Must be parsable by `Url`
151
+ * @returns {string | undefined} - ClusterId of a given url
152
+ */
153
+ findClusterId(url: string): string | undefined {
154
+ try {
155
+ const incomingUrlObj = new URL(url);
156
+ const allServiceDetails = this._getAllServiceDetails();
157
+
158
+ return allServiceDetails.find((serviceDetail: IServiceDetail) =>
159
+ serviceDetail.serviceUrls.find(({host}) => host === incomingUrlObj.host)
160
+ )?.id;
161
+ } catch {
162
+ // If the URL is invalid or can't be found, return undefined
163
+ return undefined;
164
+ }
165
+ },
166
+
167
+ /**
168
+ * Search over all service groups and return a service value from a provided
169
+ * clusterId.
170
+ * @param {object} params
171
+ * @param {string} params.clusterId - clusterId of found service
172
+ * @param {ServiceGroup} [params.serviceGroup] - specify service group
173
+ * @returns {object} service
174
+ * @returns {string} service.name
175
+ * @returns {string} service.url
176
+ */
177
+ findServiceFromClusterId(
178
+ {clusterId, serviceGroup} = {} as {clusterId: string; serviceGroup?: ServiceGroup}
179
+ ): {name: string; url: string} | undefined {
180
+ const serviceDetails = this._getServiceDetail(clusterId, serviceGroup);
181
+
182
+ if (serviceDetails) {
183
+ return {
184
+ name: serviceDetails.serviceName,
185
+ url: serviceDetails.get(),
186
+ };
187
+ }
188
+
189
+ return undefined;
190
+ },
191
+
192
+ /**
193
+ * Find a service based on the provided url.
194
+ * @param {string} url - Must be parsable by `Url`
195
+ * @returns {IServiceDetail} - ServiceDetail assocated with provided url
196
+ */
197
+ findServiceDetailFromUrl(url: string): IServiceDetail | undefined {
198
+ const serviceDetails = this._getAllServiceDetails();
199
+
200
+ return serviceDetails.find(({serviceUrls}) => {
201
+ for (const serviceUrl of serviceUrls) {
202
+ if (url.startsWith(serviceUrl.baseUrl)) {
203
+ return true;
204
+ }
205
+ }
206
+
207
+ return false;
208
+ });
209
+ },
210
+
211
+ /**
212
+ * Finds an allowed domain that matches a specific url.
213
+ *
214
+ * @param {string} url - The url to match the allowed domains against.
215
+ * @returns {string} - The matching allowed domain.
216
+ */
217
+ findAllowedDomain(url: string): string {
218
+ try {
219
+ const urlObj = new URL(url);
220
+
221
+ return this.allowedDomains.find((allowedDomain) => urlObj.host.includes(allowedDomain));
222
+ } catch {
223
+ // If the URL is invalid or can't be found, return undefined
224
+ return undefined;
225
+ }
226
+ },
227
+
228
+ /**
229
+ * Get a service url from the current services list by name. Return undefined
230
+ * if the service is not found.
231
+ * @param {string} clusterId
232
+ * @param {ServiceGroup} serviceGroup
233
+ * @returns {string | undefined}
234
+ */
235
+ get(clusterId: string, serviceGroup?: ServiceGroup): string | undefined {
236
+ const serviceDetail = this._getServiceDetail(clusterId, serviceGroup);
237
+
238
+ return serviceDetail ? serviceDetail.get() : undefined;
239
+ },
240
+
241
+ /**
242
+ * Get the current allowed domains list.
243
+ *
244
+ * @returns {Array<string>} - the current allowed domains list.
245
+ */
246
+ getAllowedDomains(): Array<string> {
247
+ return [...this.allowedDomains];
248
+ },
249
+
250
+ /**
251
+ * Mark a priority host service url as failed.
252
+ * This will mark the host associated with the
253
+ * `ServiceDetail` to be removed from the its
254
+ * respective host array, and then return the next
255
+ * viable host from the `ServiceDetail` host array,
256
+ * or the `ServiceDetail` default url if no other priority
257
+ * hosts are available, or if `noPriorityHosts` is set to
258
+ * `true`.
259
+ * @param {string} url
260
+ * @returns {string}
261
+ */
262
+ markFailedServiceUrl(url: string): string | undefined {
263
+ const serviceDetails = this._getAllServiceDetails();
264
+
265
+ const serviceDetailWithFailedHost = serviceDetails.find((serviceDetail: IServiceDetail) =>
266
+ serviceDetail.failHost(url)
267
+ );
268
+
269
+ // if we couldn't find the url we wanted to fail, return undefined
270
+ if (!serviceDetailWithFailedHost) {
271
+ return undefined;
272
+ }
273
+
274
+ return serviceDetailWithFailedHost.get();
275
+ },
276
+
277
+ /**
278
+ * Set the allowed domains for the catalog.
279
+ *
280
+ * @param {Array<string>} allowedDomains - allowed domains to be assigned.
281
+ * @returns {void}
282
+ */
283
+ setAllowedDomains(allowedDomains: Array<string>): void {
284
+ this.allowedDomains = [...allowedDomains];
285
+ },
286
+
287
+ /**
288
+ *
289
+ * @param {Array<string>} newAllowedDomains - new allowed domains to add to existing set of allowed domains
290
+ * @returns {void}
291
+ */
292
+ addAllowedDomains(newAllowedDomains: Array<string>): void {
293
+ this.allowedDomains = union(this.allowedDomains, newAllowedDomains);
294
+ },
295
+
296
+ /**
297
+ * Update the current list of `ServiceDetail`s against a provided
298
+ * service hostmap.
299
+ * @emits ServiceCatalog#preauthorized
300
+ * @emits ServiceCatalog#postauthorized
301
+ * @param {ServiceGroup} serviceGroup
302
+ * @param {Array<IServiceDetail>} serviceDetails
303
+ * @returns {void}
304
+ */
305
+ updateServiceGroups(serviceGroup: ServiceGroup, serviceDetails: Array<IServiceDetail>) {
306
+ const currentServiceDetails = this.serviceGroups[serviceGroup];
307
+
308
+ const unusedServicesDetails = currentServiceDetails.filter((serviceDetail) =>
309
+ serviceDetails.every(({id}) => id !== serviceDetail.id)
310
+ );
311
+
312
+ this._unloadServiceDetails(serviceGroup, unusedServicesDetails);
313
+
314
+ serviceDetails.forEach((serviceObj) => {
315
+ const serviceDetail = this._getServiceDetail(serviceObj.id, serviceGroup);
316
+
317
+ if (serviceDetail) {
318
+ serviceDetail.serviceUrls = serviceObj.serviceUrls || [];
319
+ } else {
320
+ this._loadServiceDetails(serviceGroup, [new ServiceDetail(serviceObj)]);
321
+ }
322
+ });
323
+
324
+ this.status[serviceGroup].ready = true;
325
+ this.trigger(serviceGroup);
326
+ },
327
+
328
+ /**
329
+ * Wait until the service catalog is available,
330
+ * or reject after a timeout of 60 seconds.
331
+ * @param {ServiceGroup} serviceGroup
332
+ * @param {number} [timeout] - in seconds
333
+ * @returns {Promise<void>}
334
+ */
335
+ waitForCatalog(serviceGroup: ServiceGroup, timeout?: number): Promise<void> {
336
+ return new Promise<void>((resolve, reject) => {
337
+ if (this.status[serviceGroup].ready) {
338
+ resolve();
339
+ }
340
+
341
+ const validatedTimeout = typeof timeout === 'number' && timeout >= 0 ? timeout : 60;
342
+
343
+ const timeoutTimer = setTimeout(
344
+ () =>
345
+ reject(
346
+ new Error(
347
+ `services: timeout occured while waiting for '${serviceGroup}' catalog to populate`
348
+ )
349
+ ),
350
+ validatedTimeout * 1000
351
+ );
352
+
353
+ this.once(serviceGroup, () => {
354
+ clearTimeout(timeoutTimer);
355
+ resolve();
356
+ });
357
+ });
358
+ },
359
+ });
360
+
361
+ export default ServiceCatalog;
@@ -0,0 +1,97 @@
1
+ import AmpState from 'ampersand-state';
2
+ import {ServiceUrl} from './types';
3
+
4
+ /**
5
+ * @class
6
+ */
7
+ const ServiceDetail = AmpState.extend({
8
+ namespace: 'ServiceDetail',
9
+
10
+ props: {
11
+ serviceUrls: ['array', false, () => []],
12
+ serviceName: ['string', true, undefined],
13
+ id: ['string', true, undefined],
14
+ },
15
+
16
+ /**
17
+ * Generate a host url based on the host
18
+ * uri provided.
19
+ * @param {ServiceUrl} serviceUrl
20
+ * @returns {string}
21
+ */
22
+ _generateHostUrl(serviceUrl: ServiceUrl): string {
23
+ const url = new URL(serviceUrl.baseUrl);
24
+
25
+ // setting url.hostname will not apply during Url.format(), set host via
26
+ // a string literal instead.
27
+ url.host = `${serviceUrl.host}${url.port ? `:${url.port}` : ''}`;
28
+
29
+ return url.href;
30
+ },
31
+
32
+ /**
33
+ * Get the current host url with the highest priority. This will only return a URL with a filtered host that has the
34
+ * `homeCluster` value set to `true`.
35
+ * @returns {string} - The priority host url.
36
+ */
37
+ _getPriorityHostUrl(): string {
38
+ // format of catalog ensures that array is sorted by highest priority
39
+ let priorityServiceUrl = this._searchForValidPriorityHost();
40
+
41
+ if (!priorityServiceUrl) {
42
+ this.serviceUrls = this.serviceUrls.map((serviceUrl) => {
43
+ serviceUrl.failed = false;
44
+
45
+ return serviceUrl;
46
+ });
47
+
48
+ priorityServiceUrl = this._searchForValidPriorityHost();
49
+ }
50
+
51
+ return priorityServiceUrl ? this._generateHostUrl(priorityServiceUrl) : '';
52
+ },
53
+
54
+ /**
55
+ * Searches for a valid service URL with a priority greater than 0 that has not failed.
56
+ * @returns {ServiceUrl | undefined} - The first valid service URL found, or undefined if none exist.
57
+ */
58
+ _searchForValidPriorityHost(): ServiceUrl | undefined {
59
+ return this.serviceUrls.find((serviceUrl) => serviceUrl.priority > 0 && !serviceUrl.failed);
60
+ },
61
+
62
+ /**
63
+ * Attempt to mark a host from this `ServiceDetail` as failed and return true
64
+ * if the provided url has a host that could be successfully marked as failed.
65
+ *
66
+ * @param {string} url
67
+ * @returns {boolean}
68
+ */
69
+ failHost(url: string): boolean {
70
+ const failedUrl = new URL(url);
71
+
72
+ const foundHost = this.serviceUrls.find((serviceUrl) => serviceUrl.host === failedUrl.host);
73
+
74
+ if (foundHost) {
75
+ foundHost.failed = true;
76
+ }
77
+
78
+ return foundHost !== undefined;
79
+ },
80
+
81
+ /**
82
+ * Generate a url using the host with the
83
+ * highest priority via host rendering.
84
+ *
85
+ * @returns {string} - The full service url.
86
+ */
87
+ get(): string {
88
+ // return empty string to indicate that no service url is available
89
+ if (!this.serviceUrls || this.serviceUrls.length === 0) {
90
+ return '';
91
+ }
92
+
93
+ return this._getPriorityHostUrl();
94
+ },
95
+ });
96
+
97
+ export default ServiceDetail;
@@ -0,0 +1,5 @@
1
+ export default {
2
+ hydra: 'https://api-usgov.webex.com/v1',
3
+ u2c: 'https://u2c.gov.ciscospark.com/u2c/api/v1',
4
+ sqdiscovery: 'https://ds.ciscospark.com/v1/region', // TODO: fedramp load balanced URL? this has been here for years as of now but now explicitly done
5
+ };