@webex/webex-core 3.12.0-mobius-socket.2 → 3.12.0-mobius-socket.3

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.
@@ -65,11 +65,12 @@ var Batcher = _webexPlugin.default.extend({
65
65
  }
66
66
  _this2.deferreds.set(idx, defer);
67
67
  _this2.prepareItem(item).then(function (req) {
68
- defer.promise = defer.promise.then((0, _common.tap)(function () {
68
+ // Attach cleanup handlers to the original deferred promise without
69
+ // creating an unobserved rejected chain.
70
+ defer.promise.then(function () {
71
+ return _this2.deferreds.delete(idx);
72
+ }, function () {
69
73
  return _this2.deferreds.delete(idx);
70
- })).catch(function (reason) {
71
- _this2.deferreds.delete(idx);
72
- return _promise.default.reject(reason);
73
74
  });
74
75
  _this2.enqueue(req).then(function () {
75
76
  return _this2.bounce();
@@ -118,7 +119,17 @@ var Batcher = _webexPlugin.default.extend({
118
119
  });
119
120
  }).catch(function (reason) {
120
121
  if (reason instanceof _webexHttpError.default) {
121
- return _this3.handleHttpError(reason);
122
+ // Some batched requests (for example GET-based batches) do not
123
+ // have reason.options.body, so handleHttpError() may reject
124
+ // without failing queued deferreds. Fallback to rejecting each
125
+ // queued request to ensure caller promises settle.
126
+ return _this3.handleHttpError(reason).catch(function () {
127
+ return _promise.default.all(queue.map(function (item) {
128
+ return _this3.getDeferredForRequest(item).then(function (defer) {
129
+ defer.reject(reason);
130
+ });
131
+ }));
132
+ });
122
133
  }
123
134
  return _promise.default.all(queue.map(function (item) {
124
135
  return _this3.getDeferredForRequest(item).then(function (defer) {
@@ -128,7 +139,12 @@ var Batcher = _webexPlugin.default.extend({
128
139
  }));
129
140
  }).catch(function (reason) {
130
141
  _this3.logger.error(process.env.NODE_ENV === 'production' ? reason : reason.stack);
131
- return _promise.default.reject(reason);
142
+ // executeQueue() is triggered via cappedDebounce(), which does not
143
+ // propagate promise chains. Re-throwing here causes global unhandled
144
+ // promise rejections even when request callers handle their own promise.
145
+ // Any known queued requests have already been failed above.
146
+
147
+ return undefined;
132
148
  });
133
149
  },
134
150
  /**
@@ -286,7 +302,7 @@ var Batcher = _webexPlugin.default.extend({
286
302
  fingerprintResponse: function fingerprintResponse(item) {
287
303
  throw new Error('fingerprintResponse() must be implemented');
288
304
  },
289
- version: "3.12.0-mobius-socket.2"
305
+ version: "3.12.0-mobius-socket.3"
290
306
  });
291
307
  var _default2 = exports.default = Batcher;
292
308
  //# sourceMappingURL=batcher.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_lodash","require","_common","_webexPlugin","_interopRequireDefault","_webexHttpError","Batcher","WebexPlugin","extend","session","deferreds","type","default","_map","queue","derived","bounce","fn","_this","cappedDebounce","executeQueue","apply","arguments","config","batcherWait","maxCalls","batcherMaxCalls","maxWait","batcherMaxWait","request","item","_this2","defer","Defer","fingerprintRequest","then","idx","has","resolve","get","promise","set","prepareItem","req","tap","delete","catch","reason","_promise","reject","enqueue","push","_this3","splice","prepareRequest","payload","submitHttpRequest","res","handleHttpSuccess","WebexHttpError","handleHttpError","all","map","getDeferredForRequest","logger","error","process","env","NODE_ENV","stack","Error","_this4","body","items","acceptItem","_this5","options","_this6","didItemFail","didFail","handleItemFailure","handleItemSuccess","getDeferredForResponse","_this7","_this8","fingerprintResponse","version","_default2","exports"],"sources":["batcher.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {has} from 'lodash';\nimport {cappedDebounce, Defer, tap} from '@webex/common';\n\nimport WebexPlugin from './webex-plugin';\nimport WebexHttpError from './webex-http-error';\n\n/**\n * Base class for coalescing requests to batched APIs\n * @class Batcher\n */\nconst Batcher = WebexPlugin.extend({\n session: {\n deferreds: {\n type: 'object',\n default() {\n return new Map();\n },\n },\n queue: {\n type: 'array',\n default() {\n return [];\n },\n },\n },\n\n derived: {\n bounce: {\n fn() {\n return cappedDebounce((...args) => this.executeQueue(...args), this.config.batcherWait, {\n maxCalls: this.config.batcherMaxCalls,\n maxWait: this.config.batcherMaxWait,\n });\n },\n },\n },\n\n /**\n * Requests an item from a batched API\n * @param {Object} item\n * @returns {Promise<mixed>}\n */\n request(item) {\n // So far, I can't find a way to avoid three layers of nesting here.\n /* eslint max-nested-callbacks: [0] */\n const defer = new Defer();\n\n this.fingerprintRequest(item)\n .then((idx) => {\n if (this.deferreds.has(idx)) {\n defer.resolve(this.deferreds.get(idx).promise);\n\n return;\n }\n this.deferreds.set(idx, defer);\n this.prepareItem(item)\n .then((req) => {\n defer.promise = defer.promise\n .then(tap(() => this.deferreds.delete(idx)))\n .catch((reason) => {\n this.deferreds.delete(idx);\n\n return Promise.reject(reason);\n });\n\n this.enqueue(req)\n .then(() => this.bounce())\n .catch((reason) => defer.reject(reason));\n })\n .catch((reason) => defer.reject(reason));\n })\n .catch((reason) => defer.reject(reason));\n\n return defer.promise;\n },\n\n /**\n * Adds an item to the queue.\n * Intended to be overridden\n * @param {mixed} req\n * @returns {Promise<undefined>}\n */\n enqueue(req) {\n this.queue.push(req);\n\n return Promise.resolve();\n },\n\n /**\n * Transform the item before adding it to the queue\n * Intended to be overridden\n * @param {mixed} item\n * @returns {Promise<mixed>}\n */\n prepareItem(item) {\n return Promise.resolve(item);\n },\n\n /**\n * Detaches the current queue, does any appropriate transforms, and submits it\n * to the API.\n * @returns {Promise<undefined>}\n */\n executeQueue() {\n const queue = this.queue.splice(0, this.config.batcherMaxCalls);\n\n return new Promise((resolve) => {\n resolve(\n this.prepareRequest(queue)\n .then((payload) =>\n this.submitHttpRequest(payload).then((res) => this.handleHttpSuccess(res))\n )\n .catch((reason) => {\n if (reason instanceof WebexHttpError) {\n return this.handleHttpError(reason);\n }\n\n return Promise.all(\n queue.map((item) =>\n this.getDeferredForRequest(item).then((defer) => {\n defer.reject(reason);\n })\n )\n );\n })\n );\n }).catch((reason) => {\n this.logger.error(process.env.NODE_ENV === 'production' ? reason : reason.stack);\n\n return Promise.reject(reason);\n });\n },\n\n /**\n * Performs any final transforms on the queue before submitting it to the API\n * Intended to be overridden\n * @param {Object|Array} queue\n * @returns {Promise<Object>}\n */\n prepareRequest(queue) {\n return Promise.resolve(queue);\n },\n\n /**\n * Submits the prepared request body to the API.\n * This method *must* be overridden\n * @param {Object} payload\n * @returns {Promise<HttpResponseObject>}\n */\n // eslint-disable-next-line no-unused-vars\n submitHttpRequest(payload) {\n throw new Error('request() must be implemented');\n },\n\n /**\n * Actions taken when the http request returns a success\n * Intended to be overridden\n * @param {Promise<HttpResponseObject>} res\n * @returns {Promise<undefined>}\n */\n handleHttpSuccess(res) {\n return Promise.all(\n ((res.body && res.body.items) || res.body).map((item) => this.acceptItem(item))\n );\n },\n\n /**\n * Actions taken when the http request returns a failure. Typically, this\n * means failing the entire queue, but could be overridden in some\n * implementations to e.g. reenqueue.\n * Intended to be overridden\n * @param {WebexHttpError} reason\n * @returns {Promise<undefined>}\n */\n handleHttpError(reason) {\n if (reason instanceof WebexHttpError) {\n if (has(reason, 'options.body.map')) {\n return Promise.all(\n reason.options.body.map((item) =>\n this.getDeferredForRequest(item).then((defer) => {\n defer.reject(reason);\n })\n )\n );\n }\n }\n this.logger.error('http error handler called without a WebexHttpError object', reason);\n\n return Promise.reject(reason);\n },\n\n /**\n * Determines if the item succeeded or failed and delegates accordingly\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n acceptItem(item) {\n return this.didItemFail(item).then((didFail) => {\n if (didFail) {\n return this.handleItemFailure(item);\n }\n\n return this.handleItemSuccess(item);\n });\n },\n\n /**\n * Indicates if the specified response item implies a success or a failure\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<Boolean>}\n */\n // eslint-disable-next-line no-unused-vars\n didItemFail(item) {\n return Promise.resolve(false);\n },\n\n /**\n * Finds the Defer for the specified item and rejects its promise\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n handleItemFailure(item) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.reject(item);\n });\n },\n\n /**\n * Finds the Defer for the specified item and resolves its promise\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n handleItemSuccess(item) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.resolve(item);\n });\n },\n\n /**\n * Returns the Deferred for the specified request item\n * @param {Object} item\n * @returns {Promise<Defer>}\n */\n getDeferredForRequest(item) {\n return this.fingerprintRequest(item).then((idx) => {\n const defer = this.deferreds.get(idx);\n\n /* istanbul ignore if */\n if (!defer) {\n throw new Error('Could not find pending request for received response');\n }\n\n return defer;\n });\n },\n\n /**\n * Returns the Deferred for the specified response item\n * @param {Object} item\n * @returns {Promise<Defer>}\n */\n getDeferredForResponse(item) {\n return this.fingerprintResponse(item).then((idx) => {\n const defer = this.deferreds.get(idx);\n\n /* istanbul ignore if */\n if (!defer) {\n throw new Error('Could not find pending request for received response');\n }\n\n return defer;\n });\n },\n\n /**\n * Generates a unique identifier for the item in a request payload\n * Intended to be overridden\n * Note that overrides must return a primitive.\n * @param {Object} item\n * @returns {Promise<primitive>}\n */\n // eslint-disable-next-line no-unused-vars\n fingerprintRequest(item) {\n throw new Error('fingerprintRequest() must be implemented');\n },\n\n /**\n * Generates a unique identifier for the item in a response payload\n * Intended to be overridden\n * Note that overrides must return a primitive.\n * @param {Object} item\n * @returns {Promise<primitive>}\n */\n // eslint-disable-next-line no-unused-vars\n fingerprintResponse(item) {\n throw new Error('fingerprintResponse() must be implemented');\n },\n});\n\nexport default Batcher;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_lodash","require","_common","_webexPlugin","_interopRequireDefault","_webexHttpError","Batcher","WebexPlugin","extend","session","deferreds","type","default","_map","queue","derived","bounce","fn","_this","cappedDebounce","executeQueue","apply","arguments","config","batcherWait","maxCalls","batcherMaxCalls","maxWait","batcherMaxWait","request","item","_this2","defer","Defer","fingerprintRequest","then","idx","has","resolve","get","promise","set","prepareItem","req","delete","enqueue","catch","reason","reject","push","_promise","_this3","splice","prepareRequest","payload","submitHttpRequest","res","handleHttpSuccess","WebexHttpError","handleHttpError","all","map","getDeferredForRequest","logger","error","process","env","NODE_ENV","stack","undefined","Error","_this4","body","items","acceptItem","_this5","options","_this6","didItemFail","didFail","handleItemFailure","handleItemSuccess","getDeferredForResponse","_this7","_this8","fingerprintResponse","version","_default2","exports"],"sources":["batcher.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {has} from 'lodash';\nimport {cappedDebounce, Defer} from '@webex/common';\n\nimport WebexPlugin from './webex-plugin';\nimport WebexHttpError from './webex-http-error';\n\n/**\n * Base class for coalescing requests to batched APIs\n * @class Batcher\n */\nconst Batcher = WebexPlugin.extend({\n session: {\n deferreds: {\n type: 'object',\n default() {\n return new Map();\n },\n },\n queue: {\n type: 'array',\n default() {\n return [];\n },\n },\n },\n\n derived: {\n bounce: {\n fn() {\n return cappedDebounce((...args) => this.executeQueue(...args), this.config.batcherWait, {\n maxCalls: this.config.batcherMaxCalls,\n maxWait: this.config.batcherMaxWait,\n });\n },\n },\n },\n\n /**\n * Requests an item from a batched API\n * @param {Object} item\n * @returns {Promise<mixed>}\n */\n request(item) {\n // So far, I can't find a way to avoid three layers of nesting here.\n /* eslint max-nested-callbacks: [0] */\n const defer = new Defer();\n\n this.fingerprintRequest(item)\n .then((idx) => {\n if (this.deferreds.has(idx)) {\n defer.resolve(this.deferreds.get(idx).promise);\n\n return;\n }\n this.deferreds.set(idx, defer);\n this.prepareItem(item)\n .then((req) => {\n // Attach cleanup handlers to the original deferred promise without\n // creating an unobserved rejected chain.\n defer.promise.then(\n () => this.deferreds.delete(idx),\n () => this.deferreds.delete(idx)\n );\n\n this.enqueue(req)\n .then(() => this.bounce())\n .catch((reason) => defer.reject(reason));\n })\n .catch((reason) => defer.reject(reason));\n })\n .catch((reason) => defer.reject(reason));\n\n return defer.promise;\n },\n\n /**\n * Adds an item to the queue.\n * Intended to be overridden\n * @param {mixed} req\n * @returns {Promise<undefined>}\n */\n enqueue(req) {\n this.queue.push(req);\n\n return Promise.resolve();\n },\n\n /**\n * Transform the item before adding it to the queue\n * Intended to be overridden\n * @param {mixed} item\n * @returns {Promise<mixed>}\n */\n prepareItem(item) {\n return Promise.resolve(item);\n },\n\n /**\n * Detaches the current queue, does any appropriate transforms, and submits it\n * to the API.\n * @returns {Promise<undefined>}\n */\n executeQueue() {\n const queue = this.queue.splice(0, this.config.batcherMaxCalls);\n\n return new Promise((resolve) => {\n resolve(\n this.prepareRequest(queue)\n .then((payload) =>\n this.submitHttpRequest(payload).then((res) => this.handleHttpSuccess(res))\n )\n .catch((reason) => {\n if (reason instanceof WebexHttpError) {\n // Some batched requests (for example GET-based batches) do not\n // have reason.options.body, so handleHttpError() may reject\n // without failing queued deferreds. Fallback to rejecting each\n // queued request to ensure caller promises settle.\n return this.handleHttpError(reason).catch(() =>\n Promise.all(\n queue.map((item) =>\n this.getDeferredForRequest(item).then((defer) => {\n defer.reject(reason);\n })\n )\n )\n );\n }\n\n return Promise.all(\n queue.map((item) =>\n this.getDeferredForRequest(item).then((defer) => {\n defer.reject(reason);\n })\n )\n );\n })\n );\n }).catch((reason) => {\n this.logger.error(process.env.NODE_ENV === 'production' ? reason : reason.stack);\n // executeQueue() is triggered via cappedDebounce(), which does not\n // propagate promise chains. Re-throwing here causes global unhandled\n // promise rejections even when request callers handle their own promise.\n // Any known queued requests have already been failed above.\n\n return undefined;\n });\n },\n\n /**\n * Performs any final transforms on the queue before submitting it to the API\n * Intended to be overridden\n * @param {Object|Array} queue\n * @returns {Promise<Object>}\n */\n prepareRequest(queue) {\n return Promise.resolve(queue);\n },\n\n /**\n * Submits the prepared request body to the API.\n * This method *must* be overridden\n * @param {Object} payload\n * @returns {Promise<HttpResponseObject>}\n */\n // eslint-disable-next-line no-unused-vars\n submitHttpRequest(payload) {\n throw new Error('request() must be implemented');\n },\n\n /**\n * Actions taken when the http request returns a success\n * Intended to be overridden\n * @param {Promise<HttpResponseObject>} res\n * @returns {Promise<undefined>}\n */\n handleHttpSuccess(res) {\n return Promise.all(\n ((res.body && res.body.items) || res.body).map((item) => this.acceptItem(item))\n );\n },\n\n /**\n * Actions taken when the http request returns a failure. Typically, this\n * means failing the entire queue, but could be overridden in some\n * implementations to e.g. reenqueue.\n * Intended to be overridden\n * @param {WebexHttpError} reason\n * @returns {Promise<undefined>}\n */\n handleHttpError(reason) {\n if (reason instanceof WebexHttpError) {\n if (has(reason, 'options.body.map')) {\n return Promise.all(\n reason.options.body.map((item) =>\n this.getDeferredForRequest(item).then((defer) => {\n defer.reject(reason);\n })\n )\n );\n }\n }\n this.logger.error('http error handler called without a WebexHttpError object', reason);\n\n return Promise.reject(reason);\n },\n\n /**\n * Determines if the item succeeded or failed and delegates accordingly\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n acceptItem(item) {\n return this.didItemFail(item).then((didFail) => {\n if (didFail) {\n return this.handleItemFailure(item);\n }\n\n return this.handleItemSuccess(item);\n });\n },\n\n /**\n * Indicates if the specified response item implies a success or a failure\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<Boolean>}\n */\n // eslint-disable-next-line no-unused-vars\n didItemFail(item) {\n return Promise.resolve(false);\n },\n\n /**\n * Finds the Defer for the specified item and rejects its promise\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n handleItemFailure(item) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.reject(item);\n });\n },\n\n /**\n * Finds the Defer for the specified item and resolves its promise\n * Intended to be overridden\n * @param {Object} item\n * @returns {Promise<undefined>}\n */\n handleItemSuccess(item) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.resolve(item);\n });\n },\n\n /**\n * Returns the Deferred for the specified request item\n * @param {Object} item\n * @returns {Promise<Defer>}\n */\n getDeferredForRequest(item) {\n return this.fingerprintRequest(item).then((idx) => {\n const defer = this.deferreds.get(idx);\n\n /* istanbul ignore if */\n if (!defer) {\n throw new Error('Could not find pending request for received response');\n }\n\n return defer;\n });\n },\n\n /**\n * Returns the Deferred for the specified response item\n * @param {Object} item\n * @returns {Promise<Defer>}\n */\n getDeferredForResponse(item) {\n return this.fingerprintResponse(item).then((idx) => {\n const defer = this.deferreds.get(idx);\n\n /* istanbul ignore if */\n if (!defer) {\n throw new Error('Could not find pending request for received response');\n }\n\n return defer;\n });\n },\n\n /**\n * Generates a unique identifier for the item in a request payload\n * Intended to be overridden\n * Note that overrides must return a primitive.\n * @param {Object} item\n * @returns {Promise<primitive>}\n */\n // eslint-disable-next-line no-unused-vars\n fingerprintRequest(item) {\n throw new Error('fingerprintRequest() must be implemented');\n },\n\n /**\n * Generates a unique identifier for the item in a response payload\n * Intended to be overridden\n * Note that overrides must return a primitive.\n * @param {Object} item\n * @returns {Promise<primitive>}\n */\n // eslint-disable-next-line no-unused-vars\n fingerprintResponse(item) {\n throw new Error('fingerprintResponse() must be implemented');\n },\n});\n\nexport default Batcher;\n"],"mappings":"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","ignoreList":[]}
@@ -556,7 +556,7 @@ var Credentials = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
556
556
  this.refresh();
557
557
  }
558
558
  },
559
- version: "3.12.0-mobius-socket.2"
559
+ version: "3.12.0-mobius-socket.3"
560
560
  }, (0, _applyDecoratedDescriptor2.default)(_obj, "getUserToken", [_dec, _dec2], (0, _getOwnPropertyDescriptor.default)(_obj, "getUserToken"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "initialize", [_dec3], (0, _getOwnPropertyDescriptor.default)(_obj, "initialize"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "invalidate", [_common.oneFlight, _dec4], (0, _getOwnPropertyDescriptor.default)(_obj, "invalidate"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "refresh", [_common.oneFlight, _dec5, _dec6], (0, _getOwnPropertyDescriptor.default)(_obj, "refresh"), _obj), _obj));
561
561
  var _default = exports.default = Credentials;
562
562
  //# sourceMappingURL=credentials.js.map
@@ -532,7 +532,7 @@ var Token = _webexPlugin.default.extend((_dec = (0, _common.oneFlight)({
532
532
  return res.body;
533
533
  });
534
534
  },
535
- version: "3.12.0-mobius-socket.2"
535
+ version: "3.12.0-mobius-socket.3"
536
536
  }, (0, _applyDecoratedDescriptor2.default)(_obj, "downscope", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "downscope"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "refresh", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "refresh"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "revoke", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "revoke"), _obj), _obj));
537
537
  var _default = exports.default = Token;
538
538
  //# sourceMappingURL=token.js.map
@@ -1443,7 +1443,7 @@ var Services = _webexPlugin.default.extend({
1443
1443
  }, _callee4);
1444
1444
  })));
1445
1445
  },
1446
- version: "3.12.0-mobius-socket.2"
1446
+ version: "3.12.0-mobius-socket.3"
1447
1447
  });
