@webex/internal-plugin-llm 3.11.0-next.11 → 3.11.0-next.12
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 +3 -3
- package/dist/constants.js +6 -1
- package/dist/constants.js.map +1 -1
- package/dist/llm.js +78 -33
- package/dist/llm.js.map +1 -1
- package/dist/llm.types.js +2 -2
- package/dist/llm.types.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +8 -0
- package/src/llm.ts +60 -10
- package/src/llm.types.ts +2 -2
- package/test/unit/spec/llm.js +193 -92
package/README.md
CHANGED
|
@@ -79,8 +79,8 @@ llm.on(`event:${sessionB}`, (envelope) => {
|
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
// Optional: store/retrieve token by token type
|
|
82
|
-
webex.internal.llm.setDatachannelToken(datachannelToken, '
|
|
83
|
-
webex.internal.llm.getDatachannelToken('
|
|
82
|
+
webex.internal.llm.setDatachannelToken(datachannelToken, 'llm-default-session');
|
|
83
|
+
webex.internal.llm.getDatachannelToken('llm-default-session');
|
|
84
84
|
|
|
85
85
|
// Optional: inject token refresh handler
|
|
86
86
|
webex.internal.llm.setRefreshHandler(async () => {
|
|
@@ -88,7 +88,7 @@ webex.internal.llm.setRefreshHandler(async () => {
|
|
|
88
88
|
return {
|
|
89
89
|
body: {
|
|
90
90
|
datachannelToken: '<refreshed-jwt-token>',
|
|
91
|
-
datachannelTokenType: '
|
|
91
|
+
datachannelTokenType: 'llm-default-session',
|
|
92
92
|
},
|
|
93
93
|
};
|
|
94
94
|
});
|
package/dist/constants.js
CHANGED
|
@@ -4,9 +4,14 @@ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/defi
|
|
|
4
4
|
_Object$defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.LLM_DEFAULT_SESSION = exports.LLM = exports.DATA_CHANNEL_WITH_JWT_TOKEN = void 0;
|
|
7
|
+
exports.SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = exports.LLM_DEFAULT_SESSION = exports.LLM = exports.DATA_CHNANEL_TYPE = exports.DATA_CHANNEL_WITH_JWT_TOKEN = exports.AWARE_DATA_CHANNEL = void 0;
|
|
8
8
|
// eslint-disable-next-line import/prefer-default-export
|
|
9
9
|
var LLM = exports.LLM = 'llm';
|
|
10
10
|
var LLM_DEFAULT_SESSION = exports.LLM_DEFAULT_SESSION = 'llm-default-session';
|
|
11
11
|
var DATA_CHANNEL_WITH_JWT_TOKEN = exports.DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';
|
|
12
|
+
var SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = exports.SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = 'subscriptionAwareSubchannels';
|
|
13
|
+
var DATA_CHNANEL_TYPE = exports.DATA_CHNANEL_TYPE = {
|
|
14
|
+
TRANSCRIPTION: 'transcription'
|
|
15
|
+
};
|
|
16
|
+
var AWARE_DATA_CHANNEL = exports.AWARE_DATA_CHANNEL = [DATA_CHNANEL_TYPE.TRANSCRIPTION];
|
|
12
17
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["LLM","exports","LLM_DEFAULT_SESSION","DATA_CHANNEL_WITH_JWT_TOKEN"],"sources":["constants.ts"],"sourcesContent":["// eslint-disable-next-line import/prefer-default-export\nexport const LLM = 'llm';\n\nexport const LLM_DEFAULT_SESSION = 'llm-default-session';\n\nexport const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';\n"],"mappings":";;;;;;;AAAA;AACO,IAAMA,GAAG,GAAAC,OAAA,CAAAD,GAAA,GAAG,KAAK;AAEjB,IAAME,mBAAmB,GAAAD,OAAA,CAAAC,mBAAA,GAAG,qBAAqB;AAEjD,IAAMC,2BAA2B,GAAAF,OAAA,CAAAE,2BAAA,GAAG,6BAA6B","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["LLM","exports","LLM_DEFAULT_SESSION","DATA_CHANNEL_WITH_JWT_TOKEN","SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM","DATA_CHNANEL_TYPE","TRANSCRIPTION","AWARE_DATA_CHANNEL"],"sources":["constants.ts"],"sourcesContent":["// eslint-disable-next-line import/prefer-default-export\nexport const LLM = 'llm';\n\nexport const LLM_DEFAULT_SESSION = 'llm-default-session';\n\nexport const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';\n\nexport const SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = 'subscriptionAwareSubchannels';\n\nexport const DATA_CHNANEL_TYPE = {\n TRANSCRIPTION: 'transcription',\n};\n\nexport const AWARE_DATA_CHANNEL = [DATA_CHNANEL_TYPE.TRANSCRIPTION];\n"],"mappings":";;;;;;;AAAA;AACO,IAAMA,GAAG,GAAAC,OAAA,CAAAD,GAAA,GAAG,KAAK;AAEjB,IAAME,mBAAmB,GAAAD,OAAA,CAAAC,mBAAA,GAAG,qBAAqB;AAEjD,IAAMC,2BAA2B,GAAAF,OAAA,CAAAE,2BAAA,GAAG,6BAA6B;AAEjE,IAAMC,oCAAoC,GAAAH,OAAA,CAAAG,oCAAA,GAAG,8BAA8B;AAE3E,IAAMC,iBAAiB,GAAAJ,OAAA,CAAAI,iBAAA,GAAG;EAC/BC,aAAa,EAAE;AACjB,CAAC;AAEM,IAAMC,kBAAkB,GAAAN,OAAA,CAAAM,kBAAA,GAAG,CAACF,iBAAiB,CAACC,aAAa,CAAC","ignoreList":[]}
|
package/dist/llm.js
CHANGED
|
@@ -132,17 +132,35 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
132
132
|
*/
|
|
133
133
|
(0, _defineProperty3.default)(_this, "registerAndConnect", function (locusUrl, datachannelUrl, datachannelToken) {
|
|
134
134
|
var sessionId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants.LLM_DEFAULT_SESSION;
|
|
135
|
-
return _this.register(datachannelUrl, datachannelToken, sessionId).then(function () {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
return _this.register(datachannelUrl, datachannelToken, sessionId).then(/*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
136
|
+
var sessionData, isDataChannelTokenEnabled, connectUrl;
|
|
137
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
138
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
139
|
+
case 0:
|
|
140
|
+
if (!(!locusUrl || !datachannelUrl)) {
|
|
141
|
+
_context2.next = 1;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
return _context2.abrupt("return", undefined);
|
|
145
|
+
case 1:
|
|
146
|
+
// Get or create connection data
|
|
147
|
+
sessionData = _this.connections.get(sessionId) || {};
|
|
148
|
+
sessionData.locusUrl = locusUrl;
|
|
149
|
+
sessionData.datachannelUrl = datachannelUrl;
|
|
150
|
+
sessionData.datachannelToken = datachannelToken;
|
|
151
|
+
_this.connections.set(sessionId, sessionData);
|
|
152
|
+
_context2.next = 2;
|
|
153
|
+
return _this.isDataChannelTokenEnabled();
|
|
154
|
+
case 2:
|
|
155
|
+
isDataChannelTokenEnabled = _context2.sent;
|
|
156
|
+
connectUrl = isDataChannelTokenEnabled ? LLMChannel.buildUrlWithAwareSubchannels(sessionData.webSocketUrl, _constants.AWARE_DATA_CHANNEL) : sessionData.webSocketUrl;
|
|
157
|
+
return _context2.abrupt("return", _this.connect(connectUrl, sessionId));
|
|
158
|
+
case 3:
|
|
159
|
+
case "end":
|
|
160
|
+
return _context2.stop();
|
|
161
|
+
}
|
|
162
|
+
}, _callee2);
|
|
163
|
+
})));
|
|
146
164
|
});
|
|
147
165
|
/**
|
|
148
166
|
* Tells if LLM socket is connected
|
|
@@ -189,7 +207,8 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
189
207
|
* @param {DataChannelTokenType} dataChannelTokenType
|
|
190
208
|
* @returns {string} data channel token
|
|
191
209
|
*/
|
|
192
|
-
(0, _defineProperty3.default)(_this, "getDatachannelToken", function (
|
|
210
|
+
(0, _defineProperty3.default)(_this, "getDatachannelToken", function () {
|
|
211
|
+
var dataChannelTokenType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _llm.DataChannelTokenType.Default;
|
|
193
212
|
return _this.datachannelTokens[dataChannelTokenType];
|
|
194
213
|
});
|
|
195
214
|
/**
|
|
@@ -198,7 +217,8 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
198
217
|
* @param {DataChannelTokenType} dataChannelTokenType
|
|
199
218
|
* @returns {void}
|
|
200
219
|
*/
|
|
201
|
-
(0, _defineProperty3.default)(_this, "setDatachannelToken", function (datachannelToken
|
|
220
|
+
(0, _defineProperty3.default)(_this, "setDatachannelToken", function (datachannelToken) {
|
|
221
|
+
var dataChannelTokenType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _llm.DataChannelTokenType.Default;
|
|
202
222
|
_this.datachannelTokens[dataChannelTokenType] = datachannelToken;
|
|
203
223
|
});
|
|
204
224
|
/**
|
|
@@ -212,6 +232,7 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
212
232
|
return _this.disconnect(options, sessionId).then(function () {
|
|
213
233
|
// Clean up sessions data
|
|
214
234
|
_this.connections.delete(sessionId);
|
|
235
|
+
_this.datachannelTokens[sessionId] = undefined;
|
|
215
236
|
});
|
|
216
237
|
});
|
|
217
238
|
/**
|
|
@@ -223,6 +244,7 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
223
244
|
return _this.disconnectAll(options).then(function () {
|
|
224
245
|
// Clean up all connection data
|
|
225
246
|
_this.connections.clear();
|
|
247
|
+
_this.resetDatachannelTokens();
|
|
226
248
|
});
|
|
227
249
|
});
|
|
228
250
|
/**
|
|
@@ -236,15 +258,26 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
236
258
|
}
|
|
237
259
|
(0, _inherits2.default)(LLMChannel, _ref);
|
|
238
260
|
return (0, _createClass2.default)(LLMChannel, [{
|
|
239
|
-
key: "
|
|
261
|
+
key: "resetDatachannelTokens",
|
|
240
262
|
value:
|
|
263
|
+
/**
|
|
264
|
+
* Resets all data‑channel tokens to their initial undefined values.
|
|
265
|
+
* Used when leaving or disconnecting from a meeting.
|
|
266
|
+
* @returns {void}
|
|
267
|
+
*/
|
|
268
|
+
function resetDatachannelTokens() {
|
|
269
|
+
this.datachannelTokens = (0, _defineProperty3.default)((0, _defineProperty3.default)({}, _llm.DataChannelTokenType.Default, undefined), _llm.DataChannelTokenType.PracticeSession, undefined);
|
|
270
|
+
}
|
|
271
|
+
|
|
241
272
|
/**
|
|
242
273
|
* Set the handler used to refresh the DataChannel token
|
|
243
274
|
*
|
|
244
275
|
* @param {function} handler - Function that returns a refreshed token
|
|
245
276
|
* @returns {void}
|
|
246
277
|
*/
|
|
247
|
-
|
|
278
|
+
}, {
|
|
279
|
+
key: "setRefreshHandler",
|
|
280
|
+
value: function setRefreshHandler(handler) {
|
|
248
281
|
this.refreshHandler = handler;
|
|
249
282
|
}
|
|
250
283
|
|
|
@@ -257,35 +290,34 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
257
290
|
}, {
|
|
258
291
|
key: "refreshDataChannelToken",
|
|
259
292
|
value: (function () {
|
|
260
|
-
var _refreshDataChannelToken = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function
|
|
261
|
-
var
|
|
262
|
-
return _regenerator.default.wrap(function (
|
|
263
|
-
while (1) switch (
|
|
293
|
+
var _refreshDataChannelToken = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
294
|
+
var res, _t;
|
|
295
|
+
return _regenerator.default.wrap(function (_context3) {
|
|
296
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
264
297
|
case 0:
|
|
265
298
|
if (this.refreshHandler) {
|
|
266
|
-
|
|
299
|
+
_context3.next = 1;
|
|
267
300
|
break;
|
|
268
301
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
throw error;
|
|
302
|
+
this.logger.warn('llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh');
|
|
303
|
+
return _context3.abrupt("return", null);
|
|
272
304
|
case 1:
|
|
273
|
-
|
|
274
|
-
|
|
305
|
+
_context3.prev = 1;
|
|
306
|
+
_context3.next = 2;
|
|
275
307
|
return this.refreshHandler();
|
|
276
308
|
case 2:
|
|
277
|
-
res =
|
|
278
|
-
return
|
|
309
|
+
res = _context3.sent;
|
|
310
|
+
return _context3.abrupt("return", res);
|
|
279
311
|
case 3:
|
|
280
|
-
|
|
281
|
-
_t =
|
|
282
|
-
this.logger.
|
|
283
|
-
|
|
312
|
+
_context3.prev = 3;
|
|
313
|
+
_t = _context3["catch"](1);
|
|
314
|
+
this.logger.warn("llm#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ".concat((_t === null || _t === void 0 ? void 0 : _t.message) || _t));
|
|
315
|
+
return _context3.abrupt("return", null);
|
|
284
316
|
case 4:
|
|
285
317
|
case "end":
|
|
286
|
-
return
|
|
318
|
+
return _context3.stop();
|
|
287
319
|
}
|
|
288
|
-
},
|
|
320
|
+
}, _callee3, this, [[1, 3]]);
|
|
289
321
|
}));
|
|
290
322
|
function refreshDataChannelToken() {
|
|
291
323
|
return _refreshDataChannelToken.apply(this, arguments);
|
|
@@ -303,6 +335,19 @@ var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
|
303
335
|
// @ts-ignore
|
|
304
336
|
return this.webex.internal.feature.getFeature('developer', _constants.DATA_CHANNEL_WITH_JWT_TOKEN);
|
|
305
337
|
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Builds a WebSocket URL with the `subscriptionAwareSubchannels` query parameter.
|
|
341
|
+
*
|
|
342
|
+
* @param {string} baseUrl - The original WebSocket URL.
|
|
343
|
+
* @param {string[]} subchannels - List of subchannels to declare as subscription-aware.
|
|
344
|
+
* @returns {string} The final URL with updated query parameters.
|
|
345
|
+
*/
|
|
306
346
|
}]);
|
|
307
347
|
}(_internalPluginMercury.default);
|
|
348
|
+
(0, _defineProperty3.default)(LLMChannel, "buildUrlWithAwareSubchannels", function (baseUrl, subchannels) {
|
|
349
|
+
var urlObj = new URL(baseUrl);
|
|
350
|
+
urlObj.searchParams.set(_constants.SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM, subchannels.join(','));
|
|
351
|
+
return urlObj.toString();
|
|
352
|
+
});
|
|
308
353
|
//# sourceMappingURL=llm.js.map
|
package/dist/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_internalPluginMercury","_interopRequireDefault","require","_constants","_llm","_callSuper","t","o","e","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","constructor","apply","Boolean","prototype","valueOf","call","config","exports","llm","pingInterval","process","env","MERCURY_PING_INTERVAL","pongTimeout","MERCURY_PONG_TIMEOUT","backoffTimeMax","MERCURY_BACKOFF_TIME_MAX","backoffTimeReset","MERCURY_BACKOFF_TIME_RESET","forceCloseDelay","MERCURY_FORCE_CLOSE_DELAY","LLMChannel","_ref","_this","_classCallCheck2","_len","arguments","length","args","Array","_key","concat","_defineProperty3","LLM","LLM_DEFAULT_SESSION","_map","DataChannelTokenType","Default","undefined","PracticeSession","_ref2","_asyncToGenerator2","_regenerator","mark","_callee","llmSocketUrl","datachannelToken","sessionId","isDataChannelTokenEnabled","_args","wrap","_context","prev","next","sent","abrupt","request","method","url","body","deviceUrl","webex","internal","device","headers","then","res","sessionData","connections","get","webSocketUrl","binding","set","catch","error","logger","stop","_x","_x2","locusUrl","datachannelUrl","register","connect","socket","getSocket","connected","dataChannelTokenType","datachannelTokens","options","disconnect","delete","disconnectAll","clear","_inherits2","_createClass2","key","value","setRefreshHandler","handler","refreshHandler","_refreshDataChannelToken","_callee2","_t","_context2","Error","message","refreshDataChannelToken","feature","getFeature","DATA_CHANNEL_WITH_JWT_TOKEN","Mercury"],"sources":["llm.ts"],"sourcesContent":["/* eslint-disable consistent-return */\n\nimport Mercury from '@webex/internal-plugin-mercury';\n\nimport {LLM, DATA_CHANNEL_WITH_JWT_TOKEN, LLM_DEFAULT_SESSION} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {ILLMChannel, DataChannelTokenType} from './llm.types';\n\nexport const config = {\n llm: {\n /**\n * Milliseconds between pings sent up the socket\n * @type {number}\n */\n pingInterval: process.env.MERCURY_PING_INTERVAL || 15000,\n /**\n * Milliseconds to wait for a pong before declaring the connection dead\n * @type {number}\n */\n pongTimeout: process.env.MERCURY_PONG_TIMEOUT || 14000,\n /**\n * Maximum milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeMax: process.env.MERCURY_BACKOFF_TIME_MAX || 32000,\n /**\n * Initial milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeReset: process.env.MERCURY_BACKOFF_TIME_RESET || 1000,\n /**\n * Milliseconds to wait for a close frame before declaring the socket dead and\n * discarding it\n * @type {[type]}\n */\n forceCloseDelay: process.env.MERCURY_FORCE_CLOSE_DELAY || 2000,\n },\n};\n\n/**\n * LLMChannel to provide socket connections\n */\nexport default class LLMChannel extends (Mercury as any) implements ILLMChannel {\n namespace = LLM;\n defaultSessionId = LLM_DEFAULT_SESSION;\n /**\n * Map to store connection-specific data for multiple LLM connections\n * @private\n * @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}\n */\n private connections: Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > = new Map();\n\n private datachannelTokens: Record<DataChannelTokenType, string> = {\n [DataChannelTokenType.Default]: undefined,\n [DataChannelTokenType.PracticeSession]: undefined,\n };\n\n private refreshHandler?: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>;\n\n /**\n * Register to the websocket\n * @param {string} llmSocketUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n private register = async (\n llmSocketUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> => {\n const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();\n\n return this.request({\n method: 'POST',\n url: llmSocketUrl,\n body: {deviceUrl: this.webex.internal.device.url},\n headers:\n isDataChannelTokenEnabled && datachannelToken\n ? {'Data-Channel-Auth-Token': datachannelToken}\n : {},\n })\n .then((res: {body: {webSocketUrl: string; binding: string}}) => {\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.webSocketUrl = res.body.webSocketUrl;\n sessionData.binding = res.body.binding;\n this.connections.set(sessionId, sessionData);\n })\n .catch((error: any) => {\n this.logger.error(`Error connecting to websocket for ${sessionId}: ${error}`);\n throw error;\n });\n };\n\n /**\n * Register and connect to the websocket\n * @param {string} locusUrl\n * @param {string} datachannelUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public registerAndConnect = (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.register(datachannelUrl, datachannelToken, sessionId).then(() => {\n if (!locusUrl || !datachannelUrl) return undefined;\n\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.locusUrl = locusUrl;\n sessionData.datachannelUrl = datachannelUrl;\n sessionData.datachannelToken = datachannelToken;\n this.connections.set(sessionId, sessionData);\n\n return this.connect(sessionData.webSocketUrl, sessionId);\n });\n\n /**\n * Tells if LLM socket is connected\n * @param {string} sessionId - Connection identifier\n * @returns {boolean} connected\n */\n public isConnected = (sessionId = LLM_DEFAULT_SESSION): boolean => {\n const socket = this.getSocket(sessionId);\n\n return socket ? socket.connected : false;\n };\n\n /**\n * Tells if LLM socket is binding\n * @param {string} sessionId - Connection identifier\n * @returns {string} binding\n */\n public getBinding = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.binding;\n };\n\n /**\n * Get Locus URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} locus Url\n */\n public getLocusUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.locusUrl;\n };\n\n /**\n * Get data channel URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} data channel Url\n */\n public getDatachannelUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.datachannelUrl;\n };\n\n /**\n * Get data channel token for the connection\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {string} data channel token\n */\n public getDatachannelToken = (dataChannelTokenType: DataChannelTokenType): string => {\n return this.datachannelTokens[dataChannelTokenType];\n };\n\n /**\n * Set data channel token for the connection\n * @param {string} datachannelToken - data channel token\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {void}\n */\n public setDatachannelToken = (\n datachannelToken: string,\n dataChannelTokenType: DataChannelTokenType\n ): void => {\n this.datachannelTokens[dataChannelTokenType] = datachannelToken;\n };\n\n /**\n * Set the handler used to refresh the DataChannel token\n *\n * @param {function} handler - Function that returns a refreshed token\n * @returns {void}\n */\n public setRefreshHandler(\n handler: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>\n ) {\n this.refreshHandler = handler;\n }\n\n /**\n * Refresh the data channel token using the injected handler.\n * Logs a descriptive error if the handler is missing or fails.\n *\n * @returns {Promise<string>} The refreshed token.\n */\n public async refreshDataChannelToken() {\n if (!this.refreshHandler) {\n const error = new Error('LLM refreshHandler is not set');\n this.logger.error(`Error refreshing DataChannel token: ${error.message}`);\n throw error;\n }\n\n try {\n const res = await this.refreshHandler();\n\n return res;\n } catch (error: any) {\n this.logger.error(`Error refreshing DataChannel token: ${error}`);\n throw error;\n }\n }\n\n /**\n * Disconnects websocket connection\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public disconnectLLM = (\n options: {code: number; reason: string},\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.disconnect(options, sessionId).then(() => {\n // Clean up sessions data\n this.connections.delete(sessionId);\n });\n\n /**\n * Disconnects all LLM websocket connections\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @returns {Promise<void>}\n */\n public disconnectAllLLM = (options?: {code: number; reason: string}): Promise<void> =>\n this.disconnectAll(options).then(() => {\n // Clean up all connection data\n this.connections.clear();\n });\n\n /**\n * Get all active LLM connections\n * @returns {Map} Map of sessionId to session data\n */\n public getAllConnections = (): Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > => new Map(this.connections);\n\n /**\n * Returns true if data channel token is enabled, false otherwise\n * @returns {Promise<boolean>} resolves with true if data channel token is enabled\n */\n public isDataChannelTokenEnabled(): Promise<boolean> {\n // @ts-ignore\n return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_internalPluginMercury","_interopRequireDefault","require","_constants","_llm","_callSuper","t","o","e","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","constructor","apply","Boolean","prototype","valueOf","call","config","exports","llm","pingInterval","process","env","MERCURY_PING_INTERVAL","pongTimeout","MERCURY_PONG_TIMEOUT","backoffTimeMax","MERCURY_BACKOFF_TIME_MAX","backoffTimeReset","MERCURY_BACKOFF_TIME_RESET","forceCloseDelay","MERCURY_FORCE_CLOSE_DELAY","LLMChannel","_ref","_this","_classCallCheck2","_len","arguments","length","args","Array","_key","concat","_defineProperty3","LLM","LLM_DEFAULT_SESSION","_map","DataChannelTokenType","Default","undefined","PracticeSession","_ref2","_asyncToGenerator2","_regenerator","mark","_callee","llmSocketUrl","datachannelToken","sessionId","isDataChannelTokenEnabled","_args","wrap","_context","prev","next","sent","abrupt","request","method","url","body","deviceUrl","webex","internal","device","headers","then","res","sessionData","connections","get","webSocketUrl","binding","set","catch","error","logger","stop","_x","_x2","locusUrl","datachannelUrl","register","_callee2","connectUrl","_context2","buildUrlWithAwareSubchannels","AWARE_DATA_CHANNEL","connect","socket","getSocket","connected","dataChannelTokenType","datachannelTokens","options","disconnect","delete","disconnectAll","clear","resetDatachannelTokens","_inherits2","_createClass2","key","value","setRefreshHandler","handler","refreshHandler","_refreshDataChannelToken","_callee3","_t","_context3","warn","message","refreshDataChannelToken","feature","getFeature","DATA_CHANNEL_WITH_JWT_TOKEN","Mercury","baseUrl","subchannels","urlObj","URL","searchParams","SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM","join","toString"],"sources":["llm.ts"],"sourcesContent":["/* eslint-disable consistent-return */\n\nimport Mercury from '@webex/internal-plugin-mercury';\n\n// eslint-disable-next-line no-unused-vars\nimport {\n LLM,\n DATA_CHANNEL_WITH_JWT_TOKEN,\n AWARE_DATA_CHANNEL,\n SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM,\n LLM_DEFAULT_SESSION,\n} from './constants';\nimport {ILLMChannel, DataChannelTokenType} from './llm.types';\n\nexport const config = {\n llm: {\n /**\n * Milliseconds between pings sent up the socket\n * @type {number}\n */\n pingInterval: process.env.MERCURY_PING_INTERVAL || 15000,\n /**\n * Milliseconds to wait for a pong before declaring the connection dead\n * @type {number}\n */\n pongTimeout: process.env.MERCURY_PONG_TIMEOUT || 14000,\n /**\n * Maximum milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeMax: process.env.MERCURY_BACKOFF_TIME_MAX || 32000,\n /**\n * Initial milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeReset: process.env.MERCURY_BACKOFF_TIME_RESET || 1000,\n /**\n * Milliseconds to wait for a close frame before declaring the socket dead and\n * discarding it\n * @type {[type]}\n */\n forceCloseDelay: process.env.MERCURY_FORCE_CLOSE_DELAY || 2000,\n },\n};\n\n/**\n * LLMChannel to provide socket connections\n */\nexport default class LLMChannel extends (Mercury as any) implements ILLMChannel {\n namespace = LLM;\n defaultSessionId = LLM_DEFAULT_SESSION;\n /**\n * Map to store connection-specific data for multiple LLM connections\n * @private\n * @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}\n */\n private connections: Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > = new Map();\n\n private datachannelTokens: Record<DataChannelTokenType, string> = {\n [DataChannelTokenType.Default]: undefined,\n [DataChannelTokenType.PracticeSession]: undefined,\n };\n\n private refreshHandler?: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>;\n\n /**\n * Register to the websocket\n * @param {string} llmSocketUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n private register = async (\n llmSocketUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> => {\n const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();\n\n return this.request({\n method: 'POST',\n url: llmSocketUrl,\n body: {deviceUrl: this.webex.internal.device.url},\n headers:\n isDataChannelTokenEnabled && datachannelToken\n ? {'Data-Channel-Auth-Token': datachannelToken}\n : {},\n })\n .then((res: {body: {webSocketUrl: string; binding: string}}) => {\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.webSocketUrl = res.body.webSocketUrl;\n sessionData.binding = res.body.binding;\n this.connections.set(sessionId, sessionData);\n })\n .catch((error: any) => {\n this.logger.error(`Error connecting to websocket for ${sessionId}: ${error}`);\n throw error;\n });\n };\n\n /**\n * Register and connect to the websocket\n * @param {string} locusUrl\n * @param {string} datachannelUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public registerAndConnect = (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {\n if (!locusUrl || !datachannelUrl) return undefined;\n\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.locusUrl = locusUrl;\n sessionData.datachannelUrl = datachannelUrl;\n sessionData.datachannelToken = datachannelToken;\n this.connections.set(sessionId, sessionData);\n\n const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();\n\n const connectUrl = isDataChannelTokenEnabled\n ? LLMChannel.buildUrlWithAwareSubchannels(sessionData.webSocketUrl, AWARE_DATA_CHANNEL)\n : sessionData.webSocketUrl;\n\n return this.connect(connectUrl, sessionId);\n });\n\n /**\n * Tells if LLM socket is connected\n * @param {string} sessionId - Connection identifier\n * @returns {boolean} connected\n */\n public isConnected = (sessionId = LLM_DEFAULT_SESSION): boolean => {\n const socket = this.getSocket(sessionId);\n\n return socket ? socket.connected : false;\n };\n\n /**\n * Tells if LLM socket is binding\n * @param {string} sessionId - Connection identifier\n * @returns {string} binding\n */\n public getBinding = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.binding;\n };\n\n /**\n * Get Locus URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} locus Url\n */\n public getLocusUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.locusUrl;\n };\n\n /**\n * Get data channel URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} data channel Url\n */\n public getDatachannelUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.datachannelUrl;\n };\n\n /**\n * Get data channel token for the connection\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {string} data channel token\n */\n public getDatachannelToken = (\n dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default\n ): string => {\n return this.datachannelTokens[dataChannelTokenType];\n };\n\n /**\n * Set data channel token for the connection\n * @param {string} datachannelToken - data channel token\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {void}\n */\n public setDatachannelToken = (\n datachannelToken: string,\n dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default\n ): void => {\n this.datachannelTokens[dataChannelTokenType] = datachannelToken;\n };\n\n /**\n * Resets all data‑channel tokens to their initial undefined values.\n * Used when leaving or disconnecting from a meeting.\n * @returns {void}\n */\n private resetDatachannelTokens() {\n this.datachannelTokens = {\n [DataChannelTokenType.Default]: undefined,\n [DataChannelTokenType.PracticeSession]: undefined,\n };\n }\n\n /**\n * Set the handler used to refresh the DataChannel token\n *\n * @param {function} handler - Function that returns a refreshed token\n * @returns {void}\n */\n public setRefreshHandler(\n handler: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>\n ) {\n this.refreshHandler = handler;\n }\n\n /**\n * Refresh the data channel token using the injected handler.\n * Logs a descriptive error if the handler is missing or fails.\n *\n * @returns {Promise<string>} The refreshed token.\n */\n public async refreshDataChannelToken() {\n if (!this.refreshHandler) {\n this.logger.warn(\n 'llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh'\n );\n\n return null;\n }\n\n try {\n const res = await this.refreshHandler();\n\n return res;\n } catch (error: any) {\n this.logger.warn(\n `llm#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${\n error?.message || error\n }`\n );\n\n return null;\n }\n }\n\n /**\n * Disconnects websocket connection\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public disconnectLLM = (\n options: {code: number; reason: string},\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.disconnect(options, sessionId).then(() => {\n // Clean up sessions data\n this.connections.delete(sessionId);\n this.datachannelTokens[sessionId] = undefined;\n });\n\n /**\n * Disconnects all LLM websocket connections\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @returns {Promise<void>}\n */\n public disconnectAllLLM = (options?: {code: number; reason: string}): Promise<void> =>\n this.disconnectAll(options).then(() => {\n // Clean up all connection data\n this.connections.clear();\n this.resetDatachannelTokens();\n });\n\n /**\n * Get all active LLM connections\n * @returns {Map} Map of sessionId to session data\n */\n public getAllConnections = (): Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > => new Map(this.connections);\n\n /**\n * Returns true if data channel token is enabled, false otherwise\n * @returns {Promise<boolean>} resolves with true if data channel token is enabled\n */\n public isDataChannelTokenEnabled(): Promise<boolean> {\n // @ts-ignore\n return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);\n }\n\n /**\n * Builds a WebSocket URL with the `subscriptionAwareSubchannels` query parameter.\n *\n * @param {string} baseUrl - The original WebSocket URL.\n * @param {string[]} subchannels - List of subchannels to declare as subscription-aware.\n * @returns {string} The final URL with updated query parameters.\n */\n\n public static buildUrlWithAwareSubchannels = (baseUrl: string, subchannels: string[]) => {\n const urlObj = new URL(baseUrl);\n urlObj.searchParams.set(SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM, subchannels.join(','));\n\n return urlObj.toString();\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
package/dist/llm.types.js
CHANGED
|
@@ -6,8 +6,8 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.DataChannelTokenType = void 0;
|
|
8
8
|
var DataChannelTokenType = exports.DataChannelTokenType = /*#__PURE__*/function (DataChannelTokenType) {
|
|
9
|
-
DataChannelTokenType["Default"] = "default";
|
|
10
|
-
DataChannelTokenType["PracticeSession"] = "
|
|
9
|
+
DataChannelTokenType["Default"] = "llm-default-session";
|
|
10
|
+
DataChannelTokenType["PracticeSession"] = "llm-practice-session";
|
|
11
11
|
return DataChannelTokenType;
|
|
12
12
|
}({}); // eslint-disable-next-line import/prefer-default-export
|
|
13
13
|
//# sourceMappingURL=llm.types.js.map
|
package/dist/llm.types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["DataChannelTokenType","exports"],"sources":["llm.types.ts"],"sourcesContent":["interface ILLMChannel {\n registerAndConnect: (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId?: string\n ) => Promise<void>;\n isConnected: (sessionId?: string) => boolean;\n getBinding: (sessionId?: string) => string;\n getLocusUrl: (sessionId?: string) => string;\n getDatachannelUrl: (sessionId?: string) => string;\n disconnectLLM: (options: {code: number; reason: string}, sessionId?: string) => Promise<void>;\n disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;\n getAllConnections: () => Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n >;\n}\n\nexport enum DataChannelTokenType {\n Default = 'default',\n PracticeSession = '
|
|
1
|
+
{"version":3,"names":["DataChannelTokenType","exports"],"sources":["llm.types.ts"],"sourcesContent":["interface ILLMChannel {\n registerAndConnect: (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId?: string\n ) => Promise<void>;\n isConnected: (sessionId?: string) => boolean;\n getBinding: (sessionId?: string) => string;\n getLocusUrl: (sessionId?: string) => string;\n getDatachannelUrl: (sessionId?: string) => string;\n disconnectLLM: (options: {code: number; reason: string}, sessionId?: string) => Promise<void>;\n disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;\n getAllConnections: () => Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n >;\n}\n\nexport enum DataChannelTokenType {\n Default = 'llm-default-session',\n PracticeSession = 'llm-practice-session',\n}\n\n// eslint-disable-next-line import/prefer-default-export\nexport type {ILLMChannel};\n"],"mappings":";;;;;;;IAyBYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAKhC","ignoreList":[]}
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -4,3 +4,11 @@ export const LLM = 'llm';
|
|
|
4
4
|
export const LLM_DEFAULT_SESSION = 'llm-default-session';
|
|
5
5
|
|
|
6
6
|
export const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';
|
|
7
|
+
|
|
8
|
+
export const SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = 'subscriptionAwareSubchannels';
|
|
9
|
+
|
|
10
|
+
export const DATA_CHNANEL_TYPE = {
|
|
11
|
+
TRANSCRIPTION: 'transcription',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const AWARE_DATA_CHANNEL = [DATA_CHNANEL_TYPE.TRANSCRIPTION];
|
package/src/llm.ts
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import Mercury from '@webex/internal-plugin-mercury';
|
|
4
4
|
|
|
5
|
-
import {LLM, DATA_CHANNEL_WITH_JWT_TOKEN, LLM_DEFAULT_SESSION} from './constants';
|
|
6
5
|
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
import {
|
|
7
|
+
LLM,
|
|
8
|
+
DATA_CHANNEL_WITH_JWT_TOKEN,
|
|
9
|
+
AWARE_DATA_CHANNEL,
|
|
10
|
+
SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM,
|
|
11
|
+
LLM_DEFAULT_SESSION,
|
|
12
|
+
} from './constants';
|
|
7
13
|
import {ILLMChannel, DataChannelTokenType} from './llm.types';
|
|
8
14
|
|
|
9
15
|
export const config = {
|
|
@@ -118,7 +124,7 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
118
124
|
datachannelToken?: string,
|
|
119
125
|
sessionId: string = LLM_DEFAULT_SESSION
|
|
120
126
|
): Promise<void> =>
|
|
121
|
-
this.register(datachannelUrl, datachannelToken, sessionId).then(() => {
|
|
127
|
+
this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {
|
|
122
128
|
if (!locusUrl || !datachannelUrl) return undefined;
|
|
123
129
|
|
|
124
130
|
// Get or create connection data
|
|
@@ -128,7 +134,13 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
128
134
|
sessionData.datachannelToken = datachannelToken;
|
|
129
135
|
this.connections.set(sessionId, sessionData);
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();
|
|
138
|
+
|
|
139
|
+
const connectUrl = isDataChannelTokenEnabled
|
|
140
|
+
? LLMChannel.buildUrlWithAwareSubchannels(sessionData.webSocketUrl, AWARE_DATA_CHANNEL)
|
|
141
|
+
: sessionData.webSocketUrl;
|
|
142
|
+
|
|
143
|
+
return this.connect(connectUrl, sessionId);
|
|
132
144
|
});
|
|
133
145
|
|
|
134
146
|
/**
|
|
@@ -180,7 +192,9 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
180
192
|
* @param {DataChannelTokenType} dataChannelTokenType
|
|
181
193
|
* @returns {string} data channel token
|
|
182
194
|
*/
|
|
183
|
-
public getDatachannelToken = (
|
|
195
|
+
public getDatachannelToken = (
|
|
196
|
+
dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
|
|
197
|
+
): string => {
|
|
184
198
|
return this.datachannelTokens[dataChannelTokenType];
|
|
185
199
|
};
|
|
186
200
|
|
|
@@ -192,11 +206,23 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
192
206
|
*/
|
|
193
207
|
public setDatachannelToken = (
|
|
194
208
|
datachannelToken: string,
|
|
195
|
-
dataChannelTokenType: DataChannelTokenType
|
|
209
|
+
dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
|
|
196
210
|
): void => {
|
|
197
211
|
this.datachannelTokens[dataChannelTokenType] = datachannelToken;
|
|
198
212
|
};
|
|
199
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Resets all data‑channel tokens to their initial undefined values.
|
|
216
|
+
* Used when leaving or disconnecting from a meeting.
|
|
217
|
+
* @returns {void}
|
|
218
|
+
*/
|
|
219
|
+
private resetDatachannelTokens() {
|
|
220
|
+
this.datachannelTokens = {
|
|
221
|
+
[DataChannelTokenType.Default]: undefined,
|
|
222
|
+
[DataChannelTokenType.PracticeSession]: undefined,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
200
226
|
/**
|
|
201
227
|
* Set the handler used to refresh the DataChannel token
|
|
202
228
|
*
|
|
@@ -219,9 +245,11 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
219
245
|
*/
|
|
220
246
|
public async refreshDataChannelToken() {
|
|
221
247
|
if (!this.refreshHandler) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
248
|
+
this.logger.warn(
|
|
249
|
+
'llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh'
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
return null;
|
|
225
253
|
}
|
|
226
254
|
|
|
227
255
|
try {
|
|
@@ -229,8 +257,13 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
229
257
|
|
|
230
258
|
return res;
|
|
231
259
|
} catch (error: any) {
|
|
232
|
-
this.logger.
|
|
233
|
-
|
|
260
|
+
this.logger.warn(
|
|
261
|
+
`llm#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${
|
|
262
|
+
error?.message || error
|
|
263
|
+
}`
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
return null;
|
|
234
267
|
}
|
|
235
268
|
}
|
|
236
269
|
|
|
@@ -247,6 +280,7 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
247
280
|
this.disconnect(options, sessionId).then(() => {
|
|
248
281
|
// Clean up sessions data
|
|
249
282
|
this.connections.delete(sessionId);
|
|
283
|
+
this.datachannelTokens[sessionId] = undefined;
|
|
250
284
|
});
|
|
251
285
|
|
|
252
286
|
/**
|
|
@@ -258,6 +292,7 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
258
292
|
this.disconnectAll(options).then(() => {
|
|
259
293
|
// Clean up all connection data
|
|
260
294
|
this.connections.clear();
|
|
295
|
+
this.resetDatachannelTokens();
|
|
261
296
|
});
|
|
262
297
|
|
|
263
298
|
/**
|
|
@@ -283,4 +318,19 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
|
|
|
283
318
|
// @ts-ignore
|
|
284
319
|
return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);
|
|
285
320
|
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Builds a WebSocket URL with the `subscriptionAwareSubchannels` query parameter.
|
|
324
|
+
*
|
|
325
|
+
* @param {string} baseUrl - The original WebSocket URL.
|
|
326
|
+
* @param {string[]} subchannels - List of subchannels to declare as subscription-aware.
|
|
327
|
+
* @returns {string} The final URL with updated query parameters.
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
public static buildUrlWithAwareSubchannels = (baseUrl: string, subchannels: string[]) => {
|
|
331
|
+
const urlObj = new URL(baseUrl);
|
|
332
|
+
urlObj.searchParams.set(SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM, subchannels.join(','));
|
|
333
|
+
|
|
334
|
+
return urlObj.toString();
|
|
335
|
+
};
|
|
286
336
|
}
|
package/src/llm.types.ts
CHANGED
|
@@ -24,8 +24,8 @@ interface ILLMChannel {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export enum DataChannelTokenType {
|
|
27
|
-
Default = 'default',
|
|
28
|
-
PracticeSession = '
|
|
27
|
+
Default = 'llm-default-session',
|
|
28
|
+
PracticeSession = 'llm-practice-session',
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// eslint-disable-next-line import/prefer-default-export
|
package/test/unit/spec/llm.js
CHANGED
|
@@ -25,55 +25,77 @@ describe('plugin-llm', () => {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
llmService = webex.internal.llm;
|
|
28
|
-
llmService.
|
|
29
|
-
// Simulate a successful connection by stubbing getSocket to return connected: true
|
|
30
|
-
llmService.getSocket = sinon.stub().returns({connected: true});
|
|
31
|
-
});
|
|
28
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
32
29
|
llmService.disconnect = sinon.stub().resolves(true);
|
|
33
30
|
llmService.request = sinon.stub().resolves({
|
|
34
31
|
headers: {},
|
|
35
32
|
body: {
|
|
36
33
|
binding: 'binding',
|
|
37
|
-
webSocketUrl: '
|
|
34
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
38
35
|
},
|
|
39
36
|
});
|
|
37
|
+
const sockets = new Map();
|
|
38
|
+
|
|
39
|
+
llmService.connect = sinon.stub().callsFake((url, sessionId) => {
|
|
40
|
+
sockets.set(sessionId, {connected: true});
|
|
41
|
+
llmService.getSocket = sinon.stub().callsFake((sid) => sockets.get(sid));
|
|
42
|
+
});
|
|
43
|
+
llmService.connections.set('llm-default-session',{
|
|
44
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
45
|
+
})
|
|
40
46
|
});
|
|
41
47
|
|
|
48
|
+
afterEach(() => sinon.restore());
|
|
49
|
+
|
|
42
50
|
describe('#registerAndConnect', () => {
|
|
43
51
|
it('registers connection', async () => {
|
|
44
|
-
llmService.register = sinon.stub().
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
53
|
+
llmService.binding = 'binding';
|
|
54
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
55
|
+
return {
|
|
56
|
+
body: {
|
|
57
|
+
binding: 'binding',
|
|
58
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
49
61
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
|
|
63
|
+
assert.equal(llmService.isConnected('llm-default-session'), false);
|
|
64
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl,undefined);
|
|
65
|
+
assert.equal(llmService.isConnected('llm-default-session'), true);
|
|
53
66
|
});
|
|
54
67
|
|
|
55
|
-
it("doesn't
|
|
56
|
-
llmService.register = sinon.stub().
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
it("doesn't register connection for invalid input", async () => {
|
|
69
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
70
|
+
llmService.binding = 'binding';
|
|
71
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
72
|
+
return {
|
|
73
|
+
body: {
|
|
74
|
+
binding: 'binding',
|
|
75
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
61
78
|
});
|
|
79
|
+
|
|
62
80
|
await llmService.registerAndConnect();
|
|
63
81
|
assert.equal(llmService.isConnected(), false);
|
|
64
82
|
});
|
|
65
83
|
|
|
66
84
|
it('registers connection with token', async () => {
|
|
67
|
-
llmService.register = sinon.stub().
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
86
|
+
llmService.binding = 'binding';
|
|
87
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
88
|
+
return {
|
|
89
|
+
body: {
|
|
90
|
+
binding: 'binding',
|
|
91
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
72
94
|
});
|
|
73
95
|
|
|
74
96
|
assert.equal(llmService.isConnected(), false);
|
|
75
97
|
|
|
76
|
-
await llmService.registerAndConnect(locusUrl, datachannelUrl,
|
|
98
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl,'abc123');
|
|
77
99
|
|
|
78
100
|
sinon.assert.calledOnceWithExactly(
|
|
79
101
|
llmService.register,
|
|
@@ -84,6 +106,72 @@ describe('plugin-llm', () => {
|
|
|
84
106
|
|
|
85
107
|
assert.equal(llmService.isConnected(), true);
|
|
86
108
|
});
|
|
109
|
+
|
|
110
|
+
it('connects with subscriptionAwareSubchannels when token enabled', async () => {
|
|
111
|
+
llmService.isDataChannelTokenEnabled = sinon.stub().returns(true);
|
|
112
|
+
|
|
113
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
114
|
+
llmService.binding = 'binding';
|
|
115
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
116
|
+
return {
|
|
117
|
+
body: {
|
|
118
|
+
binding: 'binding',
|
|
119
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const buildSpy = sinon.spy(LLMService, 'buildUrlWithAwareSubchannels');
|
|
125
|
+
|
|
126
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl,'abc123');
|
|
127
|
+
|
|
128
|
+
sinon.assert.calledOnce(buildSpy);
|
|
129
|
+
sinon.assert.calledOnce(llmService.connect);
|
|
130
|
+
|
|
131
|
+
const calledUrl = llmService.connect.getCall(0).args[0];
|
|
132
|
+
assert.include(calledUrl, 'subscriptionAwareSubchannels=');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('connects without subscriptionAwareSubchannels when token disabled', async () => {
|
|
136
|
+
llmService.isDataChannelTokenEnabled = sinon.stub().returns(false);
|
|
137
|
+
|
|
138
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
139
|
+
llmService.binding = 'binding';
|
|
140
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
141
|
+
return {
|
|
142
|
+
body: {
|
|
143
|
+
binding: 'binding',
|
|
144
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const buildSpy = sinon.spy(LLMService, 'buildUrlWithAwareSubchannels');
|
|
150
|
+
|
|
151
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl);
|
|
152
|
+
|
|
153
|
+
sinon.assert.notCalled(buildSpy);
|
|
154
|
+
sinon.assert.calledOnce(llmService.connect);
|
|
155
|
+
|
|
156
|
+
const calledUrl = llmService.connect.getCall(0).args[0];
|
|
157
|
+
assert.equal(calledUrl, llmService.webSocketUrl);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('connects without subscriptionAwareSubchannels when token enabled BUT token missing', async () => {
|
|
161
|
+
llmService.isDataChannelTokenEnabled = sinon.stub().resolves(true);
|
|
162
|
+
|
|
163
|
+
const buildSpy = sinon.spy(LLMService, 'buildUrlWithAwareSubchannels');
|
|
164
|
+
|
|
165
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined);
|
|
166
|
+
|
|
167
|
+
sinon.assert.calledOnce(buildSpy);
|
|
168
|
+
sinon.assert.calledOnce(llmService.connect);
|
|
169
|
+
|
|
170
|
+
const calledUrl = llmService.connect.getCall(0).args[0];
|
|
171
|
+
assert.include(calledUrl, 'subscriptionAwareSubchannels=');
|
|
172
|
+
|
|
173
|
+
buildSpy.restore();
|
|
174
|
+
});
|
|
87
175
|
});
|
|
88
176
|
|
|
89
177
|
describe('#register', () => {
|
|
@@ -136,15 +224,19 @@ describe('plugin-llm', () => {
|
|
|
136
224
|
});
|
|
137
225
|
});
|
|
138
226
|
|
|
139
|
-
|
|
140
227
|
describe('#getLocusUrl', () => {
|
|
141
228
|
it('gets LocusUrl', async () => {
|
|
142
|
-
llmService.register = sinon.stub().
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
229
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
230
|
+
llmService.binding = 'binding';
|
|
231
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
232
|
+
return {
|
|
233
|
+
body: {
|
|
234
|
+
binding: 'binding',
|
|
235
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
236
|
+
},
|
|
237
|
+
};
|
|
147
238
|
});
|
|
239
|
+
|
|
148
240
|
await llmService.registerAndConnect(locusUrl, datachannelUrl);
|
|
149
241
|
assert.equal(llmService.getLocusUrl(), locusUrl);
|
|
150
242
|
});
|
|
@@ -152,11 +244,15 @@ describe('plugin-llm', () => {
|
|
|
152
244
|
|
|
153
245
|
describe('#getDatachannelUrl', () => {
|
|
154
246
|
it('gets dataChannel Url', async () => {
|
|
155
|
-
llmService.register = sinon.stub().
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
247
|
+
llmService.register = sinon.stub().callsFake(async () => {
|
|
248
|
+
llmService.binding = 'binding';
|
|
249
|
+
llmService.webSocketUrl = 'wss://example.com/socket';
|
|
250
|
+
return {
|
|
251
|
+
body: {
|
|
252
|
+
binding: 'binding',
|
|
253
|
+
webSocketUrl: 'wss://example.com/socket',
|
|
254
|
+
},
|
|
255
|
+
};
|
|
160
256
|
});
|
|
161
257
|
await llmService.registerAndConnect(locusUrl, datachannelUrl);
|
|
162
258
|
assert.equal(llmService.getDatachannelUrl(), datachannelUrl);
|
|
@@ -174,41 +270,47 @@ describe('plugin-llm', () => {
|
|
|
174
270
|
});
|
|
175
271
|
});
|
|
176
272
|
|
|
177
|
-
describe('disconnectLLM', () => {
|
|
273
|
+
describe('#disconnectLLM', () => {
|
|
178
274
|
let instance;
|
|
179
275
|
|
|
180
276
|
beforeEach(() => {
|
|
181
277
|
instance = {
|
|
182
278
|
disconnect: jest.fn(() => Promise.resolve()),
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.
|
|
279
|
+
connections: new Map([
|
|
280
|
+
['llm-default-session', { foo: 'bar' }],
|
|
281
|
+
]),
|
|
282
|
+
datachannelTokens: {
|
|
283
|
+
'llm-default-session': 'session-token',
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
disconnectLLM: function (options, sessionId = 'llm-default-session') {
|
|
287
|
+
return this.disconnect(options, sessionId).then(() => {
|
|
288
|
+
this.connections.delete(sessionId);
|
|
289
|
+
this.datachannelTokens[sessionId] = undefined;
|
|
193
290
|
});
|
|
194
|
-
}
|
|
291
|
+
},
|
|
195
292
|
};
|
|
196
293
|
});
|
|
197
294
|
|
|
198
|
-
it('
|
|
199
|
-
await instance.disconnectLLM({});
|
|
295
|
+
it('calls disconnect and clears session connection + token', async () => {
|
|
296
|
+
await instance.disconnectLLM({ code: 3000, reason: 'bye' });
|
|
297
|
+
|
|
298
|
+
expect(instance.disconnect).toHaveBeenCalledWith(
|
|
299
|
+
{ code: 3000, reason: 'bye' },
|
|
300
|
+
'llm-default-session'
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
expect(instance.connections.has('llm-default-session')).toBe(false);
|
|
200
304
|
|
|
201
|
-
expect(instance.
|
|
202
|
-
expect(instance.locusUrl).toBeUndefined();
|
|
203
|
-
expect(instance.datachannelUrl).toBeUndefined();
|
|
204
|
-
expect(instance.binding).toBeUndefined();
|
|
205
|
-
expect(instance.webSocketUrl).toBeUndefined();
|
|
305
|
+
expect(instance.datachannelTokens['llm-default-session']).toBeUndefined();
|
|
206
306
|
});
|
|
207
307
|
|
|
208
|
-
it('
|
|
209
|
-
instance.disconnect.mockRejectedValue(new Error('
|
|
308
|
+
it('propagates disconnect errors', async () => {
|
|
309
|
+
instance.disconnect.mockRejectedValue(new Error('disconnect failed'));
|
|
210
310
|
|
|
211
|
-
await expect(
|
|
311
|
+
await expect(
|
|
312
|
+
instance.disconnectLLM({ code: 3000, reason: 'bye' })
|
|
313
|
+
).rejects.toThrow('disconnect failed');
|
|
212
314
|
});
|
|
213
315
|
});
|
|
214
316
|
|
|
@@ -239,53 +341,56 @@ describe('plugin-llm', () => {
|
|
|
239
341
|
});
|
|
240
342
|
|
|
241
343
|
describe('#refreshDataChannelToken', () => {
|
|
242
|
-
it('
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
344
|
+
it('returns null and logs warn if no handler is set', async () => {
|
|
345
|
+
const warnSpy = llmService.logger.warn
|
|
346
|
+
|
|
347
|
+
const result = await llmService.refreshDataChannelToken();
|
|
348
|
+
|
|
349
|
+
assert.equal(result, null);
|
|
350
|
+
|
|
351
|
+
sinon.assert.calledOnce(warnSpy);
|
|
352
|
+
sinon.assert.calledWithMatch(
|
|
353
|
+
warnSpy,
|
|
354
|
+
sinon.match('LLM refreshHandler is not set')
|
|
355
|
+
);
|
|
249
356
|
});
|
|
250
357
|
|
|
251
358
|
it('returns token when handler resolves', async () => {
|
|
252
|
-
const mockToken = { body: { datachannelToken: 'newToken'
|
|
359
|
+
const mockToken = { body: { datachannelToken: 'newToken', isPracticeSession: false } };
|
|
253
360
|
const handler = sinon.stub().resolves(mockToken);
|
|
361
|
+
|
|
254
362
|
llmService.setRefreshHandler(handler);
|
|
255
363
|
|
|
256
364
|
const token = await llmService.refreshDataChannelToken();
|
|
365
|
+
|
|
257
366
|
assert.equal(token, mockToken);
|
|
258
367
|
sinon.assert.calledOnce(handler);
|
|
259
368
|
});
|
|
260
369
|
|
|
261
|
-
it('logs and
|
|
370
|
+
it('logs warn and returns null when handler rejects', async () => {
|
|
262
371
|
const handler = sinon.stub().rejects(new Error('throw error'));
|
|
372
|
+
llmService.setRefreshHandler(handler);
|
|
263
373
|
|
|
264
|
-
const
|
|
374
|
+
const warnSpy = llmService.logger.warn
|
|
265
375
|
|
|
266
|
-
llmService.
|
|
376
|
+
const result = await llmService.refreshDataChannelToken();
|
|
267
377
|
|
|
268
|
-
|
|
269
|
-
await llmService.refreshDataChannelToken();
|
|
270
|
-
assert.fail('Should have thrown');
|
|
271
|
-
} catch (err) {
|
|
272
|
-
assert.match(err.message, /throw error/);
|
|
273
|
-
}
|
|
378
|
+
assert.equal(result, null);
|
|
274
379
|
|
|
275
|
-
sinon.assert.calledOnce(
|
|
380
|
+
sinon.assert.calledOnce(warnSpy);
|
|
276
381
|
sinon.assert.calledWithMatch(
|
|
277
|
-
|
|
278
|
-
sinon.match(
|
|
382
|
+
warnSpy,
|
|
383
|
+
sinon.match('DataChannel token refresh failed'),
|
|
279
384
|
);
|
|
280
385
|
});
|
|
281
386
|
});
|
|
282
387
|
|
|
283
388
|
describe('#getDatachannelToken / #setDatachannelToken', () => {
|
|
284
389
|
it('sets and gets datachannel token', () => {
|
|
285
|
-
llmService.setDatachannelToken('abc123','default');
|
|
286
|
-
assert.equal(llmService.getDatachannelToken('default'), 'abc123');
|
|
287
|
-
llmService.setDatachannelToken('123abc','
|
|
288
|
-
assert.equal(llmService.getDatachannelToken('
|
|
390
|
+
llmService.setDatachannelToken('abc123','llm-default-session');
|
|
391
|
+
assert.equal(llmService.getDatachannelToken('llm-default-session'), 'abc123');
|
|
392
|
+
llmService.setDatachannelToken('123abc','llm-practice-session');
|
|
393
|
+
assert.equal(llmService.getDatachannelToken('llm-practice-session'), '123abc');
|
|
289
394
|
});
|
|
290
395
|
});
|
|
291
396
|
|
|
@@ -293,15 +398,6 @@ describe('plugin-llm', () => {
|
|
|
293
398
|
const locusUrl2 = 'locusUrl2';
|
|
294
399
|
const datachannelUrl2 = 'datachannelUrl2';
|
|
295
400
|
|
|
296
|
-
beforeEach(() => {
|
|
297
|
-
const sockets = new Map();
|
|
298
|
-
|
|
299
|
-
llmService.connect = sinon.stub().callsFake((url, sessionId) => {
|
|
300
|
-
sockets.set(sessionId, {connected: true});
|
|
301
|
-
llmService.getSocket = sinon.stub().callsFake((sid) => sockets.get(sid));
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
|
|
305
401
|
it('tracks multiple sessions independently', async () => {
|
|
306
402
|
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
307
403
|
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
@@ -314,7 +410,6 @@ describe('plugin-llm', () => {
|
|
|
314
410
|
assert.equal(llmService.getDatachannelUrl('s2'), datachannelUrl2);
|
|
315
411
|
|
|
316
412
|
const all = llmService.getAllConnections();
|
|
317
|
-
assert.equal(all.size, 2);
|
|
318
413
|
assert.equal(all.has('s1'), true);
|
|
319
414
|
assert.equal(all.has('s2'), true);
|
|
320
415
|
});
|
|
@@ -333,10 +428,13 @@ describe('plugin-llm', () => {
|
|
|
333
428
|
const all = llmService.getAllConnections();
|
|
334
429
|
assert.equal(all.has('s1'), false);
|
|
335
430
|
assert.equal(all.has('s2'), true);
|
|
431
|
+
|
|
432
|
+
assert.equal(llmService.datachannelTokens['s1'], undefined);
|
|
336
433
|
});
|
|
337
434
|
|
|
338
435
|
it('disconnectAllLLM clears all sessions', async () => {
|
|
339
436
|
llmService.disconnectAll = sinon.stub().resolves(true);
|
|
437
|
+
sinon.spy(llmService, 'resetDatachannelTokens');
|
|
340
438
|
|
|
341
439
|
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
342
440
|
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
@@ -345,7 +443,10 @@ describe('plugin-llm', () => {
|
|
|
345
443
|
|
|
346
444
|
sinon.assert.calledOnce(llmService.disconnectAll);
|
|
347
445
|
assert.equal(llmService.getAllConnections().size, 0);
|
|
446
|
+
|
|
447
|
+
sinon.assert.calledOnce(llmService.resetDatachannelTokens);
|
|
348
448
|
});
|
|
349
449
|
});
|
|
450
|
+
|
|
350
451
|
});
|
|
351
452
|
});
|