@webex/internal-plugin-llm 3.12.0-next.19 → 3.12.0-next.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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","_callee2","connectUrl","_context2","buildUrlWithAwareSubchannels","AWARE_DATA_CHANNEL","connect","socket","getSocket","connected","ownerMeetingId","dataChannelTokenType","datachannelTokens","options","disconnect","delete","disconnectAll","clear","_inherits2","_createClass2","key","value","resetDatachannelTokens","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 ownerMeetingId?: 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 * Set the owner meeting ID for a given LLM session. Used by the meetings\n * plugin to tag which Meeting instance currently owns the (default) LLM\n * connection so that other Meeting instances can avoid disconnecting or\n * re-initializing a connection they do not own.\n *\n * Does NOT create a connections entry if one does not already exist — this\n * method is a no-op when there is no active session data. Callers should\n * invoke it after a successful `registerAndConnect` or during an explicit\n * ownership handoff.\n *\n * @param {string | undefined} ownerMeetingId - Meeting ID (or undefined to clear)\n * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {void}\n */\n public setOwnerMeetingId = (\n ownerMeetingId: string | undefined,\n sessionId: string = LLM_DEFAULT_SESSION\n ): void => {\n const sessionData = this.connections.get(sessionId);\n\n if (!sessionData) {\n return;\n }\n\n sessionData.ownerMeetingId = ownerMeetingId;\n this.connections.set(sessionId, sessionData);\n };\n\n /**\n * Get the owner meeting ID currently associated with an LLM session.\n * Returns undefined when no owner has been assigned (e.g. before the\n * first successful `registerAndConnect`, or after `disconnectLLM`).\n *\n * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {string | undefined} ownerMeetingId\n */\n public getOwnerMeetingId = (sessionId: string = LLM_DEFAULT_SESSION): string | undefined => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.ownerMeetingId;\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 public 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 });\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 ownerMeetingId?: 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":[]}
1
+ {"version":3,"names":["_internalPluginMercury","_interopRequireDefault","require","_constants","_llm","_createForOfIteratorHelper","r","e","t","_Symbol","_Symbol$iterator","_Array$isArray","_unsupportedIterableToArray","length","_n","F","s","n","done","value","f","TypeError","o","a","u","call","next","return","_arrayLikeToArray","toString","slice","constructor","name","_Array$from","test","Array","_callSuper","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","apply","Boolean","prototype","valueOf","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","args","_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","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","ownerMeetingId","currentOwner","getOwnerMeetingId","isOwner","tokenKey","resolvedTokenKey","_this$resolveSessionO","resolveSessionOwnership","info","datachannelTokens","_this$resolveSessionO2","_this$resolveSessionO3","options","resolvedSessionId","resolvedOwnerMeetingId","warn","_this$resolveSessionO4","_promise","resolve","disconnect","setOwnerMeetingId","delete","disconnectAll","clear","_inherits2","_createClass2","key","setRefreshHandler","handler","_this$resolveSessionO5","refreshHandler","_refreshDataChannelToken","_callee3","_this$connections$get","_args3","_t","_context3","message","refreshDataChannelToken","getLocusUrlByDatachannelUrl","requestUrl","_iterator","_step","_step$value","_slicedToArray2","connection","matchesDatachannelRequestUrl","err","getSessionIdByDatachannelUrl","_iterator2","_step2","_step2$value","feature","getFeature","DATA_CHANNEL_WITH_JWT_TOKEN","registrationUrl","startsWith","URL","registration","pathname","Mercury","baseUrl","subchannels","urlObj","searchParams","SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM","join"],"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 * Key: sessionId\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 ownerMeetingId?: string;\n refreshHandler?: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>;\n }\n > = new Map();\n\n // Session-keyed token cache is intentionally decoupled from connection state.\n // Disconnecting a socket session must not implicitly wipe token cache.\n private datachannelTokens: Record<string, string | undefined> = {\n [DataChannelTokenType.Default]: undefined,\n [DataChannelTokenType.PracticeSession]: undefined,\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 // Pre-populate locusUrl and datachannelUrl before register() fires the\n // HTTP POST, so that any token refresh triggered during registration can\n // be routed via connections without falling back to a locusInfo URL scan.\n if (locusUrl && datachannelUrl) {\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.locusUrl = locusUrl;\n sessionData.datachannelUrl = datachannelUrl;\n this.connections.set(sessionId, sessionData);\n }\n\n return this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {\n if (!locusUrl || !datachannelUrl) return undefined;\n\n // locusUrl and datachannelUrl were pre-populated before register(); here\n // we only need to read the existing session data to get webSocketUrl/binding\n // that register() filled in.\n const sessionData = this.connections.get(sessionId) || {};\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 /**\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 * Set the owner meeting ID for a given LLM session. Used by the meetings\n * plugin to tag which Meeting instance currently owns the (default) LLM\n * connection so that other Meeting instances can avoid disconnecting or\n * re-initializing a connection they do not own.\n *\n * Does NOT create a connections entry if one does not already exist — this\n * method is a no-op when there is no active session data. Callers should\n * invoke it after a successful `registerAndConnect` or during an explicit\n * ownership handoff.\n *\n * @param {string | undefined} ownerMeetingId - Meeting ID (or undefined to clear)\n * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {void}\n */\n public setOwnerMeetingId = (\n ownerMeetingId: string | undefined,\n sessionId: string = LLM_DEFAULT_SESSION\n ): void => {\n const sessionData = this.connections.get(sessionId);\n\n if (!sessionData) {\n return;\n }\n\n sessionData.ownerMeetingId = ownerMeetingId;\n this.connections.set(sessionId, sessionData);\n };\n\n /**\n * Get the owner meeting ID currently associated with an LLM session.\n * Returns undefined when no owner has been assigned (e.g. before the\n * first successful `registerAndConnect`, or after `disconnectLLM`).\n *\n * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {string | undefined} ownerMeetingId\n */\n public getOwnerMeetingId = (sessionId: string = LLM_DEFAULT_SESSION): string | undefined => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.ownerMeetingId;\n };\n\n /**\n * Resolve ownership information for an LLM session.\n *\n * Rules:\n * - no current owner => caller may proceed\n * - caller has no identity to assert => treat as owner\n * - otherwise caller must match current owner\n *\n * @param {string | undefined} ownerMeetingId - Candidate owner to evaluate\n * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {{currentOwner: (string|undefined), isOwner: boolean}}\n */\n public resolveSessionOwnership = (\n ownerMeetingId?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): {\n currentOwner: string | undefined;\n isOwner: boolean;\n } => {\n const currentOwner = this.getOwnerMeetingId(sessionId);\n const isOwner = !currentOwner || !ownerMeetingId || currentOwner === ownerMeetingId;\n\n return {\n currentOwner,\n isOwner,\n };\n };\n\n /**\n * Get data channel token for the connection\n * @param {DataChannelTokenType|string} tokenKey\n * @param {string | undefined} ownerMeetingId - Meeting id asserting read ownership\n * @returns {string | undefined} data channel token\n */\n public getDatachannelToken = (\n tokenKey?: DataChannelTokenType | string,\n ownerMeetingId?: string\n ): string | undefined => {\n const resolvedTokenKey = tokenKey ?? DataChannelTokenType.Default;\n\n const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);\n\n if (!isOwner) {\n this.logger.info(\n `llm#getDatachannelToken --> skip read for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`\n );\n\n return undefined;\n }\n\n return this.datachannelTokens[resolvedTokenKey];\n };\n\n /**\n * Set data channel token for the connection\n * @param {string} datachannelToken - data channel token\n * @param {DataChannelTokenType|string} [tokenKey]\n * @param {string | undefined} ownerMeetingId - Meeting id asserting write ownership\n * @returns {void}\n */\n public setDatachannelToken = (\n datachannelToken: string,\n tokenKey?: DataChannelTokenType | string,\n ownerMeetingId?: string\n ): void => {\n const resolvedTokenKey = tokenKey ?? DataChannelTokenType.Default;\n\n const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);\n\n if (!isOwner) {\n this.logger.info(\n `llm#setDatachannelToken --> skip write for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`\n );\n\n return;\n }\n\n this.datachannelTokens[resolvedTokenKey] = datachannelToken;\n };\n\n /**\n * Clears a single session's data channel token.\n * @param {DataChannelTokenType|string} tokenKey\n * @param {string} ownerMeetingId - Meeting id asserting delete ownership\n * @returns {void}\n */\n public clearDatachannelToken = (\n tokenKey: DataChannelTokenType | string,\n ownerMeetingId: string\n ): void => {\n const resolvedTokenKey = tokenKey;\n\n const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);\n\n if (!isOwner) {\n this.logger.info(\n `llm#clearDatachannelToken --> skip clear for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`\n );\n\n return;\n }\n\n this.datachannelTokens[resolvedTokenKey] = undefined;\n delete this.datachannelTokens[resolvedTokenKey];\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 * @param {string} [sessionId] - Connection identifier\n * @param {string | undefined} ownerMeetingId - Meeting id asserting refresh-handler ownership\n * @returns {void}\n */\n public setRefreshHandler(\n handler: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>,\n sessionId?: string,\n ownerMeetingId?: string\n ) {\n const resolvedSessionId = sessionId ?? LLM_DEFAULT_SESSION;\n\n const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedSessionId);\n\n if (!isOwner) {\n this.logger.info(\n `llm#setRefreshHandler --> skip write for session ${resolvedSessionId}; owned by ${currentOwner}, candidate ${ownerMeetingId}`\n );\n\n return;\n }\n\n const sessionData = this.connections.get(resolvedSessionId);\n\n if (sessionData) {\n sessionData.refreshHandler = handler;\n if (ownerMeetingId) {\n sessionData.ownerMeetingId = ownerMeetingId;\n }\n\n return;\n }\n\n // Intentionally allow a pre-connection session shape here.\n // Some flows inject refreshHandler before register/connect so token refresh\n // is already wired when the socket lifecycle starts. register()/\n // registerAndConnect() will later fill webSocketUrl/binding/locusUrl/\n // datachannelUrl into this same session entry.\n this.connections.set(resolvedSessionId, {\n refreshHandler: handler,\n ownerMeetingId,\n });\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 * @param {string} sessionId - Connection identifier (defaults to default session)\n * @returns {Promise<string>} The refreshed token.\n */\n public async refreshDataChannelToken(sessionId: string = LLM_DEFAULT_SESSION) {\n const refreshHandler = this.connections.get(sessionId)?.refreshHandler;\n\n if (!refreshHandler) {\n this.logger.warn(\n `llm#refreshDataChannelToken --> LLM refreshHandler is not set for session ${sessionId}, skipping token refresh`\n );\n\n return null;\n }\n\n try {\n const res = await 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 * @param {string} ownerMeetingId - Meeting id asserting disconnect ownership\n * @returns {Promise<boolean>} True when disconnect was performed, false when skipped\n */\n public disconnectLLM = (\n options: {code: number; reason: string},\n sessionId?: string,\n ownerMeetingId?: string\n ): Promise<boolean> => {\n const resolvedSessionId = sessionId ?? LLM_DEFAULT_SESSION;\n\n // Backward-compat path: historically callers could omit ownerMeetingId\n // (and sometimes sessionId). Reuse current owner when available so legacy\n // calls remain best-effort without throwing at teardown time.\n const resolvedOwnerMeetingId = ownerMeetingId || this.getOwnerMeetingId(resolvedSessionId);\n\n if (!ownerMeetingId) {\n this.logger.warn(\n `llm#disconnectLLM --> ownerMeetingId is omitted for session ${resolvedSessionId}; using legacy compatibility path`\n );\n }\n\n const {currentOwner, isOwner} = this.resolveSessionOwnership(\n resolvedOwnerMeetingId,\n resolvedSessionId\n );\n\n if (!isOwner) {\n this.logger.info(\n `llm#disconnectLLM --> skip disconnect for session ${resolvedSessionId}; owned by ${currentOwner}, candidate ${resolvedOwnerMeetingId}`\n );\n\n return Promise.resolve(false);\n }\n\n return this.disconnect(options, resolvedSessionId).then(() => {\n // Clear owner tag before cleanup to ensure it's not lingering\n // if another meeting claimed it during disconnect\n this.setOwnerMeetingId(undefined, resolvedSessionId);\n\n // Clean up sessions data\n this.connections.delete(resolvedSessionId);\n\n return true;\n });\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 ownerMeetingId?: string;\n }\n > => new Map(this.connections);\n\n /**\n * Look up the locusUrl associated with a datachannel request URL.\n * Iterates all active LLM sessions and returns the locusUrl of the\n * session whose stored datachannelUrl is a prefix of the given request URL.\n *\n * @param {string} requestUrl - The in-flight request URL to match\n * @returns {string | undefined} The matching locusUrl, or undefined if not found\n */\n public getLocusUrlByDatachannelUrl(requestUrl: string): string | undefined {\n for (const [, connection] of this.connections) {\n if (\n connection.datachannelUrl &&\n LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)\n ) {\n return connection.locusUrl;\n }\n }\n\n return undefined;\n }\n\n /**\n * Look up the sessionId associated with a datachannel request URL.\n * Iterates all active LLM sessions and returns the sessionId whose\n * stored datachannelUrl is a prefix of the given request URL.\n *\n * @param {string} requestUrl - The in-flight request URL to match\n * @returns {string | undefined} The matching sessionId, or undefined if not found\n */\n public getSessionIdByDatachannelUrl(requestUrl: string): string | undefined {\n for (const [sessionId, connection] of this.connections) {\n if (\n connection.datachannelUrl &&\n LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)\n ) {\n return sessionId;\n }\n }\n\n return undefined;\n }\n\n /**\n * Matches a request URL to a stored datachannel registration URL.\n * Host can differ (e.g. rewritten by hostmap interceptor), so we first\n * try full URL prefix and then fall back to pathname prefix.\n * @param {string} requestUrl\n * @param {string} registrationUrl\n * @returns {boolean}\n */\n public static matchesDatachannelRequestUrl(requestUrl: string, registrationUrl: string): boolean {\n if (!requestUrl || !registrationUrl) {\n return false;\n }\n\n if (requestUrl.startsWith(registrationUrl)) {\n return true;\n }\n\n try {\n const request = new URL(requestUrl);\n const registration = new URL(registrationUrl);\n\n return request.pathname.startsWith(registration.pathname);\n } catch (error) {\n return false;\n }\n }\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":[]}
@@ -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 setOwnerMeetingId: (ownerMeetingId: string | undefined, sessionId?: string) => void;\n getOwnerMeetingId: (sessionId?: string) => string | undefined;\n getAllConnections: () => Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n ownerMeetingId?: 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":";;;;;;;IA4BYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAKhC","ignoreList":[]}
1
+ {"version":3,"names":["DataChannelTokenType","exports"],"sources":["llm.types.ts"],"sourcesContent":["export enum DataChannelTokenType {\n Default = 'llm-default-session',\n PracticeSession = 'llm-practice-session',\n}\n\ntype DataChannelTokenKey = DataChannelTokenType | string;\n\ninterface 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: (\n options: {code: number; reason: string},\n sessionId?: string,\n ownerMeetingId?: string\n ) => Promise<boolean>;\n disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;\n setOwnerMeetingId: (ownerMeetingId: string | undefined, sessionId?: string) => void;\n getOwnerMeetingId: (sessionId?: string) => string | undefined;\n resolveSessionOwnership: (\n ownerMeetingId?: string,\n sessionId?: string\n ) => {\n currentOwner: string | undefined;\n isOwner: boolean;\n };\n getDatachannelToken: (\n tokenKey?: DataChannelTokenKey,\n ownerMeetingId?: string\n ) => string | undefined;\n setDatachannelToken: (\n datachannelToken: string,\n tokenKey?: DataChannelTokenKey,\n ownerMeetingId?: string\n ) => void;\n clearDatachannelToken: (tokenKey: DataChannelTokenKey, ownerMeetingId: string) => void;\n setRefreshHandler: (\n handler: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>,\n sessionId?: string,\n ownerMeetingId?: string\n ) => void;\n refreshDataChannelToken: (sessionId?: string) => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n } | null>;\n getLocusUrlByDatachannelUrl: (requestUrl: string) => string | undefined;\n getSessionIdByDatachannelUrl: (requestUrl: string) => string | undefined;\n getAllConnections: () => Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n ownerMeetingId?: string;\n }\n >;\n}\n\n// eslint-disable-next-line import/prefer-default-export\nexport type {ILLMChannel, DataChannelTokenKey};\n"],"mappings":";;;;;;;IAAYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAmEhC","ignoreList":[]}
package/package.json CHANGED
@@ -44,5 +44,5 @@
44
44
  "test:style": "eslint ./src/**/*.*",