1448
1448
  /* eslint-enable no-underscore-dangle */
1449
1449
  var _default = exports.default = Services;
@@ -1373,7 +1373,7 @@ var Services = _webexPlugin.default.extend({
1373
1373
  }, _callee3);
1374
1374
  })));
1375
1375
  },
1376
- version: "3.12.0-mobius-socket.2"
1376
+ version: "3.12.0-mobius-socket.3"
1377
1377
  });
1378
1378
  /* eslint-enable no-underscore-dangle */
1379
1379
  var _default = exports.default = Services;
@@ -57,7 +57,7 @@ var Logger = _webexPlugin.default.extend({
57
57
  info: wrapConsoleMethod('info'),
58
58
  debug: wrapConsoleMethod('debug'),
59
59
  trace: wrapConsoleMethod('trace'),
60
- version: "3.12.0-mobius-socket.2"
60
+ version: "3.12.0-mobius-socket.3"
61
61
  });
62
62
  (0, _webexCore.registerPlugin)('logger', Logger);
63
63
  var _default = exports.default = Logger;
@@ -96,7 +96,7 @@ var MAX_FILE_SIZE_IN_MB = 2048;
96
96
  * @class
97
97
  */
98
98
  var WebexCore = _ampersandState.default.extend((_obj = {
99
- version: "3.12.0-mobius-socket.2",
99
+ version: "3.12.0-mobius-socket.3",
100
100
  children: {
101
101
  internal: _webexInternalCore.default
102
102
  },
@@ -634,7 +634,7 @@ var WebexCore = _ampersandState.default.extend((_obj = {
634
634
  });
635
635
  }
636
636
  }, (0, _applyDecoratedDescriptor2.default)(_obj, "_uploadPhaseUpload", [_common.retry], (0, _getOwnPropertyDescriptor.default)(_obj, "_uploadPhaseUpload"), _obj), _obj));
