@webex/webex-core 3.12.0-next.9 → 3.12.0-webex-services-ready.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ var _serviceState = _interopRequireDefault(require("./service-state"));
31
31
  var _serviceFedRamp = _interopRequireDefault(require("./service-fed-ramp"));
32
32
  var _constants = require("../constants");
33
33
  function ownKeys(e, r) { var t = _Object$keys2(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
34
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
34
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; } /* eslint-disable no-console */
35
35
  var trailingSlashes = /(?:^\/)|(?:\/$)/;
36
36
 
37
37
  // The default cluster when one is not provided (usually as 'US' from hydra)
@@ -43,6 +43,12 @@ var DEFAULT_CLUSTER_IDENTIFIER = process.env.WEBEX_CONVERSATION_DEFAULT_CLUSTER
43
43
  var CATALOG_CACHE_KEY_V1 = 'services.v1.u2cHostMap';
44
44
  var CATALOG_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
45
45
 
46
+ // Maximum time we will wait for the initial catalog collection before letting
47
+ // `services.ready` (and therefore `webex.ready`) fire anyway. A hung request
48
+ // must never leave the app on a permanent spinner - past this point downstream
49
+ // consumers must fall through to their normal error/login paths.
50
+ var SERVICES_INIT_TIMEOUT_MS = 15000;
51
+
46
52
  /* eslint-disable no-underscore-dangle */
47
53
  /**
48
54
  * @class
@@ -73,6 +79,19 @@ var Services = _webexPlugin.default.extend({
73
79
  validateDomains: ['boolean', false, true],
74
80
  initFailed: ['boolean', false, false]
75
81
  },
82
+ session: {
83
+ /**
84
+ * Becomes `true` once service catalog initialization has completed.
85
+ * Blocks `webex.ready` until services are initialized.
86
+ * @instance
87
+ * @memberof Services
88
+ * @type {boolean}
89
+ */
90
+ ready: {
91
+ default: false,
92
+ type: 'boolean'
93
+ }
94
+ },
76
95
  _catalogs: new _weakMap.default(),
77
96
  _serviceUrls: null,
78
97
  _hostCatalog: null,
@@ -1378,6 +1397,43 @@ var Services = _webexPlugin.default.extend({
1378
1397
  return _promise.default.resolve();
1379
1398
  });
1380
1399
  },
1400
+ /**
1401
+ * Await any in-flight credentials refresh, then flip `services.ready` so
1402
+ * `webex.ready` can fire. Closes the parallel-refresh window: if a credential
1403
+ * refresh is in flight when initial catalog collection settles, we must not
1404
+ * signal ready until the refresh has resolved - otherwise downstream
1405
+ * consumers may observe `canAuthorize`/token state that is about to change
1406
+ * under them.
1407
+ *
1408
+ * @private
1409
+ * @returns {Promise<void>}
1410
+ */
1411
+ _finalizeReady: function _finalizeReady() {
1412
+ var _this1 = this;
1413
+ return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4() {
1414
+ var credentials;
1415
+ return _regenerator.default.wrap(function (_context4) {
1416
+ while (1) switch (_context4.prev = _context4.next) {
1417
+ case 0:
1418
+ credentials = _this1.webex.credentials;
1419
+ if (!(credentials && credentials.isRefreshing)) {
1420
+ _context4.next = 1;
1421
+ break;
1422
+ }
1423
+ _context4.next = 1;
1424
+ return new _promise.default(function (resolve) {
1425
+ credentials.once('change:isRefreshing', resolve);
1426
+ });
1427
+ case 1:
1428
+ _this1.ready = true;
1429
+ _this1.trigger('services:initialized');
1430
+ case 2:
1431
+ case "end":
1432
+ return _context4.stop();
1433
+ }
1434
+ }, _callee4);
1435
+ }))();
1436
+ },
1381
1437
  /**
1382
1438
  * Initializer
1383
1439
  *
@@ -1386,7 +1442,7 @@ var Services = _webexPlugin.default.extend({
1386
1442
  * @returns {Services}
1387
1443
  */