45
45
  "test:unit": "webex-legacy-tools test --unit --runner jest"
46
46
  },
47
- "version": "3.12.0-next.19"
47
+ "version": "3.12.0-next.20"
48
48
  }
package/src/constants.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  export const LLM = 'llm';
3
3
 
4
4
  export const LLM_DEFAULT_SESSION = 'llm-default-session';
5
+ export const LLM_PRACTICE_SESSION = 'llm-practice-session';
5
6
 
6
7
  export const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';
7
8
 
package/src/index.ts CHANGED
@@ -7,4 +7,5 @@ WebexCore.registerInternalPlugin('llm', LLMChannel, {
7
7
  });
8
8
 
9
9
  export {DataChannelTokenType};
10
+ export {LLM_DEFAULT_SESSION, LLM_PRACTICE_SESSION} from './constants';
10
11
  export {default} from './llm';
package/src/llm.ts CHANGED
@@ -51,6 +51,7 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
51
51
  defaultSessionId = LLM_DEFAULT_SESSION;
52
52
  /**
53
53
  * Map to store connection-specific data for multiple LLM connections
54
+ * Key: sessionId
54
55
  * @private
55
56
  * @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}
56
57
  */
@@ -61,20 +62,20 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
61
62
  binding?: string;
62
63
  locusUrl?: string;