637
- WebexCore.version = "3.12.0-mobius-socket.2";
637
+ WebexCore.version = "3.12.0-mobius-socket.3";
638
638
  (0, _webexInternalCorePluginMixin.default)(_webexInternalCore.default, _config.default, interceptors);
639
639
  (0, _webexCorePluginMixin.default)(WebexCore, _config.default, interceptors);
640
640
  var _default = exports.default = WebexCore;
package/package.json CHANGED
@@ -33,16 +33,16 @@
33
33
  "@sinonjs/fake-timers": "^6.0.1",
34
34
  "@webex/babel-config-legacy": "0.0.0",
35
35
  "@webex/eslint-config-legacy": "0.0.0",
36
- "@webex/internal-plugin-device": "3.12.0-mobius-socket.2",
36
+ "@webex/internal-plugin-device": "3.12.0-mobius-socket.3",
37
37
  "@webex/jest-config-legacy": "0.0.0",
38
38
  "@webex/legacy-tools": "0.0.0",
39
- "@webex/plugin-logger": "3.12.0-mobius-socket.2",
40
- "@webex/test-helper-chai": "3.12.0-mobius-socket.1",
41
- "@webex/test-helper-make-local-url": "3.12.0-mobius-socket.1",
42
- "@webex/test-helper-mocha": "3.12.0-mobius-socket.1",
43
- "@webex/test-helper-mock-webex": "3.12.0-mobius-socket.1",
44
- "@webex/test-helper-refresh-callback": "3.12.0-mobius-socket.1",
45
- "@webex/test-helper-test-users": "3.12.0-mobius-socket.1",
39
+ "@webex/plugin-logger": "3.12.0-mobius-socket.3",
40
+ "@webex/test-helper-chai": "3.12.0-mobius-socket.2",
41
+ "@webex/test-helper-make-local-url": "3.12.0-mobius-socket.2",
42
+ "@webex/test-helper-mocha": "3.12.0-mobius-socket.2",
43
+ "@webex/test-helper-mock-webex": "3.12.0-mobius-socket.2",
44
+ "@webex/test-helper-refresh-callback": "3.12.0-mobius-socket.2",
45
+ "@webex/test-helper-test-users": "3.12.0-mobius-socket.2",
46
46
  "chai": "^4.3.4",