1388
1444
  initialize: function initialize() {
1389
- var _this1 = this;
1445
+ var _this10 = this;
1390
1446
  var catalog = new _serviceCatalog.default();
1391
1447
  var registry = new _serviceRegistry.default();
1392
1448
  var state = new _serviceState.default();
@@ -1396,54 +1452,78 @@ var Services = _webexPlugin.default.extend({
1396
1452
 
1397
1453
  // Listen for configuration changes once.
1398
1454
  this.listenToOnce(this.webex, 'change:config', function () {
1399
- _this1.initConfig();
1455
+ _this10.initConfig();
1400
1456
  });
1401
1457
 
1402
- // wait for webex instance to be ready before attempting
1403
- // to update the service catalogs
1404
- // this can cause a race condition because credentials may
1405
- // not be valid when services is initialized
1406
- this.listenToOnce(this.webex, 'ready', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4() {
1407
- var cachedCatalog, supertoken, email;
1408
- return _regenerator.default.wrap(function (_context4) {
1409
- while (1) switch (_context4.prev = _context4.next) {
1458
+ // Wait for storage to be loaded before attempting to update the service catalogs.
1459
+ // We listen for 'loaded' instead of 'ready' because services.ready is a dependency
1460
+ // of webex.ready - listening to 'ready' would cause a deadlock.
1461
+ this.listenToOnce(this.webex, 'loaded', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee5() {
1462
+ var cachedCatalog, supertoken, timeout, email;
1463
+ return _regenerator.default.wrap(function (_context5) {
1464
+ while (1) switch (_context5.prev = _context5.next) {
1410
1465
  case 0:
1411
- _context4.next = 1;
1412
- return _this1._loadCatalogFromCache();
1466
+ _context5.next = 1;
1467
+ return _this10._loadCatalogFromCache();
1413
1468
  case 1:
1414
- cachedCatalog = _context4.sent;
1469
+ cachedCatalog = _context5.sent;
1415
1470
  if (!cachedCatalog) {
1416
- _context4.next = 2;
1471
+ _context5.next = 3;
1417
1472
  break;
1418
1473
  }
1419
1474
  catalog.isReady = true;
1420
- return _context4.abrupt("return");
1475
+ _context5.next = 2;
1476
+ return _this10._finalizeReady();
1421
1477
  case 2:
1422
- supertoken = _this1.webex.credentials.supertoken; // Validate if the supertoken exists.
1478
+ return _context5.abrupt("return");
1479
+ case 3:
1480
+ supertoken = _this10.webex.credentials.supertoken; // Race init against a hard timeout so a hung request never leaves
1481
+ // `services.ready` false forever - that would stall `webex.ready` and
1482
+ // leave the app on a permanent spinner.
1483
+ timeout = new _promise.default(function (_, reject) {
1484
+ setTimeout(function () {
1485
+ return reject(new Error("services: init timed out after ".concat(SERVICES_INIT_TIMEOUT_MS, "ms")));
1486
+ }, SERVICES_INIT_TIMEOUT_MS);
1487
+ }); // Validate if the supertoken exists.
1423
1488
  if (supertoken && supertoken.access_token) {
1424
- _this1.initServiceCatalogs().then(function () {
1489
+ _promise.default.race([_this10.initServiceCatalogs(), timeout]).then(function () {
1425
1490
  catalog.isReady = true;
1426
1491
  }).catch(function (error) {
1427
- _this1.initFailed = true;
1428
- _this1.logger.error("services: failed to init initial services when credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
1492
+ _this10.initFailed = true;
1493
+ _this10.logger.error("services: failed to init initial services when credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
1494
+ }).finally(function () {
1495
+ return _this10._finalizeReady();
1429
1496
  });
1430
1497
  } else {
1431
- email = _this1.webex.config.email;
1432
- _this1.collectPreauthCatalog(email ? {
1498
+ email = _this10.webex.config.email;
1499
+ _promise.default.race([_this10.collectPreauthCatalog(email ? {
1433
1500
  email: email
1434
- } : undefined).catch(function (error) {
1435
- _this1.initFailed = true;
1436
- _this1.logger.error("services: failed to init initial services when no credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
1501
+ } : undefined), timeout]).catch(function (error) {
1502
+ _this10.initFailed = true;
1503
+ _this10.logger.error("services: failed to init initial services when no credentials available, ".concat(error === null || error === void 0 ? void 0 : error.message));
1504
+ }).finally(function () {
1505
+ return _this10._finalizeReady();
1506
+ });
1507
+ // Listen for when credentials become available to fetch the full catalog.
1508
+ // This handles fresh login where 'loaded' fires before OAuth completes.
1509
+ _this10.listenToOnce(_this10.webex, 'change:canAuthorize', function () {
1510
+ if (_this10.webex.canAuthorize && !catalog.status.postauth.ready) {
1511
+ _this10.initServiceCatalogs().then(function () {
1512
+ catalog.isReady = true;
1513
+ }).catch(function (error) {
1514
+ _this10.logger.error("services: failed to init service catalogs after auth, ".concat(error === null || error === void 0 ? void 0 : error.message));
1515
+ });
1516
+ }
1437
1517
  });
1438
1518
  }
1439
- case 3:
1519
+ case 4:
1440
1520
  case "end":
1441
- return _context4.stop();
1521
+ return _context5.stop();
1442
1522
  }
1443
- }, _callee4);
1523
+ }, _callee5);
1444
1524
  })));
1445
1525
  },
1446
- version: "3.12.0-next.9"
1526
+ version: "3.12.0-webex-services-ready.1"
1447
1527
  });
1448
1528
  /* eslint-enable no-underscore-dangle */
1449
1529
  var _default = exports.default = Services;