63
64
  datachannelUrl?: string;
64
- datachannelToken?: string;
65
65
  ownerMeetingId?: string;
66
+ refreshHandler?: () => Promise<{
67
+ body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
68
+ }>;
66
69
  }
67
70
  > = new Map();
68
71
 
69
- private datachannelTokens: Record<DataChannelTokenType, string> = {
72
+ // Session-keyed token cache is intentionally decoupled from connection state.
73
+ // Disconnecting a socket session must not implicitly wipe token cache.
74
+ private datachannelTokens: Record<string, string | undefined> = {
70
75
  [DataChannelTokenType.Default]: undefined,
71
76
  [DataChannelTokenType.PracticeSession]: undefined,
72
77
  };
73
78
 
74
- private refreshHandler?: () => Promise<{
75
- body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
76
- }>;
77
-
78
79
  /**
79
80
  * Register to the websocket
80
81
  * @param {string} llmSocketUrl
@@ -124,16 +125,24 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
124
125
  datachannelUrl: string,
125
126
  datachannelToken?: string,
126
127
  sessionId: string = LLM_DEFAULT_SESSION
127
- ): Promise<void> =>
128
- this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {
129
- if (!locusUrl || !datachannelUrl) return undefined;
130
-
131
- // Get or create connection data
128
+ ): Promise<void> => {
129
+ // Pre-populate locusUrl and datachannelUrl before register() fires the
130
+ // HTTP POST, so that any token refresh triggered during registration can
131
+ // be routed via connections without falling back to a locusInfo URL scan.
132
+ if (locusUrl && datachannelUrl) {
132
133
  const sessionData = this.connections.get(sessionId) || {};
133
134
  sessionData.locusUrl = locusUrl;
134
135
  sessionData.datachannelUrl = datachannelUrl;
135
- sessionData.datachannelToken = datachannelToken;
136
136
  this.connections.set(sessionId, sessionData);
137
+ }
138
+
139
+ return this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {
140
+ if (!locusUrl || !datachannelUrl) return undefined;
141
+
142
+ // locusUrl and datachannelUrl were pre-populated before register(); here
143
+ // we only need to read the existing session data to get webSocketUrl/binding
144
+ // that register() filled in.
145
+ const sessionData = this.connections.get(sessionId) || {};
137
146
 
138
147
  const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();
139
148
 
@@ -143,6 +152,7 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
143
152
 
144
153
  return this.connect(connectUrl, sessionId);
145
154
  });
155
+ };
146
156
 
147
157
  /**
148
158
  * Tells if LLM socket is connected
@@ -231,73 +241,180 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
231
241
  return sessionData?.ownerMeetingId;
232
242
  };
233
243
 
244
+ /**
245
+ * Resolve ownership information for an LLM session.
246
+ *
247
+ * Rules:
248
+ * - no current owner => caller may proceed
249
+ * - caller has no identity to assert => treat as owner
250
+ * - otherwise caller must match current owner
251
+ *
252
+ * @param {string | undefined} ownerMeetingId - Candidate owner to evaluate
253
+ * @param {string} sessionId - Connection identifier (defaults to default session)
254
+ * @returns {{currentOwner: (string|undefined), isOwner: boolean}}
255
+ */
256
+ public resolveSessionOwnership = (
257
+ ownerMeetingId?: string,
258
+ sessionId: string = LLM_DEFAULT_SESSION
259
+ ): {
260
+ currentOwner: string | undefined;
261
+ isOwner: boolean;
262
+ } => {
263
+ const currentOwner = this.getOwnerMeetingId(sessionId);
264
+ const isOwner = !currentOwner || !ownerMeetingId || currentOwner === ownerMeetingId;
265
+
266
+ return {
267
+ currentOwner,
268
+ isOwner,
269
+ };
270
+ };
271
+
234
272
  /**
235
273
  * Get data channel token for the connection
236
- * @param {DataChannelTokenType} dataChannelTokenType
237
- * @returns {string} data channel token
274
+ * @param {DataChannelTokenType|string} tokenKey
275
+ * @param {string | undefined} ownerMeetingId - Meeting id asserting read ownership
276
+ * @returns {string | undefined} data channel token
238
277
  */
239
278
  public getDatachannelToken = (
240
- dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
241
- ): string => {
242
- return this.datachannelTokens[dataChannelTokenType];
279
+ tokenKey?: DataChannelTokenType | string,
280
+ ownerMeetingId?: string
281
+ ): string | undefined => {
282
+ const resolvedTokenKey = tokenKey ?? DataChannelTokenType.Default;
283
+
284
+ const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);
285
+
286
+ if (!isOwner) {
287
+ this.logger.info(
288
+ `llm#getDatachannelToken --> skip read for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`
289
+ );
290
+
291
+ return undefined;
292
+ }
293
+
294
+ return this.datachannelTokens[resolvedTokenKey];
243
295
  };
