@webex/internal-plugin-llm 3.11.0 → 3.12.0-auth-prejoin-fetch.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.
- package/README.md +83 -12
- package/dist/constants.js +9 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/llm.js +532 -51
- package/dist/llm.js.map +1 -1
- package/dist/llm.types.js +10 -0
- package/dist/llm.types.js.map +1 -1
- package/package.json +6 -6
- package/src/constants.ts +13 -0
- package/src/index.ts +5 -0
- package/src/llm.ts +539 -34
- package/src/llm.types.ts +75 -6
- package/test/unit/spec/llm.js +736 -51
package/dist/llm.js
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
|
|
4
|
+
var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
|
|
5
|
+
var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
|
|
6
|
+
var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
|
|
7
|
+
var _Array$isArray = require("@babel/runtime-corejs2/core-js/array/is-array");
|
|
4
8
|
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
|
|
5
9
|
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
|
|
6
10
|
_Object$defineProperty(exports, "__esModule", {
|
|
7
11
|
value: true
|
|
8
12
|
});
|
|
9
13
|
exports.default = exports.config = void 0;
|
|
10
|
-
var
|
|
14
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
|
|
15
|
+
var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
|
|
16
|
+
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
17
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
|
|
18
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
|
|
11
19
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
20
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
|
|
12
21
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
|
|
13
22
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
|
|
14
23
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
|
|
15
|
-
var
|
|
24
|
+
var _defineProperty3 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
16
25
|
var _internalPluginMercury = _interopRequireDefault(require("@webex/internal-plugin-mercury"));
|
|
17
26
|
var _constants = require("./constants");
|
|
27
|
+
var _llm = require("./llm.types");
|
|
28
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof _Symbol && r[_Symbol$iterator] || r["@@iterator"]; if (!t) { if (_Array$isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
29
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? _Array$from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
30
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
18
31
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
19
|
-
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /* eslint-disable consistent-return */
|
|
20
|
-
// eslint-disable-next-line no-unused-vars
|
|
21
|
-
|
|
32
|
+
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /* eslint-disable consistent-return */ // eslint-disable-next-line no-unused-vars
|
|
22
33
|
var config = exports.config = {
|
|
23
34
|
llm: {
|
|
24
35
|
/**
|
|
@@ -61,95 +72,565 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
61
72
|
args[_key] = arguments[_key];
|
|
62
73
|
}
|
|
63
74
|
_this = _callSuper(this, LLMChannel, [].concat(args));
|
|
64
|
-
(0,
|
|
75
|
+
(0, _defineProperty3.default)(_this, "namespace", _constants.LLM);
|
|
76
|
+
(0, _defineProperty3.default)(_this, "defaultSessionId", _constants.LLM_DEFAULT_SESSION);
|
|
65
77
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* @
|
|
69
|
-
* @
|
|
78
|
+
* Map to store connection-specific data for multiple LLM connections
|
|
79
|
+
* Key: sessionId
|
|
80
|
+
* @private
|
|
81
|
+
* @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}
|
|
70
82
|
*/
|
|
71
|
-
(0,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
(0,
|
|
83
|
+
(0, _defineProperty3.default)(_this, "connections", new _map.default());
|
|
84
|
+
// Session-keyed token cache is intentionally decoupled from connection state.
|
|
85
|
+
// Disconnecting a socket session must not implicitly wipe token cache.
|
|
86
|
+
(0, _defineProperty3.default)(_this, "datachannelTokens", (0, _defineProperty3.default)((0, _defineProperty3.default)({}, _llm.DataChannelTokenType.Default, undefined), _llm.DataChannelTokenType.PracticeSession, undefined));
|
|
75
87
|
/**
|
|
76
88
|
* Register to the websocket
|
|
77
89
|
* @param {string} llmSocketUrl
|
|
90
|
+
* @param {string} datachannelToken
|
|
91
|
+
* @param {string} sessionId - Connection identifier
|
|
78
92
|
* @returns {Promise<void>}
|
|
79
93
|
*/
|
|
80
|
-
(0,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
(0, _defineProperty3.default)(_this, "register", /*#__PURE__*/function () {
|
|
95
|
+
var _ref2 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee(llmSocketUrl, datachannelToken) {
|
|
96
|
+
var sessionId,
|
|
97
|
+
isDataChannelTokenEnabled,
|
|
98
|
+
_args = arguments;
|
|
99
|
+
return _regenerator.default.wrap(function (_context) {
|
|
100
|
+
while (1) switch (_context.prev = _context.next) {
|
|
101
|
+
case 0:
|
|
102
|
+
sessionId = _args.length > 2 && _args[2] !== undefined ? _args[2] : _constants.LLM_DEFAULT_SESSION;
|
|
103
|
+
_context.next = 1;
|
|
104
|
+
return _this.isDataChannelTokenEnabled();
|
|
105
|
+
case 1:
|
|
106
|
+
isDataChannelTokenEnabled = _context.sent;
|
|
107
|
+
return _context.abrupt("return", _this.request({
|
|
108
|
+
method: 'POST',
|
|
109
|
+
url: llmSocketUrl,
|
|
110
|
+
body: {
|
|
111
|
+
deviceUrl: _this.webex.internal.device.url
|
|
112
|
+
},
|
|
113
|
+
headers: isDataChannelTokenEnabled && datachannelToken ? {
|
|
114
|
+
'Data-Channel-Auth-Token': datachannelToken
|
|
115
|
+
} : {}
|
|
116
|
+
}).then(function (res) {
|
|
117
|
+
// Get or create connection data
|
|
118
|
+
var sessionData = _this.connections.get(sessionId) || {};
|
|
119
|
+
sessionData.webSocketUrl = res.body.webSocketUrl;
|
|
120
|
+
sessionData.binding = res.body.binding;
|
|
121
|
+
_this.connections.set(sessionId, sessionData);
|
|
122
|
+
}).catch(function (error) {
|
|
123
|
+
_this.logger.error("Error connecting to websocket for ".concat(sessionId, ": ").concat(error));
|
|
124
|
+
throw error;
|
|
125
|
+
}));
|
|
126
|
+
case 2:
|
|
127
|
+
case "end":
|
|
128
|
+
return _context.stop();
|
|
129
|
+
}
|
|
130
|
+
}, _callee);
|
|
131
|
+
}));
|
|
132
|
+
return function (_x, _x2) {
|
|
133
|
+
return _ref2.apply(this, arguments);
|
|
134
|
+
};
|
|
135
|
+
}());
|
|
95
136
|
/**
|
|
96
137
|
* Register and connect to the websocket
|
|
97
138
|
* @param {string} locusUrl
|
|
98
139
|
* @param {string} datachannelUrl
|
|
140
|
+
* @param {string} datachannelToken
|
|
141
|
+
* @param {string} sessionId - Connection identifier
|
|
99
142
|
* @returns {Promise<void>}
|
|
100
143
|
*/
|
|
101
|
-
(0,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
144
|
+
(0, _defineProperty3.default)(_this, "registerAndConnect", function (locusUrl, datachannelUrl, datachannelToken) {
|
|
145
|
+
var sessionId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants.LLM_DEFAULT_SESSION;
|
|
146
|
+
var registerStart = performance.now();
|
|
147
|
+
|
|
148
|
+
// Pre-populate locusUrl and datachannelUrl before register() fires the
|
|
149
|
+
// HTTP POST, so that any token refresh triggered during registration can
|
|
150
|
+
// be routed via connections without falling back to a locusInfo URL scan.
|
|
151
|
+
if (locusUrl && datachannelUrl) {
|
|
152
|
+
var sessionData = _this.connections.get(sessionId) || {};
|
|
153
|
+
sessionData.locusUrl = locusUrl;
|
|
154
|
+
sessionData.datachannelUrl = datachannelUrl;
|
|
155
|
+
_this.connections.set(sessionId, sessionData);
|
|
156
|
+
}
|
|
157
|
+
return _this.register(datachannelUrl, datachannelToken, sessionId).then(/*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
158
|
+
var clientLLMDatachannelResponseTime, sessionData, error, isDataChannelTokenEnabled, connectUrl, connectStart, clientLLMWebSocketConnectTime, _t;
|
|
159
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
160
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
161
|
+
case 0:
|
|
162
|
+
if (!(!locusUrl || !datachannelUrl)) {
|
|
163
|
+
_context2.next = 1;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
return _context2.abrupt("return", undefined);
|
|
167
|
+
case 1:
|
|
168
|
+
clientLLMDatachannelResponseTime = Math.round(performance.now() - registerStart); // locusUrl and datachannelUrl were pre-populated before register(); here
|
|
169
|
+
// we only need to read the existing session data to get webSocketUrl/binding
|
|
170
|
+
// that register() filled in.
|
|
171
|
+
sessionData = _this.connections.get(sessionId) || {};
|
|
172
|
+
if (sessionData.webSocketUrl) {
|
|
173
|
+
_context2.next = 2;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
// register() succeeded but the response carried no websocket URL. Attach the measured
|
|
177
|
+
// datachannel time so callers don't misreport a registration that completed as time 0.
|
|
178
|
+
error = new Error("LLM registration for ".concat(sessionId, " returned no websocket URL"));
|
|
179
|
+
error.timing = {
|
|
180
|
+
clientLLMDatachannelResponseTime: clientLLMDatachannelResponseTime
|
|
181
|
+
};
|
|
182
|
+
throw error;
|
|
183
|
+
case 2:
|
|
184
|
+
_context2.next = 3;
|
|
185
|
+
return _this.isDataChannelTokenEnabled();
|
|
186
|
+
case 3:
|
|
187
|
+
isDataChannelTokenEnabled = _context2.sent;
|
|
188
|
+
connectUrl = isDataChannelTokenEnabled ? LLMChannel.buildUrlWithAwareSubchannels(sessionData.webSocketUrl, _constants.AWARE_DATA_CHANNEL) : sessionData.webSocketUrl;
|
|
189
|
+
connectStart = performance.now();
|
|
190
|
+
_context2.prev = 4;
|
|
191
|
+
_context2.next = 5;
|
|
192
|
+
return _this.connect(connectUrl, sessionId);
|
|
193
|
+
case 5:
|
|
194
|
+
_context2.next = 7;
|
|
195
|
+
break;
|
|
196
|
+
case 6:
|
|
197
|
+
_context2.prev = 6;
|
|
198
|
+
_t = _context2["catch"](4);
|
|
199
|
+
// register() succeeded; only connect() failed. Attach the measured datachannel time so
|
|
200
|
+
// callers don't misreport a websocket failure as a registration that never completed.
|
|
201
|
+
// @ts-ignore
|
|
202
|
+
_t.timing = {
|
|
203
|
+
clientLLMDatachannelResponseTime: clientLLMDatachannelResponseTime
|
|
204
|
+
};
|
|
205
|
+
throw _t;
|
|
206
|
+
case 7:
|
|
207
|
+
clientLLMWebSocketConnectTime = Math.round(performance.now() - connectStart);
|
|
208
|
+
return _context2.abrupt("return", {
|
|
209
|
+
clientLLMDatachannelResponseTime: clientLLMDatachannelResponseTime,
|
|
210
|
+
clientLLMWebSocketConnectTime: clientLLMWebSocketConnectTime
|
|
211
|
+
});
|
|
212
|
+
case 8:
|
|
213
|
+
case "end":
|
|
214
|
+
return _context2.stop();
|
|
215
|
+
}
|
|
216
|
+
}, _callee2, null, [[4, 6]]);
|
|
217
|
+
})));
|
|
108
218
|
});
|
|
109
219
|
/**
|
|
110
220
|
* Tells if LLM socket is connected
|
|
221
|
+
* @param {string} sessionId - Connection identifier
|
|
111
222
|
* @returns {boolean} connected
|
|
112
223
|
*/
|
|
113
|
-
(0,
|
|
114
|
-
|
|
224
|
+
(0, _defineProperty3.default)(_this, "isConnected", function () {
|
|
225
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
226
|
+
var socket = _this.getSocket(sessionId);
|
|
227
|
+
return socket ? socket.connected : false;
|
|
115
228
|
});
|
|
116
229
|
/**
|
|
117
230
|
* Tells if LLM socket is binding
|
|
231
|
+
* @param {string} sessionId - Connection identifier
|
|
118
232
|
* @returns {string} binding
|
|
119
233
|
*/
|
|
120
|
-
(0,
|
|
121
|
-
|
|
234
|
+
(0, _defineProperty3.default)(_this, "getBinding", function () {
|
|
235
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
236
|
+
var sessionData = _this.connections.get(sessionId);
|
|
237
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.binding;
|
|
122
238
|
});
|
|
123
239
|
/**
|
|
124
240
|
* Get Locus URL for the connection
|
|
241
|
+
* @param {string} sessionId - Connection identifier
|
|
125
242
|
* @returns {string} locus Url
|
|
126
243
|
*/
|
|
127
|
-
(0,
|
|
128
|
-
|
|
244
|
+
(0, _defineProperty3.default)(_this, "getLocusUrl", function () {
|
|
245
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
246
|
+
var sessionData = _this.connections.get(sessionId);
|
|
247
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.locusUrl;
|
|
129
248
|
});
|
|
130
249
|
/**
|
|
131
250
|
* Get data channel URL for the connection
|
|
251
|
+
* @param {string} sessionId - Connection identifier
|
|
132
252
|
* @returns {string} data channel Url
|
|
133
253
|
*/
|
|
134
|
-
(0,
|
|
135
|
-
|
|
254
|
+
(0, _defineProperty3.default)(_this, "getDatachannelUrl", function () {
|
|
255
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
256
|
+
var sessionData = _this.connections.get(sessionId);
|
|
257
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.datachannelUrl;
|
|
258
|
+
});
|
|
259
|
+
/**
|
|
260
|
+
* Get WebSocket URL for the connection
|
|
261
|
+
* @param {string} sessionId - Connection identifier
|
|
262
|
+
* @returns {string | undefined} WebSocket URL
|
|
263
|
+
*/
|
|
264
|
+
(0, _defineProperty3.default)(_this, "getWebSocketUrl", function () {
|
|
265
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
266
|
+
var sessionData = _this.connections.get(sessionId);
|
|
267
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.webSocketUrl;
|
|
268
|
+
});
|
|
269
|
+
/**
|
|
270
|
+
* Set the owner meeting ID for a given LLM session. Used by the meetings
|
|
271
|
+
* plugin to tag which Meeting instance currently owns the (default) LLM
|
|
272
|
+
* connection so that other Meeting instances can avoid disconnecting or
|
|
273
|
+
* re-initializing a connection they do not own.
|
|
274
|
+
*
|
|
275
|
+
* Does NOT create a connections entry if one does not already exist — this
|
|
276
|
+
* method is a no-op when there is no active session data. Callers should
|
|
277
|
+
* invoke it after a successful `registerAndConnect` or during an explicit
|
|
278
|
+
* ownership handoff.
|
|
279
|
+
*
|
|
280
|
+
* @param {string | undefined} ownerMeetingId - Meeting ID (or undefined to clear)
|
|
281
|
+
* @param {string} sessionId - Connection identifier (defaults to default session)
|
|
282
|
+
* @returns {void}
|
|
283
|
+
*/
|
|
284
|
+
(0, _defineProperty3.default)(_this, "setOwnerMeetingId", function (ownerMeetingId) {
|
|
285
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.LLM_DEFAULT_SESSION;
|
|
286
|
+
var sessionData = _this.connections.get(sessionId);
|
|
287
|
+
if (!sessionData) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
sessionData.ownerMeetingId = ownerMeetingId;
|
|
291
|
+
_this.connections.set(sessionId, sessionData);
|
|
292
|
+
});
|
|
293
|
+
/**
|
|
294
|
+
* Get the owner meeting ID currently associated with an LLM session.
|
|
295
|
+
* Returns undefined when no owner has been assigned (e.g. before the
|
|
296
|
+
* first successful `registerAndConnect`, or after `disconnectLLM`).
|
|
297
|
+
*
|
|
298
|
+
* @param {string} sessionId - Connection identifier (defaults to default session)
|
|
299
|
+
* @returns {string | undefined} ownerMeetingId
|
|
300
|
+
*/
|
|
301
|
+
(0, _defineProperty3.default)(_this, "getOwnerMeetingId", function () {
|
|
302
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
303
|
+
var sessionData = _this.connections.get(sessionId);
|
|
304
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.ownerMeetingId;
|
|
305
|
+
});
|
|
306
|
+
/**
|
|
307
|
+
* Resolve ownership information for an LLM session.
|
|
308
|
+
*
|
|
309
|
+
* Rules:
|
|
310
|
+
* - no current owner => caller may proceed
|
|
311
|
+
* - caller has no identity to assert => treat as owner
|
|
312
|
+
* - otherwise caller must match current owner
|
|
313
|
+
*
|
|
314
|
+
* @param {string | undefined} ownerMeetingId - Candidate owner to evaluate
|
|
315
|
+
* @param {string} sessionId - Connection identifier (defaults to default session)
|
|
316
|
+
* @returns {{currentOwner: (string|undefined), isOwner: boolean}}
|
|
317
|
+
*/
|
|
318
|
+
(0, _defineProperty3.default)(_this, "resolveSessionOwnership", function (ownerMeetingId) {
|
|
319
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.LLM_DEFAULT_SESSION;
|
|
320
|
+
var currentOwner = _this.getOwnerMeetingId(sessionId);
|
|
321
|
+
var isOwner = !currentOwner || !ownerMeetingId || currentOwner === ownerMeetingId;
|
|
322
|
+
return {
|
|
323
|
+
currentOwner: currentOwner,
|
|
324
|
+
isOwner: isOwner
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
/**
|
|
328
|
+
* Get data channel token for the connection
|
|
329
|
+
* @param {DataChannelTokenType|string} tokenKey
|
|
330
|
+
* @param {string | undefined} ownerMeetingId - Meeting id asserting read ownership
|
|
331
|
+
* @returns {string | undefined} data channel token
|
|
332
|
+
*/
|
|
333
|
+
(0, _defineProperty3.default)(_this, "getDatachannelToken", function (tokenKey, ownerMeetingId) {
|
|
334
|
+
var resolvedTokenKey = tokenKey !== null && tokenKey !== void 0 ? tokenKey : _llm.DataChannelTokenType.Default;
|
|
335
|
+
var _this$resolveSessionO = _this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey),
|
|
336
|
+
currentOwner = _this$resolveSessionO.currentOwner,
|
|
337
|
+
isOwner = _this$resolveSessionO.isOwner;
|
|
338
|
+
if (!isOwner) {
|
|
339
|
+
_this.logger.info("llm#getDatachannelToken --> skip read for session ".concat(resolvedTokenKey, "; owned by ").concat(currentOwner, ", candidate ").concat(ownerMeetingId));
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
return _this.datachannelTokens[resolvedTokenKey];
|
|
343
|
+
});
|
|
344
|
+
/**
|
|
345
|
+
* Set data channel token for the connection
|
|
346
|
+
* @param {string} datachannelToken - data channel token
|
|
347
|
+
* @param {DataChannelTokenType|string} [tokenKey]
|
|
348
|
+
* @param {string | undefined} ownerMeetingId - Meeting id asserting write ownership
|
|
349
|
+
* @returns {void}
|
|
350
|
+
*/
|
|
351
|
+
(0, _defineProperty3.default)(_this, "setDatachannelToken", function (datachannelToken, tokenKey, ownerMeetingId) {
|
|
352
|
+
var resolvedTokenKey = tokenKey !== null && tokenKey !== void 0 ? tokenKey : _llm.DataChannelTokenType.Default;
|
|
353
|
+
var _this$resolveSessionO2 = _this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey),
|
|
354
|
+
currentOwner = _this$resolveSessionO2.currentOwner,
|
|
355
|
+
isOwner = _this$resolveSessionO2.isOwner;
|
|
356
|
+
if (!isOwner) {
|
|
357
|
+
_this.logger.info("llm#setDatachannelToken --> skip write for session ".concat(resolvedTokenKey, "; owned by ").concat(currentOwner, ", candidate ").concat(ownerMeetingId));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
_this.datachannelTokens[resolvedTokenKey] = datachannelToken;
|
|
361
|
+
});
|
|
362
|
+
/**
|
|
363
|
+
* Clears a single session's data channel token.
|
|
364
|
+
* @param {DataChannelTokenType|string} tokenKey
|
|
365
|
+
* @param {string} ownerMeetingId - Meeting id asserting delete ownership
|
|
366
|
+
* @returns {void}
|
|
367
|
+
*/
|
|
368
|
+
(0, _defineProperty3.default)(_this, "clearDatachannelToken", function (tokenKey, ownerMeetingId) {
|
|
369
|
+
var resolvedTokenKey = tokenKey;
|
|
370
|
+
var _this$resolveSessionO3 = _this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey),
|
|
371
|
+
currentOwner = _this$resolveSessionO3.currentOwner,
|
|
372
|
+
isOwner = _this$resolveSessionO3.isOwner;
|
|
373
|
+
if (!isOwner) {
|
|
374
|
+
_this.logger.info("llm#clearDatachannelToken --> skip clear for session ".concat(resolvedTokenKey, "; owned by ").concat(currentOwner, ", candidate ").concat(ownerMeetingId));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
_this.datachannelTokens[resolvedTokenKey] = undefined;
|
|
378
|
+
delete _this.datachannelTokens[resolvedTokenKey];
|
|
136
379
|
});
|
|
137
380
|
/**
|
|
138
381
|
* Disconnects websocket connection
|
|
139
382
|
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
383
|
+
* @param {string} sessionId - Connection identifier
|
|
384
|
+
* @param {string} ownerMeetingId - Meeting id asserting disconnect ownership
|
|
385
|
+
* @returns {Promise<boolean>} True when disconnect was performed, false when skipped
|
|
386
|
+
*/
|
|
387
|
+
(0, _defineProperty3.default)(_this, "disconnectLLM", function (options, sessionId, ownerMeetingId) {
|
|
388
|
+
var resolvedSessionId = sessionId !== null && sessionId !== void 0 ? sessionId : _constants.LLM_DEFAULT_SESSION;
|
|
389
|
+
|
|
390
|
+
// Backward-compat path: historically callers could omit ownerMeetingId
|
|
391
|
+
// (and sometimes sessionId). Reuse current owner when available so legacy
|
|
392
|
+
// calls remain best-effort without throwing at teardown time.
|
|
393
|
+
var resolvedOwnerMeetingId = ownerMeetingId || _this.getOwnerMeetingId(resolvedSessionId);
|
|
394
|
+
if (!ownerMeetingId) {
|
|
395
|
+
_this.logger.warn("llm#disconnectLLM --> ownerMeetingId is omitted for session ".concat(resolvedSessionId, "; using legacy compatibility path"));
|
|
396
|
+
}
|
|
397
|
+
var _this$resolveSessionO4 = _this.resolveSessionOwnership(resolvedOwnerMeetingId, resolvedSessionId),
|
|
398
|
+
currentOwner = _this$resolveSessionO4.currentOwner,
|
|
399
|
+
isOwner = _this$resolveSessionO4.isOwner;
|
|
400
|
+
if (!isOwner) {
|
|
401
|
+
_this.logger.info("llm#disconnectLLM --> skip disconnect for session ".concat(resolvedSessionId, "; owned by ").concat(currentOwner, ", candidate ").concat(resolvedOwnerMeetingId));
|
|
402
|
+
return _promise.default.resolve(false);
|
|
403
|
+
}
|
|
404
|
+
return _this.disconnect(options, resolvedSessionId).then(function () {
|
|
405
|
+
// Clear owner tag before cleanup to ensure it's not lingering
|
|
406
|
+
// if another meeting claimed it during disconnect
|
|
407
|
+
_this.setOwnerMeetingId(undefined, resolvedSessionId);
|
|
408
|
+
|
|
409
|
+
// Clean up sessions data
|
|
410
|
+
_this.connections.delete(resolvedSessionId);
|
|
411
|
+
return true;
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
/**
|
|
415
|
+
* Disconnects all LLM websocket connections
|
|
416
|
+
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
140
417
|
* @returns {Promise<void>}
|
|
141
418
|
*/
|
|
142
|
-
(0,
|
|
143
|
-
return _this.
|
|
144
|
-
|
|
145
|
-
_this.
|
|
146
|
-
_this.binding = undefined;
|
|
147
|
-
_this.webSocketUrl = undefined;
|
|
419
|
+
(0, _defineProperty3.default)(_this, "disconnectAllLLM", function (options) {
|
|
420
|
+
return _this.disconnectAll(options).then(function () {
|
|
421
|
+
// Clean up all connection data
|
|
422
|
+
_this.connections.clear();
|
|
148
423
|
});
|
|
149
424
|
});
|
|
425
|
+
/**
|
|
426
|
+
* Get all active LLM connections
|
|
427
|
+
* @returns {Map} Map of sessionId to session data
|
|
428
|
+
*/
|
|
429
|
+
(0, _defineProperty3.default)(_this, "getAllConnections", function () {
|
|
430
|
+
return new _map.default(_this.connections);
|
|
431
|
+
});
|
|
150
432
|
return _this;
|
|
151
433
|
}
|
|
152
434
|
(0, _inherits2.default)(LLMChannel, _ref);
|
|
153
|
-
return (0, _createClass2.default)(LLMChannel
|
|
435
|
+
return (0, _createClass2.default)(LLMChannel, [{
|
|
436
|
+
key: "setRefreshHandler",
|
|
437
|
+
value:
|
|
438
|
+
/**
|
|
439
|
+
* Set the handler used to refresh the DataChannel token
|
|
440
|
+
*
|
|
441
|
+
* @param {function} handler - Function that returns a refreshed token
|
|
442
|
+
* @param {string} [sessionId] - Connection identifier
|
|
443
|
+
* @param {string | undefined} ownerMeetingId - Meeting id asserting refresh-handler ownership
|
|
444
|
+
* @returns {void}
|
|
445
|
+
*/
|
|
446
|
+
function setRefreshHandler(handler, sessionId, ownerMeetingId) {
|
|
447
|
+
var resolvedSessionId = sessionId !== null && sessionId !== void 0 ? sessionId : _constants.LLM_DEFAULT_SESSION;
|
|
448
|
+
var _this$resolveSessionO5 = this.resolveSessionOwnership(ownerMeetingId, resolvedSessionId),
|
|
449
|
+
currentOwner = _this$resolveSessionO5.currentOwner,
|
|
450
|
+
isOwner = _this$resolveSessionO5.isOwner;
|
|
451
|
+
if (!isOwner) {
|
|
452
|
+
this.logger.info("llm#setRefreshHandler --> skip write for session ".concat(resolvedSessionId, "; owned by ").concat(currentOwner, ", candidate ").concat(ownerMeetingId));
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
var sessionData = this.connections.get(resolvedSessionId);
|
|
456
|
+
if (sessionData) {
|
|
457
|
+
sessionData.refreshHandler = handler;
|
|
458
|
+
if (ownerMeetingId) {
|
|
459
|
+
sessionData.ownerMeetingId = ownerMeetingId;
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Intentionally allow a pre-connection session shape here.
|
|
465
|
+
// Some flows inject refreshHandler before register/connect so token refresh
|
|
466
|
+
// is already wired when the socket lifecycle starts. register()/
|
|
467
|
+
// registerAndConnect() will later fill webSocketUrl/binding/locusUrl/
|
|
468
|
+
// datachannelUrl into this same session entry.
|
|
469
|
+
this.connections.set(resolvedSessionId, {
|
|
470
|
+
refreshHandler: handler,
|
|
471
|
+
ownerMeetingId: ownerMeetingId
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Refresh the data channel token using the injected handler.
|
|
477
|
+
* Logs a descriptive error if the handler is missing or fails.
|
|
478
|
+
* @param {string} sessionId - Connection identifier (defaults to default session)
|
|
479
|
+
* @returns {Promise<string>} The refreshed token.
|
|
480
|
+
*/
|
|
481
|
+
}, {
|
|
482
|
+
key: "refreshDataChannelToken",
|
|
483
|
+
value: (function () {
|
|
484
|
+
var _refreshDataChannelToken = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
485
|
+
var _this$connections$get;
|
|
486
|
+
var sessionId,
|
|
487
|
+
refreshHandler,
|
|
488
|
+
res,
|
|
489
|
+
_args3 = arguments,
|
|
490
|
+
_t2;
|
|
491
|
+
return _regenerator.default.wrap(function (_context3) {
|
|
492
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
493
|
+
case 0:
|
|
494
|
+
sessionId = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : _constants.LLM_DEFAULT_SESSION;
|
|
495
|
+
refreshHandler = (_this$connections$get = this.connections.get(sessionId)) === null || _this$connections$get === void 0 ? void 0 : _this$connections$get.refreshHandler;
|
|
496
|
+
if (refreshHandler) {
|
|
497
|
+
_context3.next = 1;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
this.logger.warn("llm#refreshDataChannelToken --> LLM refreshHandler is not set for session ".concat(sessionId, ", skipping token refresh"));
|
|
501
|
+
return _context3.abrupt("return", null);
|
|
502
|
+
case 1:
|
|
503
|
+
_context3.prev = 1;
|
|
504
|
+
_context3.next = 2;
|
|
505
|
+
return refreshHandler();
|
|
506
|
+
case 2:
|
|
507
|
+
res = _context3.sent;
|
|
508
|
+
return _context3.abrupt("return", res);
|
|
509
|
+
case 3:
|
|
510
|
+
_context3.prev = 3;
|
|
511
|
+
_t2 = _context3["catch"](1);
|
|
512
|
+
this.logger.warn("llm#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ".concat((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || _t2));
|
|
513
|
+
return _context3.abrupt("return", null);
|
|
514
|
+
case 4:
|
|
515
|
+
case "end":
|
|
516
|
+
return _context3.stop();
|
|
517
|
+
}
|
|
518
|
+
}, _callee3, this, [[1, 3]]);
|
|
519
|
+
}));
|
|
520
|
+
function refreshDataChannelToken() {
|
|
521
|
+
return _refreshDataChannelToken.apply(this, arguments);
|
|
522
|
+
}
|
|
523
|
+
return refreshDataChannelToken;
|
|
524
|
+
}())
|
|
525
|
+
}, {
|
|
526
|
+
key: "getLocusUrlByDatachannelUrl",
|
|
527
|
+
value:
|
|
528
|
+
/**
|
|
529
|
+
* Look up the locusUrl associated with a datachannel request URL.
|
|
530
|
+
* Iterates all active LLM sessions and returns the locusUrl of the
|
|
531
|
+
* session whose stored datachannelUrl is a prefix of the given request URL.
|
|
532
|
+
*
|
|
533
|
+
* @param {string} requestUrl - The in-flight request URL to match
|
|
534
|
+
* @returns {string | undefined} The matching locusUrl, or undefined if not found
|
|
535
|
+
*/
|
|
536
|
+
function getLocusUrlByDatachannelUrl(requestUrl) {
|
|
537
|
+
var _iterator = _createForOfIteratorHelper(this.connections),
|
|
538
|
+
_step;
|
|
539
|
+
try {
|
|
540
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
541
|
+
var _step$value = (0, _slicedToArray2.default)(_step.value, 2),
|
|
542
|
+
connection = _step$value[1];
|
|
543
|
+
if (connection.datachannelUrl && LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)) {
|
|
544
|
+
return connection.locusUrl;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
_iterator.e(err);
|
|
549
|
+
} finally {
|
|
550
|
+
_iterator.f();
|
|
551
|
+
}
|
|
552
|
+
return undefined;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Look up the sessionId associated with a datachannel request URL.
|
|
557
|
+
* Iterates all active LLM sessions and returns the sessionId whose
|
|
558
|
+
* stored datachannelUrl is a prefix of the given request URL.
|
|
559
|
+
*
|
|
560
|
+
* @param {string} requestUrl - The in-flight request URL to match
|
|
561
|
+
* @returns {string | undefined} The matching sessionId, or undefined if not found
|
|
562
|
+
*/
|
|
563
|
+
}, {
|
|
564
|
+
key: "getSessionIdByDatachannelUrl",
|
|
565
|
+
value: function getSessionIdByDatachannelUrl(requestUrl) {
|
|
566
|
+
var _iterator2 = _createForOfIteratorHelper(this.connections),
|
|
567
|
+
_step2;
|
|
568
|
+
try {
|
|
569
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
570
|
+
var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2),
|
|
571
|
+
sessionId = _step2$value[0],
|
|
572
|
+
connection = _step2$value[1];
|
|
573
|
+
if (connection.datachannelUrl && LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)) {
|
|
574
|
+
return sessionId;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
} catch (err) {
|
|
578
|
+
_iterator2.e(err);
|
|
579
|
+
} finally {
|
|
580
|
+
_iterator2.f();
|
|
581
|
+
}
|
|
582
|
+
return undefined;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Matches a request URL to a stored datachannel registration URL.
|
|
587
|
+
* Host can differ (e.g. rewritten by hostmap interceptor), so we first
|
|
588
|
+
* try full URL prefix and then fall back to pathname prefix.
|
|
589
|
+
* @param {string} requestUrl
|
|
590
|
+
* @param {string} registrationUrl
|
|
591
|
+
* @returns {boolean}
|
|
592
|
+
*/
|
|
593
|
+
}, {
|
|
594
|
+
key: "isDataChannelTokenEnabled",
|
|
595
|
+
value:
|
|
596
|
+
/**
|
|
597
|
+
* Returns true if data channel token is enabled, false otherwise
|
|
598
|
+
* @returns {Promise<boolean>} resolves with true if data channel token is enabled
|
|
599
|
+
*/
|
|
600
|
+
function isDataChannelTokenEnabled() {
|
|
601
|
+
// @ts-ignore
|
|
602
|
+
return this.webex.internal.feature.getFeature('developer', _constants.DATA_CHANNEL_WITH_JWT_TOKEN);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Builds a WebSocket URL with the `subscriptionAwareSubchannels` query parameter.
|
|
607
|
+
*
|
|
608
|
+
* @param {string} baseUrl - The original WebSocket URL.
|
|
609
|
+
* @param {string[]} subchannels - List of subchannels to declare as subscription-aware.
|
|
610
|
+
* @returns {string} The final URL with updated query parameters.
|
|
611
|
+
*/
|
|
612
|
+
}], [{
|
|
613
|
+
key: "matchesDatachannelRequestUrl",
|
|
614
|
+
value: function matchesDatachannelRequestUrl(requestUrl, registrationUrl) {
|
|
615
|
+
if (!requestUrl || !registrationUrl) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
if (requestUrl.startsWith(registrationUrl)) {
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
try {
|
|
622
|
+
var request = new URL(requestUrl);
|
|
623
|
+
var registration = new URL(registrationUrl);
|
|
624
|
+
return request.pathname.startsWith(registration.pathname);
|
|
625
|
+
} catch (error) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}]);
|
|
154
630
|
}(_internalPluginMercury.default);
|
|
631
|
+
(0, _defineProperty3.default)(LLMChannel, "buildUrlWithAwareSubchannels", function (baseUrl, subchannels) {
|
|
632
|
+
var urlObj = new URL(baseUrl);
|
|
633
|
+
urlObj.searchParams.set(_constants.SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM, subchannels.join(','));
|
|
634
|
+
return urlObj.toString();
|
|
635
|
+
});
|
|
155
636
|
//# sourceMappingURL=llm.js.map
|