@webex/webex-core 3.10.0 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/credentials-config.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/auth.js +6 -8
- package/dist/interceptors/auth.js.map +1 -1
- package/dist/interceptors/default-options.js +6 -8
- package/dist/interceptors/default-options.js.map +1 -1
- package/dist/interceptors/embargo.js +6 -8
- package/dist/interceptors/embargo.js.map +1 -1
- package/dist/interceptors/network-timing.js +6 -8
- package/dist/interceptors/network-timing.js.map +1 -1
- package/dist/interceptors/payload-transformer.js +6 -8
- package/dist/interceptors/payload-transformer.js.map +1 -1
- package/dist/interceptors/proxy.js +7 -10
- package/dist/interceptors/proxy.js.map +1 -1
- package/dist/interceptors/rate-limit.js +7 -10
- package/dist/interceptors/rate-limit.js.map +1 -1
- package/dist/interceptors/redirect.js +9 -8
- package/dist/interceptors/redirect.js.map +1 -1
- package/dist/interceptors/request-event.js +6 -8
- package/dist/interceptors/request-event.js.map +1 -1
- package/dist/interceptors/request-logger.js +6 -8
- package/dist/interceptors/request-logger.js.map +1 -1
- package/dist/interceptors/request-timing.js +6 -8
- package/dist/interceptors/request-timing.js.map +1 -1
- package/dist/interceptors/response-logger.js +6 -8
- package/dist/interceptors/response-logger.js.map +1 -1
- package/dist/interceptors/user-agent.js +8 -11
- package/dist/interceptors/user-agent.js.map +1 -1
- package/dist/interceptors/webex-tracking-id.js +6 -8
- package/dist/interceptors/webex-tracking-id.js.map +1 -1
- package/dist/interceptors/webex-user-agent.js +7 -10
- package/dist/interceptors/webex-user-agent.js.map +1 -1
- package/dist/lib/batcher.js +1 -1
- package/dist/lib/batcher.js.map +1 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/credentials/credentials.js +4 -6
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/grant-errors.js +18 -26
- package/dist/lib/credentials/grant-errors.js.map +1 -1
- package/dist/lib/credentials/index.js.map +1 -1
- package/dist/lib/credentials/scope.js.map +1 -1
- package/dist/lib/credentials/token-collection.js.map +1 -1
- package/dist/lib/credentials/token.js +5 -5
- package/dist/lib/credentials/token.js.map +1 -1
- package/dist/lib/interceptors/hostmap.js +6 -8
- package/dist/lib/interceptors/hostmap.js.map +1 -1
- package/dist/lib/interceptors/server-error.js +6 -8
- package/dist/lib/interceptors/server-error.js.map +1 -1
- package/dist/lib/interceptors/service.js +6 -8
- package/dist/lib/interceptors/service.js.map +1 -1
- package/dist/lib/metrics.js.map +1 -1
- package/dist/lib/page.js +5 -6
- package/dist/lib/page.js.map +1 -1
- package/dist/lib/services/index.js.map +1 -1
- package/dist/lib/services/service-catalog.js +3 -3
- package/dist/lib/services/service-catalog.js.map +1 -1
- package/dist/lib/services/service-fed-ramp.js.map +1 -1
- package/dist/lib/services/service-host.js +1 -2
- package/dist/lib/services/service-host.js.map +1 -1
- package/dist/lib/services/service-registry.js +1 -2
- package/dist/lib/services/service-registry.js.map +1 -1
- package/dist/lib/services/service-state.js +1 -2
- package/dist/lib/services/service-state.js.map +1 -1
- package/dist/lib/services/service-url.js +11 -1
- package/dist/lib/services/service-url.js.map +1 -1
- package/dist/lib/services/services.js +485 -127
- package/dist/lib/services/services.js.map +1 -1
- package/dist/lib/services-v2/index.js.map +1 -1
- package/dist/lib/services-v2/metrics.js.map +1 -1
- package/dist/lib/services-v2/service-catalog.js +7 -7
- package/dist/lib/services-v2/service-catalog.js.map +1 -1
- package/dist/lib/services-v2/service-detail.js.map +1 -1
- package/dist/lib/services-v2/service-fed-ramp.js.map +1 -1
- package/dist/lib/services-v2/services-v2.js +379 -51
- package/dist/lib/services-v2/services-v2.js.map +1 -1
- package/dist/lib/services-v2/types.js.map +1 -1
- package/dist/lib/stateless-webex-plugin.js +3 -4
- package/dist/lib/stateless-webex-plugin.js.map +1 -1
- package/dist/lib/storage/decorators.js.map +1 -1
- package/dist/lib/storage/errors.js +7 -9
- package/dist/lib/storage/errors.js.map +1 -1
- package/dist/lib/storage/index.js.map +1 -1
- package/dist/lib/storage/make-webex-plugin-store.js +14 -5
- package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
- package/dist/lib/storage/make-webex-store.js +13 -5
- package/dist/lib/storage/make-webex-store.js.map +1 -1
- package/dist/lib/storage/memory-store-adapter.js.map +1 -1
- package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-http-error.js +8 -11
- package/dist/lib/webex-http-error.js.map +1 -1
- package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-plugin.js.map +1 -1
- package/dist/plugins/logger.js +1 -1
- package/dist/plugins/logger.js.map +1 -1
- package/dist/webex-core.js +11 -11
- package/dist/webex-core.js.map +1 -1
- package/dist/webex-internal-core.js.map +1 -1
- package/package.json +13 -13
- package/src/config.js +15 -0
- package/src/interceptors/redirect.js +4 -0
- package/src/lib/services/service-url.js +9 -1
- package/src/lib/services/services.js +315 -7
- package/src/lib/services-v2/index.ts +0 -1
- package/src/lib/services-v2/service-catalog.ts +4 -4
- package/src/lib/services-v2/services-v2.ts +307 -7
- package/src/lib/services-v2/types.ts +13 -0
- package/test/fixtures/host-catalog-v2.ts +1 -1
- package/test/integration/spec/services/service-catalog.js +10 -4
- package/test/integration/spec/services/services.js +65 -9
- package/test/integration/spec/services-v2/service-catalog.js +2 -2
- package/test/integration/spec/services-v2/services-v2.js +56 -6
- package/test/unit/spec/interceptors/redirect.js +98 -0
- package/test/unit/spec/services/service-url.js +110 -0
- package/test/unit/spec/services/services.js +411 -2
- package/test/unit/spec/services-v2/services-v2.ts +316 -0
|
@@ -20,6 +20,8 @@ export const DEFAULT_CLUSTER_SERVICE = 'identityLookup';
|
|
|
20
20
|
const CLUSTER_SERVICE = process.env.WEBEX_CONVERSATION_CLUSTER_SERVICE || DEFAULT_CLUSTER_SERVICE;
|
|
21
21
|
const DEFAULT_CLUSTER_IDENTIFIER =
|
|
22
22
|
process.env.WEBEX_CONVERSATION_DEFAULT_CLUSTER || `${DEFAULT_CLUSTER}:${CLUSTER_SERVICE}`;
|
|
23
|
+
const CATALOG_CACHE_KEY_V1 = 'services.v1.u2cHostMap';
|
|
24
|
+
const CATALOG_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
23
25
|
|
|
24
26
|
/* eslint-disable no-underscore-dangle */
|
|
25
27
|
/**
|
|
@@ -61,6 +63,9 @@ const Services = WebexPlugin.extend({
|
|
|
61
63
|
|
|
62
64
|
_hostCatalog: null,
|
|
63
65
|
|
|
66
|
+
// Map of active cluster ids per service, e.g. { wdm: 'urn:TEAM:ap-southeast-2_m:wdm' }
|
|
67
|
+
_activeServices: {},
|
|
68
|
+
|
|
64
69
|
/**
|
|
65
70
|
* Get the registry associated with this webex instance.
|
|
66
71
|
*
|
|
@@ -93,6 +98,49 @@ const Services = WebexPlugin.extend({
|
|
|
93
98
|
return this._catalogs.get(this.webex);
|
|
94
99
|
},
|
|
95
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Safely access localStorage if available; returns the Storage or null.
|
|
103
|
+
* @returns {Storage|null}
|
|
104
|
+
*/
|
|
105
|
+
_getLocalStorageSafe() {
|
|
106
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
107
|
+
return window.localStorage;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return null;
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Determine the intended preauth selection based on the current context.
|
|
115
|
+
* @param {string|undefined} currentOrgId
|
|
116
|
+
* @returns {{selectionType: string, selectionValue: string}}
|
|
117
|
+
*/
|
|
118
|
+
getIntendedPreauthSelection(currentOrgId) {
|
|
119
|
+
if (this.webex.credentials?.canAuthorize) {
|
|
120
|
+
if (currentOrgId) {
|
|
121
|
+
return {
|
|
122
|
+
selectionType: 'orgId',
|
|
123
|
+
selectionValue: currentOrgId,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const emailConfig = this.webex.config && this.webex.config.email;
|
|
129
|
+
|
|
130
|
+
if (typeof emailConfig === 'string' && emailConfig.trim()) {
|
|
131
|
+
return {
|
|
132
|
+
selectionType: 'emailhash',
|
|
133
|
+
selectionValue: sha256(emailConfig.toLowerCase()).toString(),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// fall back to proximity mode when no orgId or email available
|
|
138
|
+
return {
|
|
139
|
+
selectionType: 'mode',
|
|
140
|
+
selectionValue: 'DEFAULT_BY_PROXIMITY',
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
|
|
96
144
|
/**
|
|
97
145
|
* Get a service url from the current services list by name
|
|
98
146
|
* from the associated instance catalog.
|
|
@@ -160,6 +208,50 @@ const Services = WebexPlugin.extend({
|
|
|
160
208
|
return catalog.markFailedUrl(url, noPriorityHosts);
|
|
161
209
|
},
|
|
162
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Get all Mobius cluster host entries from the legacy host catalog.
|
|
213
|
+
* @returns {Array<{host: string, id: string, ttl: number, priority: number}>}
|
|
214
|
+
*/
|
|
215
|
+
getMobiusClusters() {
|
|
216
|
+
this.logger.info('services: fetching mobius clusters');
|
|
217
|
+
const clusters = [];
|
|
218
|
+
const hostCatalog = this._hostCatalog || {};
|
|
219
|
+
|
|
220
|
+
Object.entries(hostCatalog).forEach(([host, entries]) => {
|
|
221
|
+
(entries || []).forEach((entry) => {
|
|
222
|
+
if (typeof entry?.id === 'string' && entry.id.endsWith(':mobius')) {
|
|
223
|
+
// Ensure host is included; prefer entry.host if present, else use the map key
|
|
224
|
+
const withHost = entry.host ? entry.host : host;
|
|
225
|
+
// Skip duplicates for the same host
|
|
226
|
+
if (!clusters.find((c) => c && c.host === withHost)) {
|
|
227
|
+
clusters.push({...entry, host: withHost});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return clusters;
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check is valid host from the legacy host catalog.
|
|
238
|
+
* @param {string} host
|
|
239
|
+
* @returns {Boolean}
|
|
240
|
+
*/
|
|
241
|
+
isValidHost(host) {
|
|
242
|
+
const hostCatalog = this._hostCatalog || {};
|
|
243
|
+
|
|
244
|
+
return !!hostCatalog[host]?.length;
|
|
245
|
+
},
|
|
246
|
+
/**
|
|
247
|
+
* Merge provided active cluster mappings into current state.
|
|
248
|
+
* @param {Record<string,string>} activeServices
|
|
249
|
+
* @returns {void}
|
|
250
|
+
*/
|
|
251
|
+
_updateActiveServices(activeServices) {
|
|
252
|
+
this._activeServices = {...this._activeServices, ...activeServices};
|
|
253
|
+
},
|
|
254
|
+
|
|
163
255
|
/**
|
|
164
256
|
* saves all the services from the pre and post catalog service
|
|
165
257
|
* @param {Object} serviceUrls
|
|
@@ -191,7 +283,7 @@ const Services = WebexPlugin.extend({
|
|
|
191
283
|
* @param {string} [param.token] - used for signin catalog
|
|
192
284
|
* @returns {Promise<object>}
|
|
193
285
|
*/
|
|
194
|
-
updateServices({from, query, token, forceRefresh} = {}) {
|
|
286
|
+
async updateServices({from, query, token, forceRefresh} = {}) {
|
|
195
287
|
const catalog = this._getCatalog();
|
|
196
288
|
let formattedQuery;
|
|
197
289
|
let serviceGroup;
|
|
@@ -245,7 +337,20 @@ const Services = WebexPlugin.extend({
|
|
|
245
337
|
forceRefresh,
|
|
246
338
|
})
|
|
247
339
|
.then((serviceHostMap) => {
|
|
248
|
-
|
|
340
|
+
const formattedServiceHostMap = this._formatReceivedHostmap(serviceHostMap);
|
|
341
|
+
// Build selection metadata for caching discrimination
|
|
342
|
+
let selectionMeta;
|
|
343
|
+
if (serviceGroup === 'preauth' || serviceGroup === 'signin') {
|
|
344
|
+
const key = formattedQuery && Object.keys(formattedQuery || {})[0];
|
|
345
|
+
if (key) {
|
|
346
|
+
selectionMeta = {
|
|
347
|
+
selectionType: key,
|
|
348
|
+
selectionValue: formattedQuery[key],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
this._cacheCatalog(serviceGroup, serviceHostMap, selectionMeta);
|
|
353
|
+
catalog.updateServiceUrls(serviceGroup, formattedServiceHostMap);
|
|
249
354
|
this.updateCredentialsConfig();
|
|
250
355
|
catalog.status[serviceGroup].collecting = false;
|
|
251
356
|
})
|
|
@@ -473,10 +578,14 @@ const Services = WebexPlugin.extend({
|
|
|
473
578
|
({countryCode, timezone} = clientRegionInfo);
|
|
474
579
|
}
|
|
475
580
|
|
|
476
|
-
// Send the user activation request
|
|
581
|
+
// Send the user activation request.
|
|
582
|
+
// Use user-onboarding service if configured, otherwise use license service.
|
|
583
|
+
const useUserOnboarding =
|
|
584
|
+
this.webex.config.services?.useUserOnboardingServiceForActivations;
|
|
585
|
+
|
|
477
586
|
return this.request({
|
|
478
|
-
service: 'license',
|
|
479
|
-
resource: 'users/activations',
|
|
587
|
+
service: useUserOnboarding ? 'user-onboarding' : 'license',
|
|
588
|
+
resource: useUserOnboarding ? 'api/v1/users/activations' : 'users/activations',
|
|
480
589
|
method: 'POST',
|
|
481
590
|
headers: {
|
|
482
591
|
accept: 'application/json',
|
|
@@ -958,7 +1067,197 @@ const Services = WebexPlugin.extend({
|
|
|
958
1067
|
|
|
959
1068
|
return this.webex.internal.newMetrics.callDiagnosticLatencies
|
|
960
1069
|
.measureLatency(() => this.request(requestObject), 'internal.get.u2c.time')
|
|
961
|
-
.then(({body}) =>
|
|
1070
|
+
.then(({body}) => body);
|
|
1071
|
+
},
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* Cache the catalog in the bounded storage.
|
|
1075
|
+
* @param {string} serviceGroup - preauth, signin, postauth
|
|
1076
|
+
* @param {object} hostMap - The hostmap to cache
|
|
1077
|
+
* @param {object} [meta] - Optional selection metadata used to validate cache reuse
|
|
1078
|
+
* @returns {Promise<void>}
|
|
1079
|
+
*
|
|
1080
|
+
*/
|
|
1081
|
+
async _cacheCatalog(serviceGroup, hostMap, meta) {
|
|
1082
|
+
let current = {};
|
|
1083
|
+
let orgId;
|
|
1084
|
+
try {
|
|
1085
|
+
// Respect calling.cacheU2C toggle; if disabled, skip writing cache
|
|
1086
|
+
if (!this.webex.config?.calling?.cacheU2C) {
|
|
1087
|
+
this.logger.info(`services: skipping cache write for ${serviceGroup} as per the config`);
|
|
1088
|
+
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// Persist to localStorage to survive browser refresh
|
|
1093
|
+
try {
|
|
1094
|
+
const ls = this._getLocalStorageSafe();
|
|
1095
|
+
const cachedJson = ls ? ls.getItem(CATALOG_CACHE_KEY_V1) : null;
|
|
1096
|
+
current = cachedJson ? JSON.parse(cachedJson) : {};
|
|
1097
|
+
} catch (e) {
|
|
1098
|
+
current = {};
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
try {
|
|
1102
|
+
const {credentials} = this.webex;
|
|
1103
|
+
orgId = credentials.getOrgId();
|
|
1104
|
+
} catch (e) {
|
|
1105
|
+
orgId = current.orgId;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// Capture environment fingerprint to invalidate cache across env changes
|
|
1109
|
+
let {env} = current;
|
|
1110
|
+
const fedramp = !!this.webex?.config?.fedramp;
|
|
1111
|
+
const u2cDiscoveryUrl = this.webex?.config?.services?.discovery?.u2c;
|
|
1112
|
+
env = {fedramp, u2cDiscoveryUrl};
|
|
1113
|
+
|
|
1114
|
+
const updated = {
|
|
1115
|
+
...current,
|
|
1116
|
+
orgId: orgId || current.orgId,
|
|
1117
|
+
env: env || current.env,
|
|
1118
|
+
// When selection meta is provided, store as an object; otherwise keep legacy shape
|
|
1119
|
+
[serviceGroup]: meta ? {hostMap, meta} : hostMap,
|
|
1120
|
+
cachedAt: Date.now(),
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
const ls = this._getLocalStorageSafe();
|
|
1124
|
+
if (ls) {
|
|
1125
|
+
ls.setItem(CATALOG_CACHE_KEY_V1, JSON.stringify(updated));
|
|
1126
|
+
}
|
|
1127
|
+
} catch (error) {
|
|
1128
|
+
this.logger.warn('services: error caching catalog', error);
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* Load the catalog from cache and hydrate the in-memory ServiceCatalog.
|
|
1134
|
+
* @returns {Promise<boolean>} true if cache was loaded, false otherwise
|
|
1135
|
+
*/
|
|
1136
|
+
async _loadCatalogFromCache() {
|
|
1137
|
+
let currentOrgId;
|
|
1138
|
+
try {
|
|
1139
|
+
// Respect calling.cacheU2C toggle; if disabled, skip using cache
|
|
1140
|
+
if (!this.webex.config?.calling?.cacheU2C) {
|
|
1141
|
+
this.logger.info('services: skipping cache warm-up as per the cache config');
|
|
1142
|
+
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
const ls = this._getLocalStorageSafe();
|
|
1147
|
+
if (!ls) {
|
|
1148
|
+
this.logger.info('services: skipping cache warm-up as no localStorage is available');
|
|
1149
|
+
|
|
1150
|
+
return false;
|
|
1151
|
+
}
|
|
1152
|
+
const cachedJson = ls.getItem(CATALOG_CACHE_KEY_V1);
|
|
1153
|
+
const cached = cachedJson ? JSON.parse(cachedJson) : undefined;
|
|
1154
|
+
if (!cached) {
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
// TTL enforcement: clear if older than 24 hours
|
|
1158
|
+
const cachedAt = Number(cached.cachedAt) || 0;
|
|
1159
|
+
if (!cachedAt || Date.now() - cachedAt > CATALOG_TTL_MS) {
|
|
1160
|
+
this.clearCatalogCache();
|
|
1161
|
+
|
|
1162
|
+
return false;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// If authorized, ensure cached org matches
|
|
1166
|
+
try {
|
|
1167
|
+
if (this.webex.credentials?.canAuthorize) {
|
|
1168
|
+
const {credentials} = this.webex;
|
|
1169
|
+
currentOrgId = credentials.getOrgId();
|
|
1170
|
+
if (cached.orgId && cached.orgId !== currentOrgId) {
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
} catch (e) {
|
|
1175
|
+
this.logger.warn('services: error checking orgId', e);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// Ensure cached environment matches current environment
|
|
1179
|
+
|
|
1180
|
+
const fedramp = !!this.webex.config?.fedramp;
|
|
1181
|
+
const u2cDiscoveryUrl = this.webex.config?.services?.discovery?.u2c;
|
|
1182
|
+
const currentEnv = {fedramp, u2cDiscoveryUrl};
|
|
1183
|
+
if (cached.env) {
|
|
1184
|
+
const sameEnv =
|
|
1185
|
+
cached.env.fedramp === currentEnv.fedramp &&
|
|
1186
|
+
cached.env.u2cDiscoveryUrl === currentEnv.u2cDiscoveryUrl;
|
|
1187
|
+
if (!sameEnv) {
|
|
1188
|
+
this.logger.info('services: skipping cache warm due to environment mismatch');
|
|
1189
|
+
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
const catalog = this._getCatalog();
|
|
1195
|
+
|
|
1196
|
+
// Apply any cached groups (with preauth selection validation if available)
|
|
1197
|
+
const groups = ['preauth', 'signin', 'postauth'];
|
|
1198
|
+
groups.forEach((serviceGroup) => {
|
|
1199
|
+
const cachedGroup = cached[serviceGroup];
|
|
1200
|
+
if (!cachedGroup) {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// Support legacy (hostMap) and new ({hostMap, meta}) shapes
|
|
1205
|
+
const hostMap = cachedGroup && cachedGroup.hostMap ? cachedGroup.hostMap : cachedGroup;
|
|
1206
|
+
const meta = cachedGroup?.meta;
|
|
1207
|
+
|
|
1208
|
+
if (serviceGroup === 'preauth' && meta) {
|
|
1209
|
+
// For proximity-based selection, always fetch fresh to respect IP/region changes
|
|
1210
|
+
if (meta.selectionType === 'mode') {
|
|
1211
|
+
this.logger.info('services: skipping preauth cache warm for proximity mode');
|
|
1212
|
+
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
const intended = this.getIntendedPreauthSelection(currentOrgId);
|
|
1217
|
+
const matches =
|
|
1218
|
+
intended &&
|
|
1219
|
+
intended.selectionType === meta.selectionType &&
|
|
1220
|
+
intended.selectionValue === meta.selectionValue;
|
|
1221
|
+
|
|
1222
|
+
if (!matches) {
|
|
1223
|
+
this.logger.info('services: skipping preauth cache warm due to selection mismatch');
|
|
1224
|
+
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
if (hostMap) {
|
|
1230
|
+
const formatted = this._formatReceivedHostmap(hostMap);
|
|
1231
|
+
catalog.updateServiceUrls(serviceGroup, formatted);
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
// Align credentials against warmed catalog
|
|
1236
|
+
this.updateCredentialsConfig();
|
|
1237
|
+
|
|
1238
|
+
return true;
|
|
1239
|
+
} catch (e) {
|
|
1240
|
+
this.logger.warn('services: error loading catalog from cache', e);
|
|
1241
|
+
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
},
|
|
1245
|
+
|
|
1246
|
+
/**
|
|
1247
|
+
* Clear the catalog cache from the bounded storage.
|
|
1248
|
+
* @returns {Promise<void>}
|
|
1249
|
+
*/
|
|
1250
|
+
clearCatalogCache() {
|
|
1251
|
+
try {
|
|
1252
|
+
const ls = this._getLocalStorageSafe();
|
|
1253
|
+
if (ls) {
|
|
1254
|
+
ls.removeItem(CATALOG_CACHE_KEY_V1);
|
|
1255
|
+
}
|
|
1256
|
+
} catch (e) {
|
|
1257
|
+
this.logger.warn('services: error clearing catalog cache', e);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
return Promise.resolve();
|
|
962
1261
|
},
|
|
963
1262
|
|
|
964
1263
|
/**
|
|
@@ -1038,6 +1337,7 @@ const Services = WebexPlugin.extend({
|
|
|
1038
1337
|
// Validate if the token is authorized.
|
|
1039
1338
|
if (credentials.canAuthorize) {
|
|
1040
1339
|
// Attempt to collect the postauth catalog.
|
|
1340
|
+
|
|
1041
1341
|
return this.updateServices().catch(() => {
|
|
1042
1342
|
this.initFailed = true;
|
|
1043
1343
|
this.logger.warn('services: cannot retrieve postauth catalog');
|
|
@@ -1073,7 +1373,15 @@ const Services = WebexPlugin.extend({
|
|
|
1073
1373
|
|
|
1074
1374
|
// wait for webex instance to be ready before attempting
|
|
1075
1375
|
// to update the service catalogs
|
|
1076
|
-
this
|
|
1376
|
+
// this can cause a race condition because credentials may
|
|
1377
|
+
// not be valid when services is initialized
|
|
1378
|
+
this.listenToOnce(this.webex, 'ready', async () => {
|
|
1379
|
+
const cachedCatalog = await this._loadCatalogFromCache();
|
|
1380
|
+
if (cachedCatalog) {
|
|
1381
|
+
catalog.isReady = true;
|
|
1382
|
+
|
|
1383
|
+
return; // skip initServiceCatalogs() on reload when cache exists
|
|
1384
|
+
}
|
|
1077
1385
|
const {supertoken} = this.webex.credentials;
|
|
1078
1386
|
// Validate if the supertoken exists.
|
|
1079
1387
|
if (supertoken && supertoken.access_token) {
|
|
@@ -119,7 +119,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
119
119
|
// declare namespaces outside of loop
|
|
120
120
|
let existingService: IServiceDetail | undefined;
|
|
121
121
|
|
|
122
|
-
serviceDetails
|
|
122
|
+
serviceDetails?.forEach((service) => {
|
|
123
123
|
existingService = this._getServiceDetail(service.id, serviceGroup);
|
|
124
124
|
|
|
125
125
|
if (existingService) {
|
|
@@ -311,13 +311,13 @@ const ServiceCatalog = AmpState.extend({
|
|
|
311
311
|
) {
|
|
312
312
|
const currentServiceDetails = this.serviceGroups[serviceGroup];
|
|
313
313
|
|
|
314
|
-
const unusedServicesDetails = currentServiceDetails
|
|
315
|
-
serviceDetails
|
|
314
|
+
const unusedServicesDetails = currentServiceDetails?.filter((serviceDetail) =>
|
|
315
|
+
serviceDetails?.every(({id}) => id !== serviceDetail.id)
|
|
316
316
|
);
|
|
317
317
|
|
|
318
318
|
this._unloadServiceDetails(serviceGroup, unusedServicesDetails);
|
|
319
319
|
|
|
320
|
-
serviceDetails
|
|
320
|
+
serviceDetails?.forEach((serviceObj) => {
|
|
321
321
|
const serviceDetail = this._getServiceDetail(serviceObj.id, serviceGroup);
|
|
322
322
|
serviceObj?.serviceUrls?.sort((a, b) => {
|
|
323
323
|
if (a.priority < 0 && b.priority < 0) return 0;
|