244
296
 
245
297
  /**
246
298
  * Set data channel token for the connection
247
299
  * @param {string} datachannelToken - data channel token
248
- * @param {DataChannelTokenType} dataChannelTokenType
300
+ * @param {DataChannelTokenType|string} [tokenKey]
301
+ * @param {string | undefined} ownerMeetingId - Meeting id asserting write ownership
249
302
  * @returns {void}
250
303
  */
251
304
  public setDatachannelToken = (
252
305
  datachannelToken: string,
253
- dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
306
+ tokenKey?: DataChannelTokenType | string,
307
+ ownerMeetingId?: string
254
308
  ): void => {
255
- this.datachannelTokens[dataChannelTokenType] = datachannelToken;
309
+ const resolvedTokenKey = tokenKey ?? DataChannelTokenType.Default;
310
+
311
+ const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);
312
+
313
+ if (!isOwner) {
314
+ this.logger.info(
315
+ `llm#setDatachannelToken --> skip write for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`
316
+ );
317
+
318
+ return;
319
+ }
320
+
321
+ this.datachannelTokens[resolvedTokenKey] = datachannelToken;
256
322
  };
257
323
 
258
324
  /**
259
- * Resets all data‑channel tokens to their initial undefined values.
260
- * Used when leaving or disconnecting from a meeting.
325
+ * Clears a single session's data channel token.
326
+ * @param {DataChannelTokenType|string} tokenKey
327
+ * @param {string} ownerMeetingId - Meeting id asserting delete ownership
261
328
  * @returns {void}
262
329
  */
