@webex/webex-core 3.12.0-task-refactor.1 → 3.12.0-webex-services-ready.2
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 +7 -0
- package/dist/config.js.map +1 -1
- package/dist/credentials-config.js +12 -0
- package/dist/credentials-config.js.map +1 -1
- package/dist/interceptors/redirect.js +1 -1
- package/dist/interceptors/redirect.js.map +1 -1
- package/dist/lib/batcher.js +23 -7
- package/dist/lib/batcher.js.map +1 -1
- package/dist/lib/credentials/credentials.js +48 -4
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/token.js +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 +583 -94
- package/dist/lib/services/services.js.map +1 -1
- package/dist/lib/services-v2/services-v2.js +507 -41
- package/dist/lib/services-v2/services-v2.js.map +1 -1
- package/dist/lib/services-v2/types.js.map +1 -1
- package/dist/plugins/logger.js +1 -1
- package/dist/webex-core.js +2 -2
- package/dist/webex-core.js.map +1 -1
- package/package.json +13 -13
- package/src/config.js +7 -0
- package/src/credentials-config.js +13 -0
- package/src/interceptors/redirect.js +4 -1
- package/src/lib/batcher.js +25 -10
- package/src/lib/credentials/credentials.js +50 -3
- package/src/lib/services/service-url.js +9 -1
- package/src/lib/services/services.js +433 -6
- package/src/lib/services-v2/services-v2.ts +417 -2
- package/src/lib/services-v2/types.ts +5 -0
- package/test/integration/spec/services/service-catalog.js +16 -11
- package/test/integration/spec/services/services.js +58 -9
- package/test/integration/spec/services-v2/services-v2.js +49 -6
- package/test/unit/spec/credentials/credentials.js +133 -2
- package/test/unit/spec/lib/batcher.js +56 -0
- package/test/unit/spec/services/service-url.js +110 -0
- package/test/unit/spec/services/services.js +692 -12
- package/test/unit/spec/services-v2/services-v2.ts +539 -0
- package/test/unit/spec/webex-core.js +2 -0
- package/test/unit/spec/webex-internal-core.js +2 -0
|
@@ -11,6 +11,8 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
11
11
|
value: true
|
|
12
12
|
});
|
|
13
13
|
exports.default = exports.DEFAULT_CLUSTER_SERVICE = exports.DEFAULT_CLUSTER = void 0;
|
|
14
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
|
|
15
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
|
|
14
16
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
|
|
15
17
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
16
18
|
var _weakMap = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/weak-map"));
|
|
@@ -18,6 +20,8 @@ var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/ar
|
|
|
18
20
|
var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
|
|
19
21
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
20
22
|
var _values = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/values"));
|
|
23
|
+
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
|
|
24
|
+
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
|
|
21
25
|
var _sha = _interopRequireDefault(require("crypto-js/sha256"));
|
|
22
26
|
var _lodash = require("lodash");
|
|
23
27
|
var _webexPlugin = _interopRequireDefault(require("../webex-plugin"));
|
|
@@ -35,6 +39,14 @@ var DEFAULT_CLUSTER = exports.DEFAULT_CLUSTER = 'urn:TEAM:us-east-2_a';
|
|
|
35
39
|
var DEFAULT_CLUSTER_SERVICE = exports.DEFAULT_CLUSTER_SERVICE = 'identityLookup';
|
|
36
40
|
var CLUSTER_SERVICE = process.env.WEBEX_CONVERSATION_CLUSTER_SERVICE || DEFAULT_CLUSTER_SERVICE;
|
|
37
41
|
var DEFAULT_CLUSTER_IDENTIFIER = process.env.WEBEX_CONVERSATION_DEFAULT_CLUSTER || "".concat(DEFAULT_CLUSTER, ":").concat(CLUSTER_SERVICE);
|
|
42
|
+
var CATALOG_CACHE_KEY_V2 = 'services.v2.u2cHostMap';
|
|
43
|
+
var CATALOG_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
44
|
+
|
|
45
|
+
// Maximum time we will wait for the initial catalog collection before letting
|
|
46
|
+
// `services.ready` (and therefore `webex.ready`) fire anyway. A hung request
|
|
47
|
+
// must never leave the app on a permanent spinner - past this point downstream
|
|
48
|
+
// consumers must fall through to their normal error/login paths.
|
|
49
|
+
var SERVICES_INIT_TIMEOUT_MS = 15000;
|
|
38
50
|
|
|
39
51
|
/* eslint-disable no-underscore-dangle */
|
|
40
52
|
/**
|
|
@@ -46,6 +58,21 @@ var Services = _webexPlugin.default.extend({
|
|
|
46
58
|
validateDomains: ['boolean', false, true],
|
|
47
59
|
initFailed: ['boolean', false, false]
|
|
48
60
|
},
|
|
61
|
+
session: {
|
|
62
|
+
/**
|
|
63
|
+
* Becomes `true` once the initial catalog collection has completed
|
|
64
|
+
* (successfully or otherwise) and any in-flight credentials refresh has
|
|
65
|
+
* settled. Blocks `webex.ready` so consumers can rely on `webex.ready`
|
|
66
|
+
* implying "catalogs populated AND credential state stable".
|
|
67
|
+
* @instance
|
|
68
|
+
* @memberof Services
|
|
69
|
+
* @type {boolean}
|
|
70
|
+
*/
|
|
71
|
+
ready: {
|
|
72
|
+
default: false,
|
|
73
|
+
type: 'boolean'
|
|
74
|
+
}
|
|
75
|
+
},
|
|
49
76
|
_catalogs: new _weakMap.default(),
|
|
50
77
|
_activeServices: {},
|
|
51
78
|
_services: [],
|
|
@@ -58,6 +85,45 @@ var Services = _webexPlugin.default.extend({
|
|
|
58
85
|
_getCatalog: function _getCatalog() {
|
|
59
86
|
return this._catalogs.get(this.webex);
|
|
60
87
|
},
|
|
88
|
+
/**
|
|
89
|
+
* Safely access localStorage if available; returns the Storage or null.
|
|
90
|
+
* @returns {Storage | null}
|
|
91
|
+
*/
|
|
92
|
+
_getLocalStorageSafe: function _getLocalStorageSafe() {
|
|
93
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
94
|
+
return window.localStorage;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
},
|
|
98
|
+
/**
|
|
99
|
+
* Determine the intended preauth selection based on the current context.
|
|
100
|
+
* @param {string} [currentOrgId]
|
|
101
|
+
* @returns {{selectionType: string, selectionValue: string}}
|
|
102
|
+
*/
|
|
103
|
+
getIntendedPreauthSelection: function getIntendedPreauthSelection(currentOrgId) {
|
|
104
|
+
var _this$webex$credentia;
|
|
105
|
+
if ((_this$webex$credentia = this.webex.credentials) !== null && _this$webex$credentia !== void 0 && _this$webex$credentia.canAuthorize) {
|
|
106
|
+
if (currentOrgId) {
|
|
107
|
+
return {
|
|
108
|
+
selectionType: 'orgId',
|
|
109
|
+
selectionValue: currentOrgId
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
var emailConfig = this.webex.config && this.webex.config.email;
|
|
114
|
+
if (typeof emailConfig === 'string' && emailConfig.trim()) {
|
|
115
|
+
return {
|
|
116
|
+
selectionType: 'emailhash',
|
|
117
|
+
selectionValue: (0, _sha.default)(emailConfig.toLowerCase()).toString()
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// fall back to proximity mode when no orgId or email available
|
|
122
|
+
return {
|
|
123
|
+
selectionType: 'mode',
|
|
124
|
+
selectionValue: 'DEFAULT_BY_PROXIMITY'
|
|
125
|
+
};
|
|
126
|
+
},
|
|
61
127
|
/**
|
|
62
128
|
* Get a service url from the current services list by name
|
|
63
129
|
* from the associated instance catalog.
|
|
@@ -104,6 +170,7 @@ var Services = _webexPlugin.default.extend({
|
|
|
104
170
|
* @returns {Array<ServiceHost>} - An array of `ServiceHost` objects.
|
|
105
171
|
*/
|
|
106
172
|
getMobiusClusters: function getMobiusClusters() {
|
|
173
|
+
this.logger.info('services: fetching mobius clusters');
|
|
107
174
|
var clusters = [];
|
|
108
175
|
var services = this._services || [];
|
|
109
176
|
services.filter(function (service) {
|
|
@@ -140,6 +207,24 @@ var Services = _webexPlugin.default.extend({
|
|
|
140
207
|
});
|
|
141
208
|
});
|
|
142
209
|
},
|
|
210
|
+
/**
|
|
211
|
+
* Checks if the current environment is an integration (INT) environment
|
|
212
|
+
* by examining the u2c discovery URL from webex config.
|
|
213
|
+
* INT environments use discovery URLs containing 'intb' (e.g., u2c-intb.ciscospark.com).
|
|
214
|
+
* @returns {boolean} True if INT environment, false otherwise
|
|
215
|
+
*/
|
|
216
|
+
isIntegrationEnvironment: function isIntegrationEnvironment() {
|
|
217
|
+
try {
|
|
218
|
+
var _this$webex, _this$webex$config, _this$webex$config$se, _this$webex$config$se2;
|
|
219
|
+
var u2cUrl = ((_this$webex = this.webex) === null || _this$webex === void 0 ? void 0 : (_this$webex$config = _this$webex.config) === null || _this$webex$config === void 0 ? void 0 : (_this$webex$config$se = _this$webex$config.services) === null || _this$webex$config$se === void 0 ? void 0 : (_this$webex$config$se2 = _this$webex$config$se.discovery) === null || _this$webex$config$se2 === void 0 ? void 0 : _this$webex$config$se2.u2c) || '';
|
|
220
|
+
var isInt = u2cUrl.includes('intb');
|
|
221
|
+
this.logger.info("services: isIntegrationEnvironment: ".concat(isInt));
|
|
222
|
+
return isInt;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
this.logger.error('services: failed to determine integration environment', error);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
},
|
|
143
228
|
/**
|
|
144
229
|
* saves all the services from the pre and post catalog service
|
|
145
230
|
* @param {ActiveServices} activeServices
|
|
@@ -222,6 +307,18 @@ var Services = _webexPlugin.default.extend({
|
|
|
222
307
|
forceRefresh: forceRefresh
|
|
223
308
|
}).then(function (serviceHostMap) {
|
|
224
309
|
catalog.updateServiceGroups(serviceGroup, serviceHostMap === null || serviceHostMap === void 0 ? void 0 : serviceHostMap.services, serviceHostMap === null || serviceHostMap === void 0 ? void 0 : serviceHostMap.timestamp);
|
|
310
|
+
// Build selection metadata for caching discrimination (preauth/signin)
|
|
311
|
+
var selectionMeta;
|
|
312
|
+
if (serviceGroup === 'preauth' || serviceGroup === 'signin') {
|
|
313
|
+
var key = formattedQuery && (0, _keys.default)(formattedQuery || {})[0];
|
|
314
|
+
if (key) {
|
|
315
|
+
selectionMeta = {
|
|
316
|
+
selectionType: key,
|
|
317
|
+
selectionValue: formattedQuery[key]
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
_this._cacheCatalog(serviceGroup, serviceHostMap, selectionMeta);
|
|
225
322
|
_this.updateCredentialsConfig();
|
|
226
323
|
catalog.status[serviceGroup].collecting = false;
|
|
227
324
|
}).catch(function (error) {
|
|
@@ -298,9 +395,9 @@ var Services = _webexPlugin.default.extend({
|
|
|
298
395
|
|
|
299
396
|
// Destructure the client authorization details.
|
|
300
397
|
/* eslint-disable camelcase */
|
|
301
|
-
var _this$webex$
|
|
302
|
-
client_id = _this$webex$
|
|
303
|
-
client_secret = _this$webex$
|
|
398
|
+
var _this$webex$credentia2 = this.webex.credentials.config,
|
|
399
|
+
client_id = _this$webex$credentia2.client_id,
|
|
400
|
+
client_secret = _this$webex$credentia2.client_secret;
|
|
304
401
|
|
|
305
402
|
// Validate that client authentication details exist.
|
|
306
403
|
if (!client_id || !client_secret) {
|
|
@@ -876,6 +973,213 @@ var Services = _webexPlugin.default.extend({
|
|
|
876
973
|
}
|
|
877
974
|
return url.replace(data.defaultUrl, data.priorityUrl);
|
|
878
975
|
},
|
|
976
|
+
/**
|
|
977
|
+
* @private
|
|
978
|
+
* Cache the catalog in the bounded storage.
|
|
979
|
+
* @param {ServiceGroup} serviceGroup - preauth, signin, postauth
|
|
980
|
+
* @param {ServiceHostmap} hostMap - The hostmap to cache
|
|
981
|
+
* @param {object} [meta] - Optional selection metadata for cache discrimination
|
|
982
|
+
* @returns {Promise<void>}
|
|
983
|
+
*/
|
|
984
|
+
_cacheCatalog: function _cacheCatalog(serviceGroup, hostMap, meta) {
|
|
985
|
+
var _this9 = this;
|
|
986
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
987
|
+
var current, orgId, _this9$webex$config, _this9$webex$config$c, _this9$webex, _this9$webex$config2, _this9$webex2, _this9$webex2$config, _this9$webex2$config$, _this9$webex2$config$2, _ls, cachedJson, credentials, _current, env, fedramp, u2cDiscoveryUrl, updated, ls, _t;
|
|
988
|
+
return _regenerator.default.wrap(function (_context) {
|
|
989
|
+
while (1) switch (_context.prev = _context.next) {
|
|
990
|
+
case 0:
|
|
991
|
+
current = {};
|
|
992
|
+
_context.prev = 1;
|
|
993
|
+
if ((_this9$webex$config = _this9.webex.config) !== null && _this9$webex$config !== void 0 && (_this9$webex$config$c = _this9$webex$config.calling) !== null && _this9$webex$config$c !== void 0 && _this9$webex$config$c.cacheU2C) {
|
|
994
|
+
_context.next = 2;
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
_this9.logger.info("services: skipping cache write for ".concat(serviceGroup, " as per the config"));
|
|
998
|
+
return _context.abrupt("return");
|
|
999
|
+
case 2:
|
|
1000
|
+
try {
|
|
1001
|
+
_ls = _this9._getLocalStorageSafe();
|
|
1002
|
+
cachedJson = _ls ? _ls.getItem(CATALOG_CACHE_KEY_V2) : null;
|
|
1003
|
+
current = cachedJson ? JSON.parse(cachedJson) : {};
|
|
1004
|
+
} catch (_unused2) {
|
|
1005
|
+
current = {};
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
credentials = _this9.webex.credentials;
|
|
1009
|
+
orgId = credentials.getOrgId();
|
|
1010
|
+
} catch (_unused3) {
|
|
1011
|
+
orgId = current.orgId;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Capture environment fingerprint to invalidate cache across env changes
|
|
1015
|
+
_current = current, env = _current.env;
|
|
1016
|
+
fedramp = !!((_this9$webex = _this9.webex) !== null && _this9$webex !== void 0 && (_this9$webex$config2 = _this9$webex.config) !== null && _this9$webex$config2 !== void 0 && _this9$webex$config2.fedramp);
|
|
1017
|
+
u2cDiscoveryUrl = (_this9$webex2 = _this9.webex) === null || _this9$webex2 === void 0 ? void 0 : (_this9$webex2$config = _this9$webex2.config) === null || _this9$webex2$config === void 0 ? void 0 : (_this9$webex2$config$ = _this9$webex2$config.services) === null || _this9$webex2$config$ === void 0 ? void 0 : (_this9$webex2$config$2 = _this9$webex2$config$.discovery) === null || _this9$webex2$config$2 === void 0 ? void 0 : _this9$webex2$config$2.u2c;
|
|
1018
|
+
env = {
|
|
1019
|
+
fedramp: fedramp,
|
|
1020
|
+
u2cDiscoveryUrl: u2cDiscoveryUrl
|
|
1021
|
+
};
|
|
1022
|
+
updated = _objectSpread(_objectSpread({}, current), {}, (0, _defineProperty2.default)((0, _defineProperty2.default)({
|
|
1023
|
+
orgId: orgId || current.orgId,
|
|
1024
|
+
env: env || current.env
|
|
1025
|
+
}, serviceGroup, meta ? {
|
|
1026
|
+
hostMap: hostMap,
|
|
1027
|
+
meta: meta
|
|
1028
|
+
} : hostMap), "cachedAt", (0, _now.default)()));
|
|
1029
|
+
ls = _this9._getLocalStorageSafe();
|
|
1030
|
+
if (ls) {
|
|
1031
|
+
ls.setItem(CATALOG_CACHE_KEY_V2, (0, _stringify.default)(updated));
|
|
1032
|
+
}
|
|
1033
|
+
_context.next = 4;
|
|
1034
|
+
break;
|
|
1035
|
+
case 3:
|
|
1036
|
+
_context.prev = 3;
|
|
1037
|
+
_t = _context["catch"](1);
|
|
1038
|
+
_this9.logger.warn('services: error caching catalog', _t);
|
|
1039
|
+
case 4:
|
|
1040
|
+
case "end":
|
|
1041
|
+
return _context.stop();
|
|
1042
|
+
}
|
|
1043
|
+
}, _callee, null, [[1, 3]]);
|
|
1044
|
+
}))();
|
|
1045
|
+
},
|
|
1046
|
+
/**
|
|
1047
|
+
* @private
|
|
1048
|
+
* Load the catalog from cache and hydrate the in-memory ServiceCatalog.
|
|
1049
|
+
* @returns {Promise<boolean>} true if cache was loaded, false otherwise
|
|
1050
|
+
*/
|
|
1051
|
+
_loadCatalogFromCache: function _loadCatalogFromCache() {
|
|
1052
|
+
var _this0 = this;
|
|
1053
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
1054
|
+
var currentOrgId, _this0$webex$config, _this0$webex$config$c, _this0$webex$config2, _this0$webex$config3, _this0$webex$config3$, _this0$webex$config3$2, ls, cachedJson, cached, cachedAt, _this0$webex$credenti, credentials, fedramp, u2cDiscoveryUrl, currentEnv, sameEnv, catalog, groups, _t2, _t3;
|
|
1055
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
1056
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
1057
|
+
case 0:
|
|
1058
|
+
_context2.prev = 0;
|
|
1059
|
+
if ((_this0$webex$config = _this0.webex.config) !== null && _this0$webex$config !== void 0 && (_this0$webex$config$c = _this0$webex$config.calling) !== null && _this0$webex$config$c !== void 0 && _this0$webex$config$c.cacheU2C) {
|
|
1060
|
+
_context2.next = 1;
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
_this0.logger.info('services: skipping cache warm-up as per the cache config');
|
|
1064
|
+
return _context2.abrupt("return", false);
|
|
1065
|
+
case 1:
|
|
1066
|
+
ls = _this0._getLocalStorageSafe();
|
|
1067
|
+
if (ls) {
|
|
1068
|
+
_context2.next = 2;
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
_this0.logger.info('services: skipping cache warm-up as no localStorage is available');
|
|
1072
|
+
return _context2.abrupt("return", false);
|
|
1073
|
+
case 2:
|
|
1074
|
+
cachedJson = ls.getItem(CATALOG_CACHE_KEY_V2);
|
|
1075
|
+
cached = cachedJson ? JSON.parse(cachedJson) : undefined;
|
|
1076
|
+
if (cached) {
|
|
1077
|
+
_context2.next = 3;
|
|
1078
|
+
break;
|
|
1079
|
+
}
|
|
1080
|
+
return _context2.abrupt("return", false);
|
|
1081
|
+
case 3:
|
|
1082
|
+
// TTL enforcement
|
|
1083
|
+
cachedAt = Number(cached.cachedAt) || 0;
|
|
1084
|
+
if (!(!cachedAt || (0, _now.default)() - cachedAt > CATALOG_TTL_MS)) {
|
|
1085
|
+
_context2.next = 4;
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
_this0.clearCatalogCache();
|
|
1089
|
+
return _context2.abrupt("return", false);
|
|
1090
|
+
case 4:
|
|
1091
|
+
_context2.prev = 4;
|
|
1092
|
+
if (!((_this0$webex$credenti = _this0.webex.credentials) !== null && _this0$webex$credenti !== void 0 && _this0$webex$credenti.canAuthorize)) {
|
|
1093
|
+
_context2.next = 5;
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1096
|
+
credentials = _this0.webex.credentials;
|
|
1097
|
+
currentOrgId = credentials.getOrgId();
|
|
1098
|
+
if (!(cached.orgId && cached.orgId !== currentOrgId)) {
|
|
1099
|
+
_context2.next = 5;
|
|
1100
|
+
break;
|
|
1101
|
+
}
|
|
1102
|
+
return _context2.abrupt("return", false);
|
|
1103
|
+
case 5:
|
|
1104
|
+
_context2.next = 7;
|
|
1105
|
+
break;
|
|
1106
|
+
case 6:
|
|
1107
|
+
_context2.prev = 6;
|
|
1108
|
+
_t2 = _context2["catch"](4);
|
|
1109
|
+
_this0.logger.warn('services: error checking orgId', _t2);
|
|
1110
|
+
case 7:
|
|
1111
|
+
// Ensure cached environment matches current environment
|
|
1112
|
+
fedramp = !!((_this0$webex$config2 = _this0.webex.config) !== null && _this0$webex$config2 !== void 0 && _this0$webex$config2.fedramp);
|
|
1113
|
+
u2cDiscoveryUrl = (_this0$webex$config3 = _this0.webex.config) === null || _this0$webex$config3 === void 0 ? void 0 : (_this0$webex$config3$ = _this0$webex$config3.services) === null || _this0$webex$config3$ === void 0 ? void 0 : (_this0$webex$config3$2 = _this0$webex$config3$.discovery) === null || _this0$webex$config3$2 === void 0 ? void 0 : _this0$webex$config3$2.u2c;
|
|
1114
|
+
currentEnv = {
|
|
1115
|
+
fedramp: fedramp,
|
|
1116
|
+
u2cDiscoveryUrl: u2cDiscoveryUrl
|
|
1117
|
+
};
|
|
1118
|
+
if (!cached.env) {
|
|
1119
|
+
_context2.next = 8;
|
|
1120
|
+
break;
|
|
1121
|
+
}
|
|
1122
|
+
sameEnv = cached.env.fedramp === currentEnv.fedramp && cached.env.u2cDiscoveryUrl === currentEnv.u2cDiscoveryUrl;
|
|
1123
|
+
if (sameEnv) {
|
|
1124
|
+
_context2.next = 8;
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
return _context2.abrupt("return", false);
|
|
1128
|
+
case 8:
|
|
1129
|
+
catalog = _this0._getCatalog();
|
|
1130
|
+
groups = ['preauth', 'signin', 'postauth'];
|
|
1131
|
+
groups.forEach(function (serviceGroup) {
|
|
1132
|
+
var cachedGroup = cached[serviceGroup];
|
|
1133
|
+
if (!cachedGroup) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// Support legacy (hostMap) and new ({hostMap, meta}) shapes
|
|
1138
|
+
var hostMap = cachedGroup && cachedGroup.hostMap ? cachedGroup.hostMap : cachedGroup;
|
|
1139
|
+
var meta = cachedGroup === null || cachedGroup === void 0 ? void 0 : cachedGroup.meta;
|
|
1140
|
+
if (serviceGroup === 'preauth' && meta) {
|
|
1141
|
+
// For proximity-based selection, always fetch fresh to respect IP/region changes
|
|
1142
|
+
if (meta.selectionType === 'mode') {
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
var intended = _this0.getIntendedPreauthSelection(currentOrgId);
|
|
1146
|
+
var matches = intended && intended.selectionType === meta.selectionType && intended.selectionValue === meta.selectionValue;
|
|
1147
|
+
if (!matches) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
if (hostMap) {
|
|
1152
|
+
catalog.updateServiceGroups(serviceGroup, hostMap === null || hostMap === void 0 ? void 0 : hostMap.services, hostMap === null || hostMap === void 0 ? void 0 : hostMap.timestamp);
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
_this0.updateCredentialsConfig();
|
|
1156
|
+
return _context2.abrupt("return", true);
|
|
1157
|
+
case 9:
|
|
1158
|
+
_context2.prev = 9;
|
|
1159
|
+
_t3 = _context2["catch"](0);
|
|
1160
|
+
return _context2.abrupt("return", false);
|
|
1161
|
+
case 10:
|
|
1162
|
+
case "end":
|
|
1163
|
+
return _context2.stop();
|
|
1164
|
+
}
|
|
1165
|
+
}, _callee2, null, [[0, 9], [4, 6]]);
|
|
1166
|
+
}))();
|
|
1167
|
+
},
|
|
1168
|
+
/**
|
|
1169
|
+
* Clear the catalog cache from the bounded storage (v2).
|
|
1170
|
+
* @returns {Promise<void>}
|
|
1171
|
+
*/
|
|
1172
|
+
clearCatalogCache: function clearCatalogCache() {
|
|
1173
|
+
try {
|
|
1174
|
+
var ls = this._getLocalStorageSafe();
|
|
1175
|
+
if (ls) {
|
|
1176
|
+
ls.removeItem(CATALOG_CACHE_KEY_V2);
|
|
1177
|
+
}
|
|
1178
|
+
} catch (e) {
|
|
1179
|
+
this.logger.warn('services: error clearing catalog cache', e);
|
|
1180
|
+
}
|
|
1181
|
+
return _promise.default.resolve();
|
|
1182
|
+
},
|
|
879
1183
|
/**
|
|
880
1184
|
* @private
|
|
881
1185
|
* Simplified method wrapper for sending a request to get
|
|
@@ -890,7 +1194,7 @@ var Services = _webexPlugin.default.extend({
|
|
|
890
1194
|
* @returns {Promise<object>}
|
|
891
1195
|
*/
|
|
892
1196
|
_fetchNewServiceHostmap: function _fetchNewServiceHostmap() {
|
|
893
|
-
var
|
|
1197
|
+
var _this1 = this;
|
|
894
1198
|
var _ref11 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
895
1199
|
from = _ref11.from,
|
|
896
1200
|
query = _ref11.query,
|
|
@@ -917,10 +1221,10 @@ var Services = _webexPlugin.default.extend({
|
|
|
917
1221
|
};
|
|
918
1222
|
}
|
|
919
1223
|
return this.webex.internal.newMetrics.callDiagnosticLatencies.measureLatency(function () {
|
|
920
|
-
return
|
|
1224
|
+
return _this1.request(requestObject);
|
|
921
1225
|
}, 'internal.get.u2c.time').then(function (_ref12) {
|
|
922
1226
|
var body = _ref12.body;
|
|
923
|
-
return
|
|
1227
|
+
return _this1._formatReceivedHostmap(body || {});
|
|
924
1228
|
});
|
|
925
1229
|
},
|
|
926
1230
|
/**
|
|
@@ -929,12 +1233,12 @@ var Services = _webexPlugin.default.extend({
|
|
|
929
1233
|
* @returns {void}
|
|
930
1234
|
*/
|
|
931
1235
|
initConfig: function initConfig() {
|
|
932
|
-
var
|
|
1236
|
+
var _this10 = this;
|
|
933
1237
|
// Get the catalog and destructure the services config.
|
|
934
1238
|
var catalog = this._getCatalog();
|
|
935
|
-
var _this$webex$
|
|
936
|
-
services = _this$webex$
|
|
937
|
-
fedramp = _this$webex$
|
|
1239
|
+
var _this$webex$config2 = this.webex.config,
|
|
1240
|
+
services = _this$webex$config2.services,
|
|
1241
|
+
fedramp = _this$webex$config2.fedramp;
|
|
938
1242
|
|
|
939
1243
|
// Validate that the services configuration exists.
|
|
940
1244
|
if (services) {
|
|
@@ -945,7 +1249,7 @@ var Services = _webexPlugin.default.extend({
|
|
|
945
1249
|
if (services.discovery) {
|
|
946
1250
|
// Format the discovery configuration into an injectable array.
|
|
947
1251
|
var formattedDiscoveryServices = (0, _keys.default)(services.discovery).map(function (key) {
|
|
948
|
-
return
|
|
1252
|
+
return _this10._formatHostMapEntry({
|
|
949
1253
|
id: key,
|
|
950
1254
|
serviceName: key,
|
|
951
1255
|
serviceUrls: [{
|
|
@@ -961,7 +1265,7 @@ var Services = _webexPlugin.default.extend({
|
|
|
961
1265
|
if (services.override) {
|
|
962
1266
|
// Format the override configuration into an injectable array.
|
|
963
1267
|
var formattedOverrideServices = (0, _keys.default)(services.override).map(function (key) {
|
|
964
|
-
return
|
|
1268
|
+
return _this10._formatHostMapEntry({
|
|
965
1269
|
id: key,
|
|
966
1270
|
serviceName: key,
|
|
967
1271
|
serviceUrls: [{
|
|
@@ -996,7 +1300,7 @@ var Services = _webexPlugin.default.extend({
|
|
|
996
1300
|
* @returns {Promise<void, Error>} - Errors if the token is unavailable.
|
|
997
1301
|
*/
|
|
998
1302
|
initServiceCatalogs: function initServiceCatalogs() {
|
|
999
|
-
var
|
|
1303
|
+
var _this11 = this;
|
|
1000
1304
|
var refresh = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
1001
1305
|
this.logger.info('services: initializing initial service catalogs');
|
|
1002
1306
|
|
|
@@ -1012,18 +1316,18 @@ var Services = _webexPlugin.default.extend({
|
|
|
1012
1316
|
})
|
|
1013
1317
|
// Begin collecting the preauth/limited catalog.
|
|
1014
1318
|
.then(function (orgId) {
|
|
1015
|
-
return
|
|
1319
|
+
return _this11.collectPreauthCatalog({
|
|
1016
1320
|
orgId: orgId
|
|
1017
1321
|
}, refresh);
|
|
1018
1322
|
}).then(function () {
|
|
1019
1323
|
// Validate if the token is authorized.
|
|
1020
1324
|
if (credentials.canAuthorize) {
|
|
1021
1325
|
// Attempt to collect the postauth catalog.
|
|
1022
|
-
return
|
|
1326
|
+
return _this11.updateServices({
|
|
1023
1327
|
forceRefresh: refresh
|
|
1024
1328
|
}).catch(function () {
|
|
1025
|
-
|
|
1026
|
-
|
|
1329
|
+
_this11.initFailed = true;
|
|
1330
|
+
_this11.logger.warn('services: cannot retrieve postauth catalog');
|
|
1027
1331
|
});
|
|
1028
1332
|
}
|
|
1029
1333
|
|
|
@@ -1031,6 +1335,42 @@ var Services = _webexPlugin.default.extend({
|
|
|
1031
1335
|
return _promise.default.resolve();
|
|
1032
1336
|
});
|
|
1033
1337
|
},
|
|
1338
|
+
/**
|
|
1339
|
+
* Await any in-flight credentials refresh, then flip `services.ready` so
|
|
1340
|
+
* `webex.ready` can fire. Closes the parallel-refresh window: if a credential
|
|
1341
|
+
* refresh is in flight when initial catalog collection settles, we must not
|
|
1342
|
+
* signal ready until the refresh has resolved - otherwise downstream
|
|
1343
|
+
* consumers may observe `canAuthorize`/token state that is about to change
|
|
1344
|
+
* under them.
|
|
1345
|
+
*
|
|
1346
|
+
* @private
|
|
1347
|
+
* @returns {Promise<void>}
|
|
1348
|
+
*/
|
|
1349
|
+
_finalizeReady: function _finalizeReady() {
|
|
1350
|
+
var _this12 = this;
|
|
1351
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
1352
|
+
var credentials;
|
|
1353
|
+
return _regenerator.default.wrap(function (_context3) {
|
|
1354
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
1355
|
+
case 0:
|
|
1356
|
+
credentials = _this12.webex.credentials;
|
|
1357
|
+
if (!(credentials && credentials.isRefreshing)) {
|
|
1358
|
+
_context3.next = 1;
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1361
|
+
_context3.next = 1;
|
|
1362
|
+
return new _promise.default(function (resolve) {
|
|
1363
|
+
credentials.once('change:isRefreshing', resolve);
|
|
1364
|
+
});
|
|
1365
|
+
case 1:
|
|
1366
|
+
_this12.ready = true;
|
|
1367
|
+
case 2:
|
|
1368
|
+
case "end":
|
|
1369
|
+
return _context3.stop();
|
|
1370
|
+
}
|
|
1371
|
+
}, _callee3);
|
|
1372
|
+
}))();
|
|
1373
|
+
},
|
|
1034
1374
|
/**
|
|
1035
1375
|
* Initializer
|
|
1036
1376
|
*
|
|
@@ -1039,39 +1379,165 @@ var Services = _webexPlugin.default.extend({
|
|
|
1039
1379
|
* @returns {Services}
|
|
1040
1380
|
*/
|
|
1041
1381
|
initialize: function initialize() {
|
|
1042
|
-
var
|
|
1382
|
+
var _this13 = this;
|
|
1043
1383
|
var catalog = new _serviceCatalog.default();
|
|
1044
1384
|
this._catalogs.set(this.webex, catalog);
|
|
1045
1385
|
|
|
1046
|
-
// Listen for configuration changes once.
|
|
1386
|
+
// Listen for configuration changes once. The config is not populated on the
|
|
1387
|
+
// webex instance until the `change:config` event fires, so any decision that
|
|
1388
|
+
// depends on config values (such as the gated-vs-ungated init below) must be
|
|
1389
|
+
// made from within this handler rather than synchronously in `initialize()`.
|
|
1047
1390
|
this.listenToOnce(this.webex, 'change:config', function () {
|
|
1048
|
-
|
|
1049
|
-
|
|
1391
|
+
var _this13$webex$config, _this13$webex$config$;
|
|
1392
|
+
_this13.initConfig();
|
|
1050
1393
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
//
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
}).catch(function (error) {
|
|
1060
|
-
_this10.initFailed = true;
|
|
1061
|
-
_this10.logger.error("services: failed to init initial services when credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1062
|
-
});
|
|
1394
|
+
// Feature flag: when enabled, `webex.ready` is blocked until the initial
|
|
1395
|
+
// catalog collection has settled AND any in-flight credentials refresh has
|
|
1396
|
+
// completed. When disabled (the default), preserves the pre-existing
|
|
1397
|
+
// behavior where `webex.ready` fires as soon as `webex.loaded` does and
|
|
1398
|
+
// the catalog is collected out-of-band.
|
|
1399
|
+
var waitForCatalogInit = ((_this13$webex$config = _this13.webex.config) === null || _this13$webex$config === void 0 ? void 0 : (_this13$webex$config$ = _this13$webex$config.services) === null || _this13$webex$config$ === void 0 ? void 0 : _this13$webex$config$.waitForCatalogInit) === true;
|
|
1400
|
+
if (waitForCatalogInit) {
|
|
1401
|
+
_this13._initializeCatalogsGated(catalog);
|
|
1063
1402
|
} else {
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
} : undefined).catch(function (error) {
|
|
1068
|
-
_this10.initFailed = true;
|
|
1069
|
-
_this10.logger.error("services: failed to init initial services when no credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1070
|
-
});
|
|
1403
|
+
// Not gating - immediately mark ready so we do not block webex.ready.
|
|
1404
|
+
_this13.ready = true;
|
|
1405
|
+
_this13._initializeCatalogsUngated(catalog);
|
|
1071
1406
|
}
|
|
1072
1407
|
});
|
|
1073
1408
|
},
|
|
1074
|
-
|
|
1409
|
+
/**
|
|
1410
|
+
* Original (pre-verified-ready) initialization path. Runs on `webex.ready`
|
|
1411
|
+
* and collects catalogs opportunistically without blocking anything.
|
|
1412
|
+
*
|
|
1413
|
+
* @private
|
|
1414
|
+
* @param {ServiceCatalog} catalog
|
|
1415
|
+
* @returns {void}
|
|
1416
|
+
*/
|
|
1417
|
+
_initializeCatalogsUngated: function _initializeCatalogsUngated(catalog) {
|
|
1418
|
+
var _this14 = this;
|
|
1419
|
+
// wait for webex instance to be ready before attempting
|
|
1420
|
+
// to update the service catalogs
|
|
1421
|
+
this.listenToOnce(this.webex, 'ready', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4() {
|
|
1422
|
+
var warmed, supertoken, email;
|
|
1423
|
+
return _regenerator.default.wrap(function (_context4) {
|
|
1424
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
1425
|
+
case 0:
|
|
1426
|
+
_context4.next = 1;
|
|
1427
|
+
return _this14._loadCatalogFromCache();
|
|
1428
|
+
case 1:
|
|
1429
|
+
warmed = _context4.sent;
|
|
1430
|
+
if (!warmed) {
|
|
1431
|
+
_context4.next = 2;
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
catalog.isReady = true;
|
|
1435
|
+
return _context4.abrupt("return");
|
|
1436
|
+
case 2:
|
|
1437
|
+
supertoken = _this14.webex.credentials.supertoken; // Validate if the supertoken exists.
|
|
1438
|
+
if (supertoken && supertoken.access_token) {
|
|
1439
|
+
_this14.initServiceCatalogs().then(function () {
|
|
1440
|
+
catalog.isReady = true;
|
|
1441
|
+
}).catch(function (error) {
|
|
1442
|
+
_this14.initFailed = true;
|
|
1443
|
+
_this14.logger.error("services: failed to init initial services when credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1444
|
+
});
|
|
1445
|
+
} else {
|
|
1446
|
+
email = _this14.webex.config.email;
|
|
1447
|
+
_this14.collectPreauthCatalog(email ? {
|
|
1448
|
+
email: email
|
|
1449
|
+
} : undefined).catch(function (error) {
|
|
1450
|
+
_this14.initFailed = true;
|
|
1451
|
+
_this14.logger.error("services: failed to init initial services when no credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
case 3:
|
|
1455
|
+
case "end":
|
|
1456
|
+
return _context4.stop();
|
|
1457
|
+
}
|
|
1458
|
+
}, _callee4);
|
|
1459
|
+
})));
|
|
1460
|
+
},
|
|
1461
|
+
/**
|
|
1462
|
+
* Verified-ready initialization path. Blocks `webex.ready` until the initial
|
|
1463
|
+
* catalog fetch has settled (or timed out) AND any in-flight credentials
|
|
1464
|
+
* refresh has completed. Also handles the fresh-login case where OAuth
|
|
1465
|
+
* completes after `loaded` fires.
|
|
1466
|
+
*
|
|
1467
|
+
* @private
|
|
1468
|
+
* @param {ServiceCatalog} catalog
|
|
1469
|
+
* @returns {void}
|
|
1470
|
+
*/
|
|
1471
|
+
_initializeCatalogsGated: function _initializeCatalogsGated(catalog) {
|
|
1472
|
+
var _this15 = this;
|
|
1473
|
+
// Wait for storage to be loaded before attempting to update the service
|
|
1474
|
+
// catalogs. We listen for 'loaded' instead of 'ready' because `services.ready`
|
|
1475
|
+
// now blocks `webex.ready` - listening to 'ready' would deadlock.
|
|
1476
|
+
this.listenToOnce(this.webex, 'loaded', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee5() {
|
|
1477
|
+
var warmed, supertoken, timeout, email;
|
|
1478
|
+
return _regenerator.default.wrap(function (_context5) {
|
|
1479
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
1480
|
+
case 0:
|
|
1481
|
+
_context5.next = 1;
|
|
1482
|
+
return _this15._loadCatalogFromCache();
|
|
1483
|
+
case 1:
|
|
1484
|
+
warmed = _context5.sent;
|
|
1485
|
+
if (!warmed) {
|
|
1486
|
+
_context5.next = 3;
|
|
1487
|
+
break;
|
|
1488
|
+
}
|
|
1489
|
+
catalog.isReady = true;
|
|
1490
|
+
_context5.next = 2;
|
|
1491
|
+
return _this15._finalizeReady();
|
|
1492
|
+
case 2:
|
|
1493
|
+
return _context5.abrupt("return");
|
|
1494
|
+
case 3:
|
|
1495
|
+
supertoken = _this15.webex.credentials.supertoken; // Race init against a hard timeout so a hung request never leaves
|
|
1496
|
+
// `services.ready` false forever - that would stall `webex.ready` and
|
|
1497
|
+
// leave the app on a permanent spinner.
|
|
1498
|
+
timeout = new _promise.default(function (_, reject) {
|
|
1499
|
+
setTimeout(function () {
|
|
1500
|
+
return reject(new Error("services: init timed out after ".concat(SERVICES_INIT_TIMEOUT_MS, "ms")));
|
|
1501
|
+
}, SERVICES_INIT_TIMEOUT_MS);
|
|
1502
|
+
}); // Validate if the supertoken exists.
|
|
1503
|
+
if (supertoken && supertoken.access_token) {
|
|
1504
|
+
_promise.default.race([_this15.initServiceCatalogs(), timeout]).then(function () {
|
|
1505
|
+
catalog.isReady = true;
|
|
1506
|
+
}).catch(function (error) {
|
|
1507
|
+
_this15.initFailed = true;
|
|
1508
|
+
_this15.logger.error("services: failed to init initial services when credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1509
|
+
}).finally(function () {
|
|
1510
|
+
return _this15._finalizeReady();
|
|
1511
|
+
});
|
|
1512
|
+
} else {
|
|
1513
|
+
email = _this15.webex.config.email;
|
|
1514
|
+
_promise.default.race([_this15.collectPreauthCatalog(email ? {
|
|
1515
|
+
email: email
|
|
1516
|
+
} : undefined), timeout]).catch(function (error) {
|
|
1517
|
+
_this15.initFailed = true;
|
|
1518
|
+
_this15.logger.error("services: failed to init initial services when no credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1519
|
+
}).finally(function () {
|
|
1520
|
+
return _this15._finalizeReady();
|
|
1521
|
+
});
|
|
1522
|
+
|
|
1523
|
+
// Handle fresh login: 'loaded' fires before OAuth completes, so listen
|
|
1524
|
+
// for `canAuthorize` flipping true and then collect the postauth catalog.
|
|
1525
|
+
_this15.listenToOnce(_this15.webex, 'change:canAuthorize', function () {
|
|
1526
|
+
if (_this15.webex.canAuthorize && !catalog.status.postauth.ready) {
|
|
1527
|
+
_this15.initServiceCatalogs().catch(function (error) {
|
|
1528
|
+
_this15.logger.error("services: failed to init service catalogs after auth, ".concat(error === null || error === void 0 ? void 0 : error.message));
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
case 4:
|
|
1534
|
+
case "end":
|
|
1535
|
+
return _context5.stop();
|
|
1536
|
+
}
|
|
1537
|
+
}, _callee5);
|
|
1538
|
+
})));
|
|
1539
|
+
},
|
|
1540
|
+
version: "3.12.0-webex-services-ready.2"
|
|
1075
1541
|
});
|
|
1076
1542
|
/* eslint-enable no-underscore-dangle */
|
|
1077
1543
|
var _default = exports.default = Services;
|