47
47
  "chai-as-promised": "^7.1.1",
48
48
  "eslint": "^8.24.0",
@@ -50,10 +50,10 @@
50
50
  "sinon": "^9.2.4"
51
51
  },
52
52
  "dependencies": {
53
- "@webex/common": "3.12.0-mobius-socket.1",
54
- "@webex/common-timers": "3.12.0-mobius-socket.1",
55
- "@webex/http-core": "3.12.0-mobius-socket.1",
56
- "@webex/storage-adapter-spec": "3.12.0-mobius-socket.1",
53
+ "@webex/common": "3.12.0-mobius-socket.2",
54
+ "@webex/common-timers": "3.12.0-mobius-socket.2",
55
+ "@webex/http-core": "3.12.0-mobius-socket.2",
56
+ "@webex/storage-adapter-spec": "3.12.0-mobius-socket.2",
57
57
  "ampersand-collection": "^2.0.2",
58
58
  "ampersand-events": "^2.0.2",
59
59
  "ampersand-state": "^5.0.3",
@@ -73,5 +73,5 @@
73
73
  "test:style": "eslint ./src/**/*.*",
74
74
  "test:unit": "webex-legacy-tools test --unit --runner jest"
75
75
  },
76
- "version": "3.12.0-mobius-socket.2"
76
+ "version": "3.12.0-mobius-socket.3"
77
77
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import {has} from 'lodash';
6
- import {cappedDebounce, Defer, tap} from '@webex/common';
6
+ import {cappedDebounce, Defer} from '@webex/common';
7
7
 