263
- public resetDatachannelTokens() {
264
- this.datachannelTokens = {
265
- [DataChannelTokenType.Default]: undefined,
266
- [DataChannelTokenType.PracticeSession]: undefined,
267
- };
268
- }
330
+ public clearDatachannelToken = (
331
+ tokenKey: DataChannelTokenType | string,
332
+ ownerMeetingId: string
333
+ ): void => {
334
+ const resolvedTokenKey = tokenKey;
335
+
336
+ const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedTokenKey);
337
+
338
+ if (!isOwner) {
339
+ this.logger.info(
340
+ `llm#clearDatachannelToken --> skip clear for session ${resolvedTokenKey}; owned by ${currentOwner}, candidate ${ownerMeetingId}`
341
+ );
342
+
343
+ return;
344
+ }
345
+
346
+ this.datachannelTokens[resolvedTokenKey] = undefined;
347
+ delete this.datachannelTokens[resolvedTokenKey];
348
+ };
269
349
 
270
350
  /**
271
351
  * Set the handler used to refresh the DataChannel token
272
352
  *
273
353
  * @param {function} handler - Function that returns a refreshed token
354
+ * @param {string} [sessionId] - Connection identifier
355
+ * @param {string | undefined} ownerMeetingId - Meeting id asserting refresh-handler ownership
274
356
  * @returns {void}
275
357
  */
276
358
  public setRefreshHandler(
277
359
  handler: () => Promise<{
278
360
  body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
279
- }>
361
+ }>,
362
+ sessionId?: string,
363
+ ownerMeetingId?: string
280
364
  ) {
281
- this.refreshHandler = handler;
365
+ const resolvedSessionId = sessionId ?? LLM_DEFAULT_SESSION;
366
+
367
+ const {currentOwner, isOwner} = this.resolveSessionOwnership(ownerMeetingId, resolvedSessionId);
368
+
369
+ if (!isOwner) {
370
+ this.logger.info(
371
+ `llm#setRefreshHandler --> skip write for session ${resolvedSessionId}; owned by ${currentOwner}, candidate ${ownerMeetingId}`
372
+ );
373
+
374
+ return;
375
+ }
376
+
377
+ const sessionData = this.connections.get(resolvedSessionId);
378
+
379
+ if (sessionData) {
380
+ sessionData.refreshHandler = handler;
381
+ if (ownerMeetingId) {
382
+ sessionData.ownerMeetingId = ownerMeetingId;
383
+ }
384
+
385
+ return;
386
+ }
387
+
388
+ // Intentionally allow a pre-connection session shape here.
389
+ // Some flows inject refreshHandler before register/connect so token refresh
390
+ // is already wired when the socket lifecycle starts. register()/
391
+ // registerAndConnect() will later fill webSocketUrl/binding/locusUrl/
392
+ // datachannelUrl into this same session entry.
393
+ this.connections.set(resolvedSessionId, {
394
+ refreshHandler: handler,
395
+ ownerMeetingId,
396
+ });
282
397
  }