8
8
  import WebexPlugin from './webex-plugin';
9
9
  import WebexHttpError from './webex-http-error';
@@ -59,13 +59,12 @@ const Batcher = WebexPlugin.extend({
59
59
  this.deferreds.set(idx, defer);
60
60
  this.prepareItem(item)
61
61
  .then((req) => {
62
- defer.promise = defer.promise
63
- .then(tap(() => this.deferreds.delete(idx)))
64
- .catch((reason) => {
65
- this.deferreds.delete(idx);
66
-
67
- return Promise.reject(reason);
68
- });
62
+ // Attach cleanup handlers to the original deferred promise without
63
+ // creating an unobserved rejected chain.
64
+ defer.promise.then(
65
+ () => this.deferreds.delete(idx),
66
+ () => this.deferreds.delete(idx)
67
+ );
69
68
 
70
69
  this.enqueue(req)
71
70
  .then(() => this.bounce())
@@ -116,7 +115,19 @@ const Batcher = WebexPlugin.extend({
116
115
  )
117
116
  .catch((reason) => {
118
117
  if (reason instanceof WebexHttpError) {
119
- return this.handleHttpError(reason);
118
+ // Some batched requests (for example GET-based batches) do not
119
+ // have reason.options.body, so handleHttpError() may reject
120
+ // without failing queued deferreds. Fallback to rejecting each
121
+ // queued request to ensure caller promises settle.
122
+ return this.handleHttpError(reason).catch(() =>
123
+ Promise.all(
124
+ queue.map((item) =>
125
+ this.getDeferredForRequest(item).then((defer) => {
126
+ defer.reject(reason);
127
+ })
128
+ )
129
+ )
130
+ );
120
131
  }
121
132
 
122
133
  return Promise.all(
@@ -130,8 +141,12 @@ const Batcher = WebexPlugin.extend({
130
141
  );
131
142
  }).catch((reason) => {
132
143
  this.logger.error(process.env.NODE_ENV === 'production' ? reason : reason.stack);
144
+ // executeQueue() is triggered via cappedDebounce(), which does not
145
+ // propagate promise chains. Re-throwing here causes global unhandled
146
+ // promise rejections even when request callers handle their own promise.
147
+ // Any known queued requests have already been failed above.
133
148
 
134
- return Promise.reject(reason);
149
+ return undefined;
135
150
  });
136
151
  },
137
152
 
@@ -7,6 +7,7 @@ import {assert} from '@webex/test-helper-chai';
7
7
  import MockWebex from '@webex/test-helper-mock-webex';
8
8
  import sinon from 'sinon';
9
9
  import {Batcher} from '@webex/webex-core';
10
+ import WebexHttpError from '../../../../src/lib/webex-http-error';
10
11
 
11
12
  function promiseTick(count) {
12
13
  let promise = Promise.resolve();
@@ -154,6 +155,61 @@ describe('webex-core', () => {
154
155
  return Promise.all([assert.isRejected(p1), assert.isRejected(p2)]);
155
156
  });
156
157
  });
158
+
159
+ it('does not trigger unhandledRejection when caller handles rejection', () => {
160
+ const unhandled = [];
161
+ const onUnhandledRejection = (reason) => {
162
+ unhandled.push(reason);
163
+ };
164
+
165
+ process.on('unhandledRejection', onUnhandledRejection);
166
+
167
+ const p = webex.internal.batcher.request(1);
168
+
169
+ // eslint-disable-next-line prefer-promise-reject-errors
170
+ webex.request.returns(Promise.reject({statusCode: 0}));
171
+
172
+ return promiseTick(50)
173
+ .then(() => clock.tick(2))
174
+ .then(() => promiseTick(50))
175
+ .then(() => assert.isRejected(p))
176
+ .then(() => promiseTick(50))
177
+ .then(() => {
178
+ assert.lengthOf(unhandled, 0);
179
+ })
180
+ .finally(() => {
181
+ process.removeListener('unhandledRejection', onUnhandledRejection);
182
+ });
183
+ });
184
+
185
+ it('fails queued deferreds for webex http errors without request body', () => {
186
+ const p1 = webex.internal.batcher.request(1);
187
+ const p2 = webex.internal.batcher.request(2);
188
+ const reason = new WebexHttpError.BadRequest({
189
+ statusCode: 400,
190
+ body: {message: 'simulated failure'},
191
+ options: {
192
+ method: 'GET',
193
+ uri: 'https://example.com/v1/mock/batch',
194
+ headers: {trackingid: 'test-tracking-id'},
195
+ },
196
+ headers: {},
197
+ });
198
+
199
+ webex.request.returns(Promise.reject(reason));
200
+
201
+ return promiseTick(50)
202
+ .then(() => clock.tick(2))
203
+ .then(() => promiseTick(50))
204
+ .then(() => {
205
+ assert.calledOnce(webex.request);
206
+
207
+ return Promise.all([
208
+ assert.isRejected(p1, /simulated failure/),
209
+ assert.isRejected(p2, /simulated failure/),
210
+ ]);
211
+ });
212
+ });
157
213
  });
158
214
 
159
215
  describe('when the number of request attempts exceeds a given threshold', () => {