283
398
 
284
399
  /**
285
400
  * Refresh the data channel token using the injected handler.
286
401
  * Logs a descriptive error if the handler is missing or fails.
287
- *
402
+ * @param {string} sessionId - Connection identifier (defaults to default session)
288
403
  * @returns {Promise<string>} The refreshed token.
289
404
  */
290
- public async refreshDataChannelToken() {
291
- if (!this.refreshHandler) {
405
+ public async refreshDataChannelToken(sessionId: string = LLM_DEFAULT_SESSION) {
406
+ const refreshHandler = this.connections.get(sessionId)?.refreshHandler;
407
+
408
+ if (!refreshHandler) {
292
409
  this.logger.warn(
293
- 'llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh'
410
+ `llm#refreshDataChannelToken --> LLM refreshHandler is not set for session ${sessionId}, skipping token refresh`
294
411
  );
295
412
 
296
413
  return null;
297
414
  }
298
415
 
299
416
  try {
300
- const res = await this.refreshHandler();
417
+ const res = await refreshHandler();
301
418
 
302
419
  return res;
303
420
  } catch (error: any) {
@@ -315,16 +432,51 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
315
432
  * Disconnects websocket connection
316
433
  * @param {{code: number, reason: string}} options - The disconnect option object with code and reason
317
434
  * @param {string} sessionId - Connection identifier
318
- * @returns {Promise<void>}
435
+ * @param {string} ownerMeetingId - Meeting id asserting disconnect ownership
436
+ * @returns {Promise<boolean>} True when disconnect was performed, false when skipped
319
437
  */
320
438
  public disconnectLLM = (
321
439
  options: {code: number; reason: string},
322
- sessionId: string = LLM_DEFAULT_SESSION
323
- ): Promise<void> =>
324
- this.disconnect(options, sessionId).then(() => {
440
+ sessionId?: string,
441
+ ownerMeetingId?: string
442
+ ): Promise<boolean> => {
443
+ const resolvedSessionId = sessionId ?? LLM_DEFAULT_SESSION;
444
+
445
+ // Backward-compat path: historically callers could omit ownerMeetingId
446
+ // (and sometimes sessionId). Reuse current owner when available so legacy
447
+ // calls remain best-effort without throwing at teardown time.
448
+ const resolvedOwnerMeetingId = ownerMeetingId || this.getOwnerMeetingId(resolvedSessionId);
449
+
450
+ if (!ownerMeetingId) {
451
+ this.logger.warn(
452
+ `llm#disconnectLLM --> ownerMeetingId is omitted for session ${resolvedSessionId}; using legacy compatibility path`
453
+ );
454
+ }
455
+
456
+ const {currentOwner, isOwner} = this.resolveSessionOwnership(
457
+ resolvedOwnerMeetingId,
458
+ resolvedSessionId
459
+ );
460
+
461
+ if (!isOwner) {
462
+ this.logger.info(
463
+ `llm#disconnectLLM --> skip disconnect for session ${resolvedSessionId}; owned by ${currentOwner}, candidate ${resolvedOwnerMeetingId}`
464
+ );
465
+
466
+ return Promise.resolve(false);
467
+ }
468
+
469
+ return this.disconnect(options, resolvedSessionId).then(() => {
470
+ // Clear owner tag before cleanup to ensure it's not lingering
471
+ // if another meeting claimed it during disconnect
472
+ this.setOwnerMeetingId(undefined, resolvedSessionId);
473
+
325
474
  // Clean up sessions data
326
- this.connections.delete(sessionId);
475
+ this.connections.delete(resolvedSessionId);
476
+
477
+ return true;
327
478
  });
479
+ };
328
480
 
329
481
  /**
330
482
  * Disconnects all LLM websocket connections
@@ -348,11 +500,79 @@ export default class LLMChannel extends (Mercury as any) implements ILLMChannel
348
500
  binding?: string;
349
501
  locusUrl?: string;
350
502
  datachannelUrl?: string;
351
- datachannelToken?: string;
352
503
  ownerMeetingId?: string;
353
504
  }
354
505
  > => new Map(this.connections);
355
506
 
507
+ /**
508
+ * Look up the locusUrl associated with a datachannel request URL.
509
+ * Iterates all active LLM sessions and returns the locusUrl of the
510
+ * session whose stored datachannelUrl is a prefix of the given request URL.
511
+ *
512
+ * @param {string} requestUrl - The in-flight request URL to match
513
+ * @returns {string | undefined} The matching locusUrl, or undefined if not found
514
+ */
515
+ public getLocusUrlByDatachannelUrl(requestUrl: string): string | undefined {
516
+ for (const [, connection] of this.connections) {
517
+ if (
518
+ connection.datachannelUrl &&
519
+ LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)
520
+ ) {
521
+ return connection.locusUrl;
522
+ }
523
+ }
524
+
525
+ return undefined;
526
+ }
527
+
528
+ /**
529
+ * Look up the sessionId associated with a datachannel request URL.
530
+ * Iterates all active LLM sessions and returns the sessionId whose
531
+ * 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 sessionId, or undefined if not found
535
+ */
536
+ public getSessionIdByDatachannelUrl(requestUrl: string): string | undefined {
537
+ for (const [sessionId, connection] of this.connections) {
538
+ if (
539
+ connection.datachannelUrl &&
540
+ LLMChannel.matchesDatachannelRequestUrl(requestUrl, connection.datachannelUrl)
541
+ ) {
542
+ return sessionId;
543
+ }
544
+ }
545
+
546
+ return undefined;
547
+ }
548
+
549
+ /**
550
+ * Matches a request URL to a stored datachannel registration URL.
551
+ * Host can differ (e.g. rewritten by hostmap interceptor), so we first
552
+ * try full URL prefix and then fall back to pathname prefix.
553
+ * @param {string} requestUrl
554
+ * @param {string} registrationUrl
555
+ * @returns {boolean}
556
+ */
557
+ public static matchesDatachannelRequestUrl(requestUrl: string, registrationUrl: string): boolean {
558
+ if (!requestUrl || !registrationUrl) {
559
+ return false;
560
+ }
561
+
562
+ if (requestUrl.startsWith(registrationUrl)) {
563
+ return true;
564
+ }
565
+
566
+ try {
567
+ const request = new URL(requestUrl);
568
+ const registration = new URL(registrationUrl);
569
+
570
+ return request.pathname.startsWith(registration.pathname);
571
+ } catch (error) {
572
+ return false;
573
+ }
574
+ }
575
+
356
576
  /**
357
577
  * Returns true if data channel token is enabled, false otherwise
358
578
  * @returns {Promise<boolean>} resolves with true if data channel token is enabled