Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions apps/meteor/client/components/withErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
import type { ComponentType, ReactNode, ComponentProps } from 'react';
import React, { ComponentType, ReactNode, ComponentProps } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

function withErrorBoundary<T extends object>(Component: ComponentType<T>, fallback: ReactNode = null) {
const WrappedComponent = function (props: ComponentProps<typeof Component>) {
return (
<ErrorBoundary fallback={<>{fallback}</>}>
<Component {...props} />
</ErrorBoundary>
);
};
import { ComponentErrorFallback } from '../components/errors/ErrorFallbacks';
import { errorTrackingService } from '../services/ErrorTrackingService';

export function withErrorBoundary<T extends object>(
Component: ComponentType<T>,
fallback: ReactNode = <ComponentErrorFallback />,
scope: 'global' | 'feature' | 'component' = 'component',
) {
const WrappedComponent = (props: ComponentProps<typeof Component>) => (
<ErrorBoundary
fallback={<>{fallback}</>}
onError={(error) => {
errorTrackingService.reportError(error, {
scope,
severity: scope === 'global' ? 'critical' : 'high',
recoverable: true,
componentPath: Component.displayName || Component.name,
});
}}
>
<Component {...props} />
</ErrorBoundary>
);

WrappedComponent.displayName = `withErrorBoundary(${Component.displayName ?? Component.name ?? 'Component'})`;

return WrappedComponent;
}

export { withErrorBoundary };
37 changes: 13 additions & 24 deletions apps/meteor/client/views/admin/workspace/WorkspacePage.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import type { IWorkspaceInfo, IStats } from '@rocket.chat/core-typings';
import { Box, Button, ButtonGroup, Callout, CardGrid } from '@rocket.chat/fuselage';
import { Box, Callout, CardGrid, ButtonGroup, Button } from '@rocket.chat/fuselage';
import type { IInstance } from '@rocket.chat/rest-typings';
import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client';
import { memo } from 'react';
import React, { memo } from 'react';
import { useTranslation } from 'react-i18next';

import { useIsEnterprise } from '../../../hooks/useIsEnterprise';
import { FeatureErrorFallback } from '../../../components/errors/ErrorFallbacks';
import { withErrorBoundary } from '../../../lib/withErrorBoundary';
import DeploymentCard from './DeploymentCard/DeploymentCard';
import MessagesRoomsCard from './MessagesRoomsCard/MessagesRoomsCard';
import UsersUploadsCard from './UsersUploadsCard/UsersUploadsCard';
import VersionCard from './VersionCard/VersionCard';
import { useIsEnterprise } from '../../../hooks/useIsEnterprise';

type WorkspaceStatusPageProps = {
canViewStatistics: boolean;
Expand All @@ -31,7 +33,6 @@ const WorkspacePage = ({
onClickDownloadInfo,
}: WorkspaceStatusPageProps) => {
const { t } = useTranslation();

const { data } = useIsEnterprise();

const warningMultipleInstances = !data?.isEnterprise && !statistics?.msEnabled && statistics?.instanceCount > 1;
Expand All @@ -53,28 +54,12 @@ const WorkspacePage = ({
<PageScrollableContentWithShadow p={16}>
<Box marginBlock='none' marginInline='auto' width='full' color='default'>
{warningMultipleInstances && (
<Callout type='warning' title={t('Multiple_monolith_instances_alert')} marginBlockEnd={16}></Callout>
<Callout type='warning' title={t('Multiple_monolith_instances_alert')} mbe={16} />
)}
{alertOplogForMultipleInstances && (
<Callout
type='danger'
title={t('Error_RocketChat_requires_oplog_tailing_when_running_in_multiple_instances')}
marginBlockEnd={16}
>
<Callout type='danger' title={t('Error_Oplog_Required')} mbe={16}>
<Box withRichContent>
<p>{t('Error_RocketChat_requires_oplog_tailing_when_running_in_multiple_instances_details')}</p>
<p>
<a
rel='noopener noreferrer'
target='_blank'
href={
'https://rocket.chat/docs/installation/manual-installation/multiple-instances-to-improve-' +
'performance/#running-multiple-instances-per-host-to-improve-performance'
}
>
{t('Click_here_for_more_info')}
</a>
</p>
<p>{t('Error_RocketChat_requires_oplog_tailing_details')}</p>
</Box>
</Callout>
)}
Expand All @@ -92,4 +77,8 @@ const WorkspacePage = ({
);
};

export default memo(WorkspacePage);
export default withErrorBoundary(
memo(WorkspacePage),
<FeatureErrorFallback resetErrorBoundary={() => window.location.reload()} />,
'feature'
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Box, Option, Icon, States, StatesIcon, StatesTitle } from '@rocket.chat/fuselage';
import React from 'react';
import { useTranslation } from 'react-i18next';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the project's standard useTranslation hook.

The component imports useTranslation from react-i18next, but the project uses its own implementation from @rocket.chat/ui-contexts. This inconsistency could cause i18n to fail or use an incorrect translation context.

🔧 Proposed fix
-import { useTranslation } from 'react-i18next';
+import { useTranslation } from '@rocket.chat/ui-contexts';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useTranslation } from 'react-i18next';
import { useTranslation } from '@rocket.chat/ui-contexts';
🤖 Prompt for AI Agents
In @apps/meteor/client/views/room/contextualBar/OTR/MCP/MCPToolList.tsx at line
3, Replace the direct react-i18next import with the project's translation hook:
in MCPToolList.tsx stop importing useTranslation from 'react-i18next' and import
the useTranslation provided by the project (from '@rocket.chat/ui-contexts') so
the MCPToolList component uses the app's i18n context; update any references to
useTranslation in that file accordingly.


// FIX: Define proper interface to replace 'any[]'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove FIX comments per coding guidelines.

The coding guidelines specify to avoid code comments in the implementation. The FIX comment on line 5 is also stale, referencing any[] that no longer exists in the code.

♻️ Proposed refactor
-// FIX: Define proper interface to replace 'any[]'
 interface MCPTool {
 	name: string;
 	description: string;
 }
-	// FIX: Defensive validation - filter out malformed data
 	const validTools = tools.filter((tool) => tool && typeof tool.name === 'string' && tool.name.trim() !== '');
-			// FIX: Use a unique key combining name and index for stability
 			<Option key={`${tool.name}-${index}`}>
 				<Box mi='x8'>
-					{/* FIX: Use nullish coalescing for display safety */}
 					<Box fontScale='p2m'>{tool.name ?? t('Unknown_Tool')}</Box>

Also applies to: 18-18, 33-33, 37-37

🤖 Prompt for AI Agents
In @apps/meteor/client/views/room/contextualBar/OTR/MCP/MCPToolList.tsx at line
5, The file contains stale "FIX" inline comments (e.g., in MCPToolList.tsx near
the MCPToolList component) that violate coding guidelines and reference an old
any[] issue; remove all such FIX comments (the ones noted around lines 5, 18,
33, 37) from the source so the implementation contains no FIXME/FIX comments
while leaving the surrounding code and type definitions (props, interfaces, and
any existing types used by MCPToolList and its helper functions) unchanged.

interface MCPTool {
name: string;
description: string;
}

interface MCPToolListProps {
tools: MCPTool[];
}

export const MCPToolList = ({ tools }: MCPToolListProps) => {
const { t } = useTranslation();

// FIX: Defensive validation - filter out malformed data
const validTools = tools.filter((tool) => tool && typeof tool.name === 'string' && tool.name.trim() !== '');

if (validTools.length === 0) {
return (
<States inline>
<StatesIcon name='ai' />
<StatesTitle>{t('No_MCP_Tools_Available')}</StatesTitle>
</States>
);
}

return (
<Box>
{validTools.map((tool, index) => (
// FIX: Use a unique key combining name and index for stability
<Option key={`${tool.name}-${index}`}>
<Icon name='robot' size='x20' />
<Box mi='x8'>
{/* FIX: Use nullish coalescing for display safety */}
<Box fontScale='p2m'>{tool.name ?? t('Unknown_Tool')}</Box>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unreachable fallback code.

The validation on line 19 ensures tool.name is always a valid non-empty string. The nullish coalescing fallback t('Unknown_Tool') on line 38 is unreachable dead code.

🧹 Proposed fix
-					<Box fontScale='p2m'>{tool.name ?? t('Unknown_Tool')}</Box>
+					<Box fontScale='p2m'>{tool.name}</Box>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Box fontScale='p2m'>{tool.name ?? t('Unknown_Tool')}</Box>
<Box fontScale='p2m'>{tool.name}</Box>
🤖 Prompt for AI Agents
In @apps/meteor/client/views/room/contextualBar/OTR/MCP/MCPToolList.tsx at line
38, The nullish-coalescing fallback t('Unknown_Tool') in the Box rendering is
dead code because validation earlier guarantees tool.name is a valid non-empty
string; remove the unreachable fallback and render tool.name directly (replace
"tool.name ?? t('Unknown_Tool')" with "tool.name") in MCPToolList.tsx to keep
the JSX concise and avoid misleading code paths.

<Box fontScale='c1' color='hint'>
{tool.description ?? ''}
</Box>
</Box>
</Option>
))}
</Box>
);
};
43 changes: 43 additions & 0 deletions packages/core-services/src/mcp/MCPGatewayService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { MCPClient } from '@modelcontextprotocol/sdk'; // Hypothetical SDK usage

export interface MCPConfig {
serverId: string;
url: string;
enabled: boolean;
}

class MCPGatewayService {
private clients: Map<string, any> = new Map();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace any with MCPClient for type safety.

Typing the Map value as any eliminates TypeScript's type checking, allowing potential runtime errors from incorrect method calls or type mismatches.

🔧 Proposed fix
-	private clients: Map<string, any> = new Map();
+	private clients: Map<string, MCPClient> = new Map();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private clients: Map<string, any> = new Map();
private clients: Map<string, MCPClient> = new Map();
🤖 Prompt for AI Agents
In @packages/core-services/src/mcp/MCPGatewayService.ts at line 10, The clients
Map in MCPGatewayService is currently typed as Map<string, any>; change its
declaration to Map<string, MCPClient> to restore type safety, update the
initialization to new Map<string, MCPClient>(), and import or reference the
MCPClient type/interface where needed; then fix any call sites that relied on
implicit any by ensuring stored values are actual MCPClient instances or
cast/constructed appropriately (e.g., in methods that add or retrieve clients,
adjust signatures/returns to use MCPClient instead of any).


/**
* Connects to a new MCP server provided by the user/admin
*/
public async connectServer(config: MCPConfig): Promise<void> {
if (!config.enabled) return;

try {
// Initialize connection to the remote MCP server
const client = new MCPClient({ url: config.url });
await client.connect();

this.clients.set(config.serverId, client);
console.log(`[MCP] Connected to server: ${config.serverId}`);
} catch (error) {
console.error(`[MCP] Connection failed for ${config.serverId}:`, error);
}
}
Comment on lines +15 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add resource cleanup and duplicate serverId handling.

Multiple issues require attention:

  1. Resource leak: Replacing an existing client (same serverId) without disconnecting the old connection leaks resources and may leave stale connections open.
  2. No URL validation: config.url is passed directly to MCPClient without validation, risking runtime errors from malformed URLs.
  3. Silent failures: Connection failures are logged but not propagated, preventing callers from detecting or handling errors appropriately.
🔧 Proposed fix
 	public async connectServer(config: MCPConfig): Promise<void> {
 		if (!config.enabled) return;
+		
+		// Validate URL
+		try {
+			new URL(config.url);
+		} catch {
+			throw new Error(`Invalid MCP server URL: ${config.url}`);
+		}
+		
+		// Disconnect existing client if present
+		const existingClient = this.clients.get(config.serverId);
+		if (existingClient) {
+			await existingClient.disconnect?.();
+		}
 
 		try {
 			// Initialize connection to the remote MCP server
 			const client = new MCPClient({ url: config.url });
 			await client.connect();
 			
 			this.clients.set(config.serverId, client);
 			console.log(`[MCP] Connected to server: ${config.serverId}`);
 		} catch (error) {
 			console.error(`[MCP] Connection failed for ${config.serverId}:`, error);
+			throw error;
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public async connectServer(config: MCPConfig): Promise<void> {
if (!config.enabled) return;
try {
// Initialize connection to the remote MCP server
const client = new MCPClient({ url: config.url });
await client.connect();
this.clients.set(config.serverId, client);
console.log(`[MCP] Connected to server: ${config.serverId}`);
} catch (error) {
console.error(`[MCP] Connection failed for ${config.serverId}:`, error);
}
}
public async connectServer(config: MCPConfig): Promise<void> {
if (!config.enabled) return;
try {
new URL(config.url);
} catch {
throw new Error(`Invalid MCP server URL: ${config.url}`);
}
const existingClient = this.clients.get(config.serverId);
if (existingClient) {
await existingClient.disconnect?.();
}
try {
const client = new MCPClient({ url: config.url });
await client.connect();
this.clients.set(config.serverId, client);
console.log(`[MCP] Connected to server: ${config.serverId}`);
} catch (error) {
console.error(`[MCP] Connection failed for ${config.serverId}:`, error);
throw error;
}
}
🤖 Prompt for AI Agents
In @packages/core-services/src/mcp/MCPGatewayService.ts around lines 15 - 28, In
connectServer, prevent resource leaks and improve error handling by first
validating config.url (e.g., using the URL constructor) and throwing immediately
for malformed URLs; if this.clients has an existing client for config.serverId,
call its disconnect/close method (the existing MCPClient instance) and remove it
before creating a new MCPClient; attempt to connect the new MCPClient and on any
connection error ensure you clean up (disconnect/close the new client if
partially connected) and rethrow the error so callers can handle failures
instead of only logging; update references to connectServer, MCPClient,
MCPConfig, and this.clients accordingly.


/**
* Lists available tools from all connected MCP servers
*/
public async getAllTools() {
const allTools = [];
for (const client of this.clients.values()) {
const tools = await client.listTools();
allTools.push(...tools);
}
return allTools;
}
Comment on lines +33 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Handle individual client failures gracefully.

If any client.listTools() call throws, the entire method fails, preventing users from accessing tools from healthy servers. One misbehaving MCP server should not block all tool discovery.

🛡️ Proposed fix for resilient tool aggregation
 	public async getAllTools() {
 		const allTools = [];
 		for (const client of this.clients.values()) {
-			const tools = await client.listTools();
-			allTools.push(...tools);
+			try {
+				const tools = await client.listTools();
+				allTools.push(...tools);
+			} catch (error) {
+				console.error('[MCP] Failed to list tools from client:', error);
+				// Continue with other clients
+			}
 		}
 		return allTools;
 	}
🤖 Prompt for AI Agents
In @packages/core-services/src/mcp/MCPGatewayService.ts around lines 33 - 40,
getAllTools currently fails if any client.listTools() throws; update it to catch
errors per-client so one misbehaving MCP server doesn't block aggregation:
inside getAllTools iterate over this.clients.values(), call await
client.listTools() inside a try/catch, on success push results into allTools, on
error log the failure including a client-identifying symbol (e.g., client.id,
client.name or the client object) and continue to the next client, then return
the aggregated allTools as before.

}

export const mcpGatewayService = new MCPGatewayService();
Comment on lines +9 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add cleanup methods and replace console logging.

To align with the PR's error tracking infrastructure and production-grade requirements:

  1. Missing cleanup/disconnect: No method exists to disconnect individual servers or clean up all connections during shutdown, risking resource leaks in long-running processes.
  2. Console logging: Using console.log/console.error contradicts the PR's structured error tracking service mentioned in commit messages and AI summary.
♻️ Proposed additions

Add cleanup methods:

	/**
	 * Disconnects a specific MCP server
	 */
	public async disconnectServer(serverId: string): Promise<void> {
		const client = this.clients.get(serverId);
		if (client) {
			try {
				await client.disconnect?.();
				this.clients.delete(serverId);
			} catch (error) {
				console.error(`[MCP] Failed to disconnect ${serverId}:`, error);
			}
		}
	}

	/**
	 * Disconnects all MCP servers (cleanup on shutdown)
	 */
	public async disconnectAll(): Promise<void> {
		const disconnectPromises = Array.from(this.clients.keys()).map(
			serverId => this.disconnectServer(serverId)
		);
		await Promise.allSettled(disconnectPromises);
	}

Replace console logging with your error tracking service (refer to the ErrorTrackingService mentioned in the PR context).

🤖 Prompt for AI Agents
In @packages/core-services/src/mcp/MCPGatewayService.ts around lines 9 - 43, The
MCPGatewayService is missing cleanup/disconnect methods and uses console
logging; add two methods on the class—public async disconnectServer(serverId:
string): Promise<void> which looks up this.clients.get(serverId), calls await
client.disconnect?.(), deletes the client from this.clients and reports failures
via the project's ErrorTrackingService or structured logger (not console.error),
and public async disconnectAll(): Promise<void> which iterates
this.clients.keys() and awaits Promise.allSettled(keys.map(id =>
this.disconnectServer(id))); also replace console.log and console.error inside
connectServer with the centralized ErrorTrackingService/logger calls (include
contextual messages and error details) to align with production error tracking.

Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import * as UiKit from '@rocket.chat/ui-kit';
import type { ReactElement } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

import { FuselageSurfaceRenderer, renderTextObject } from './FuselageSurfaceRenderer';
import VideoConferenceBlock from '../blocks/VideoConferenceBlock';
import { AppIdProvider } from '../contexts/AppIdContext';
import { ComponentErrorFallback } from '../components/errors/ErrorFallbacks';
import { errorTrackingService } from '../services/ErrorTrackingService';

export class FuselageMessageSurfaceRenderer extends FuselageSurfaceRenderer {
public constructor() {
super(['actions', 'context', 'divider', 'image', 'input', 'section', 'preview', 'video_conf', 'info_card']);
}
public constructor() {
super(['actions', 'context', 'divider', 'image', 'input', 'section', 'preview', 'video_conf', 'info_card']);
}

override plain_text = renderTextObject;
override plain_text = renderTextObject;

override mrkdwn = renderTextObject;
override mrkdwn = renderTextObject;

video_conf(block: UiKit.VideoConferenceBlock, context: UiKit.BlockContext, index: number): ReactElement | null {
if (context === UiKit.BlockContext.BLOCK) {
return (
<AppIdProvider key={index} appId={block.appId}>
<VideoConferenceBlock block={block} context={context} index={index} surfaceRenderer={this} />
</AppIdProvider>
);
}
video_conf(block: UiKit.VideoConferenceBlock, context: UiKit.BlockContext, index: number): ReactElement | null {
if (context === UiKit.BlockContext.BLOCK) {
return (

<ErrorBoundary
key={index}
fallback={<ComponentErrorFallback />}
onError={(error) => errorTrackingService.reportError(error, {
scope: 'component',
severity: 'medium',
recoverable: true,
componentPath: 'FuselageMessageSurfaceRenderer.video_conf'
})}
>
<AppIdProvider appId={block.appId}>
<VideoConferenceBlock block={block} context={context} index={index} surfaceRenderer={this} />
</AppIdProvider>
</ErrorBoundary>
);
}

return null;
}
return null;
}
}
40 changes: 27 additions & 13 deletions packages/livechat/src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import i18next from 'i18next';
import { Component } from 'preact';
import Router, { route } from 'preact-router';
import { withTranslation } from 'react-i18next';
import { ErrorBoundary } from 'react-error-boundary';
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The react-error-boundary package is imported but not declared in livechat's package.json dependencies. Additionally, this package uses Preact, not React, so react-error-boundary may not be compatible. Consider using a Preact-compatible error boundary implementation or configure preact/compat aliasing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/livechat/src/components/App/App.tsx, line 6:

<comment>The `react-error-boundary` package is imported but not declared in livechat's package.json dependencies. Additionally, this package uses Preact, not React, so `react-error-boundary` may not be compatible. Consider using a Preact-compatible error boundary implementation or configure preact/compat aliasing.</comment>

<file context>
@@ -3,6 +3,7 @@ import i18next from 'i18next';
 import { Component } from 'preact';
 import Router, { route } from 'preact-router';
 import { withTranslation } from 'react-i18next';
+import { ErrorBoundary } from 'react-error-boundary';
 
 import type { Department } from '../../definitions/departments';
</file context>
Fix with Cubic

Comment on lines 3 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check package.json for the livechat package to see alias configuration
echo "=== Checking livechat package.json ==="
cat packages/livechat/package.json

echo -e "\n=== Looking for preact/compat configuration ==="
# Search for preact/compat references
rg -n "preact/compat" packages/livechat/ --type json --type js --type ts

echo -e "\n=== Checking for react alias configuration ==="
# Look for alias config in package.json or build files
rg -n "alias.*react|\"react\":" packages/livechat/ --type json -A2 -B2

echo -e "\n=== Check webpack or build configuration ==="
find packages/livechat -name "webpack*.js" -o -name "vite.config.*" -o -name "rollup.config.*" -o -name "tsconfig.json" | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 12601


🏁 Script executed:

#!/bin/bash
# Check the root package.json for workspace configuration related to livechat
echo "=== Root monorepo config (package.json extract) ==="
rg -n "preact|alias" package.json -A2 -B2

echo -e "\n=== Check if react-error-boundary is installed ==="
rg -n "react-error-boundary" packages/livechat/package.json

echo -e "\n=== Look for any compatibility setup in livechat ==="
find packages/livechat -name ".babelrc*" -o -name "jest.config.*" | xargs cat 2>/dev/null

Repository: RocketChat/Rocket.Chat

Length of output: 223


🏁 Script executed:

#!/bin/bash
# Check the actual imports in App.tsx
cat -n packages/livechat/src/components/App/App.tsx | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 1133


🏁 Script executed:

#!/bin/bash
# Check if react-error-boundary appears anywhere in dependencies across the monorepo
rg "react-error-boundary" --type json | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 194


🏁 Script executed:

#!/bin/bash
# Check if react-error-boundary is a transitive dependency from other packages in livechat
echo "=== Checking if react-error-boundary might be transitive ==="
# Check react-i18next and other react packages in livechat
rg "react-i18next|react-hook-form" packages/livechat/package.json -A1 -B1

echo -e "\n=== Check package-lock or yarn.lock for react-error-boundary ==="
# Look for any reference in lock files
find . -maxdepth 1 -name "*lock*" -o -name "*yarn*" | head -5

echo -e "\n=== Verify if the build actually works ==="
# Check if there are any build errors or warnings in CI config related to this
find . -name "*.yml" -o -name "*.yaml" | xargs grep -l "livechat" 2>/dev/null | head -3

Repository: RocketChat/Rocket.Chat

Length of output: 395


🏁 Script executed:

#!/bin/bash
# Simpler check: look at what react-i18next depends on
echo "=== Dependencies of packages that might pull in react-error-boundary ==="
cat packages/livechat/package.json | grep -A1 '"react-i18next"'
# Check if there's any documentation about the missing dependency
grep -r "react-error-boundary" packages/livechat --include="*.md" --include="*.ts" --include="*.tsx" --include="*.js" | grep -v node_modules | head -10

Repository: RocketChat/Rocket.Chat

Length of output: 302


react-error-boundary is not installed in this package.

The import on line 6 references react-error-boundary, but this package is missing from packages/livechat/package.json entirely. While preact/compat is properly configured in webpack and TypeScript, it cannot resolve a missing package. Either add react-error-boundary to dependencies or use a Preact-compatible alternative.

🤖 Prompt for AI Agents
In @packages/livechat/src/components/App/App.tsx around lines 3 - 6, The file
imports ErrorBoundary from 'react-error-boundary' in App.tsx but the package is
not listed in packages/livechat/package.json; either add "react-error-boundary"
to the livechat package dependencies and run the package manager install, or
replace the usage/import of ErrorBoundary in App.tsx with a Preact-compatible
alternative (e.g., implement a small Preact ErrorBoundary component or use a
preact-compatible library), updating the import and any usage sites accordingly
so the module resolution succeeds.


import type { Department } from '../../definitions/departments';
import { setInitCookies } from '../../helpers/cookies';
Expand All @@ -24,6 +25,10 @@ import SwitchDepartment from '../../routes/SwitchDepartment';
import TriggerMessage from '../../routes/TriggerMessage';
import type { Dispatch, StoreState } from '../../store';
import { ScreenProvider } from '../Screen/ScreenProvider';
import { GlobalErrorFallback } from '../../../../ui-client/src/components/errors/ErrorFallbacks';
import { errorTrackingService } from '../../../../ui-client/src/services/ErrorTrackingService';
import { ScreenProvider } from '../Screen/ScreenProvider';
import { GlobalErrorFallback, errorTrackingService } from '@rocket.chat/ui-client';

type AppProps = {
config: {
Expand Down Expand Up @@ -164,7 +169,6 @@ export class App extends Component<AppProps, AppState> {
}

protected async initialize() {
// TODO: split these behaviors into composable components
await Connection.init();
CustomFields.init();
userPresence.init();
Expand Down Expand Up @@ -203,19 +207,29 @@ export class App extends Component<AppProps, AppState> {
}

return (
<ScreenProvider>
<Router history={history} onChange={this.handleRoute}>
<ChatConnector path='/' default />
<ChatFinished path='/chat-finished' />
<GDPRAgreement path='/gdpr' />
<LeaveMessage path='/leave-message' />
<Register path='/register' />
<SwitchDepartment path='/switch-department' />
<TriggerMessage path='/trigger-messages' />
</Router>
</ScreenProvider>
<ErrorBoundary
FallbackComponent={GlobalErrorFallback}
onError={(error) => errorTrackingService.reportError(error, {
scope: 'global',
severity: 'critical',
recoverable: false,
componentPath: 'LivechatApp'
})}
>
<ScreenProvider>
<Router history={history} onChange={this.handleRoute}>
<ChatConnector path='/' default />
<ChatFinished path='/chat-finished' />
<GDPRAgreement path='/gdpr' />
<LeaveMessage path='/leave-message' />
<Register path='/register' />
<SwitchDepartment path='/switch-department' />
<TriggerMessage path='/trigger-messages' />
</Router>
</ScreenProvider>
</ErrorBoundary>
);
};
}

export default withTranslation()(App);
export default withTranslation()(App);
9 changes: 6 additions & 3 deletions packages/ui-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/ui-client",
"version": "26.0.0-rc.1",
"name": "@rocket.chat/livechat",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Critical: This package is being renamed from @rocket.chat/ui-client to @rocket.chat/livechat, but @rocket.chat/livechat already exists in packages/livechat/. This creates a name collision that will break workspace resolution. This change also appears unrelated to the PR's stated purpose (MCP Gateway integration) and may be accidental.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui-client/package.json, line 2:

<comment>Critical: This package is being renamed from `@rocket.chat/ui-client` to `@rocket.chat/livechat`, but `@rocket.chat/livechat` already exists in `packages/livechat/`. This creates a name collision that will break workspace resolution. This change also appears unrelated to the PR's stated purpose (MCP Gateway integration) and may be accidental.</comment>

<file context>
@@ -1,6 +1,6 @@
 {
-	"name": "@rocket.chat/ui-client",
-	"version": "26.0.0-rc.1",
+	"name": "@rocket.chat/livechat",
+	"version": "1.0.0",
 	"private": true,
</file context>
Suggested change
"name": "@rocket.chat/livechat",
"name": "@rocket.chat/ui-client",
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Critical: Package name incorrectly changed from @rocket.chat/ui-client to @rocket.chat/livechat. This name is already used by packages/livechat/package.json, creating a duplicate. This appears to be an accidental merge conflict or copy-paste error that will break the monorepo.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui-client/package.json, line 2:

<comment>Critical: Package name incorrectly changed from `@rocket.chat/ui-client` to `@rocket.chat/livechat`. This name is already used by `packages/livechat/package.json`, creating a duplicate. This appears to be an accidental merge conflict or copy-paste error that will break the monorepo.</comment>

<file context>
@@ -1,6 +1,6 @@
 {
-	"name": "@rocket.chat/ui-client",
-	"version": "26.0.0-rc.1",
+	"name": "@rocket.chat/livechat",
+	"version": "1.0.0",
 	"private": true,
</file context>
Suggested change
"name": "@rocket.chat/livechat",
"name": "@rocket.chat/ui-client",
Fix with Cubic

"version": "1.0.0",
Comment on lines +2 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for all references to the old package name @rocket.chat/ui-client

echo "=== Searching for import statements referencing @rocket.chat/ui-client ==="
rg -n '@rocket\.chat/ui-client' --type ts --type tsx --type js --type jsx -g '!node_modules' -g '!dist' -g '!*.lock' 2>/dev/null | head -50

echo ""
echo "=== Searching in all package.json files for @rocket.chat/ui-client ==="
fd -e json 'package.json' -x grep -H '@rocket\.chat/ui-client' {} \; | grep -v node_modules | head -30

echo ""
echo "=== Checking current directory structure ==="
ls -la packages/ | grep -E "(ui-client|livechat)"

echo ""
echo "=== Checking for references to @rocket.chat/livechat ==="
rg -n '@rocket\.chat/livechat' --type ts --type tsx --type js --type jsx -g '!node_modules' -g '!dist' 2>/dev/null | head -30

echo ""
echo "=== List all package.json files in packages directory ==="
fd 'package.json' packages/ | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 1690


🏁 Script executed:

#!/bin/bash
echo "=== packages/ui-client/package.json content ==="
cat packages/ui-client/package.json

echo ""
echo "=== packages/livechat/package.json content ==="
cat packages/livechat/package.json

Repository: RocketChat/Rocket.Chat

Length of output: 6840


Critical: Duplicate package name and broken dependencies prevent build.

The package in packages/ui-client is being renamed from @rocket.chat/ui-client to @rocket.chat/livechat, but this creates two critical issues:

  1. Duplicate package name conflict: Both packages/ui-client (v1.0.0) and packages/livechat (v2.0.0-rc.1) now export @rocket.chat/livechat. This is invalid in a monorepo and will cause resolution failures.

  2. Broken dependencies: The package depends on @rocket.chat/ui-client ("workspace:~") which no longer exists (renamed to @rocket.chat/livechat). Additionally, 4+ packages still depend on the old @rocket.chat/ui-client name and have not been updated:

    • packages/ui-voip
    • packages/web-ui-registration
    • packages/gazzodown
    • apps/meteor

All references must be updated consistently, and the duplicate package name must be resolved before this can merge.

🤖 Prompt for AI Agents
In @packages/ui-client/package.json around lines 2 - 3, packages/ui-client's
package.json was renamed to "@rocket.chat/livechat", creating a duplicate
package name clash with packages/livechat and leaving dependencies pointing to
the old name; restore a single authoritative package name and update dependent
packages accordingly: either revert packages/ui-client's "name" to
"@rocket.chat/ui-client" (or remove/merge that package if it should be
consolidated into packages/livechat), then update all package.json dependency
entries that reference "@rocket.chat/ui-client" (including in packages/ui-voip,
packages/web-ui-registration, packages/gazzodown, and apps/meteor) to the final
chosen name ("@rocket.chat/livechat" if you consolidated, or
"@rocket.chat/ui-client" if you kept them separate) and ensure workspace:
versions match the package version in the monorepo; finally remove/resolve the
duplicate export by keeping only one package with the chosen name and run the
package manager's workspace resolution check to confirm no remaining conflicts.

"private": true,
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
Expand All @@ -19,7 +19,9 @@
},
"dependencies": {
"@rocket.chat/onboarding-ui": "~0.36.0",
"dompurify": "~3.2.7"
"@rocket.chat/ui-client": "workspace:~",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Adding @rocket.chat/ui-client as a workspace dependency is problematic since this same file's name is being changed from @rocket.chat/ui-client. This creates an unresolvable dependency. If the name change is reverted, this dependency line should also be removed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui-client/package.json, line 22:

<comment>Adding `@rocket.chat/ui-client` as a workspace dependency is problematic since this same file's name is being changed from `@rocket.chat/ui-client`. This creates an unresolvable dependency. If the name change is reverted, this dependency line should also be removed.</comment>

<file context>
@@ -19,7 +19,9 @@
 	"dependencies": {
 		"@rocket.chat/onboarding-ui": "~0.36.0",
-		"dompurify": "~3.2.7"
+		"@rocket.chat/ui-client": "workspace:~",
+		"dompurify": "~3.2.7",
+		"react-error-boundary": "^5.0.0"
</file context>
Fix with Cubic

"dompurify": "~3.2.7",
"react-error-boundary": "^5.0.0"
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

react-error-boundary npm latest version 2025 security vulnerabilities

💡 Result:

Short answer (as of Jan 8, 2026): the react-error-boundary package latest published version is 6.0.1, and there are no known direct security vulnerabilities reported for the package itself. [1][2]

Sources:

  • Snyk package/security page for react-error-boundary (shows latest 6.0.1, no direct vulnerabilities). [1]
  • jsDelivr / package metadata showing version 6.0.1. [2]

If you want, I can list its release date, scan it for transitive (dependency) issues, or check npm advisories/CVE databases for further confirmation.


🌐 Web query:

dompurify npm latest version 2025 security vulnerabilities

💡 Result:

Short answer

  • Latest npm release (as of Jan 8, 2026): DOMPurify v3.2.4. [1]

Known security issues (important ones from 2024–2025)

  • CVE-2024-45801 — prototype-pollution / nesting bypass (fixed in 2.5.4 and 3.1.3). [2]
  • CVE-2024-47875 — nesting-based mutation XSS (mXSS) (fixed in 2.5.0 and 3.1.3). [3]
  • CVE-2025-26791 — incorrect template-literal regex when SAFE_FOR_TEMPLATES=true leading to mXSS (fixed in 3.2.4). [4]

Recommendation

  • Upgrade to v3.2.4 (or newer) and audit usages of SAFE_FOR_TEMPLATES; follow project/security advisories for patches. [1][4]

Sources
[1] npm package / DOMPurify release info.
[2] NVD — CVE-2024-45801.
[3] NVD — CVE-2024-47875.
[4] CVE-2025-26791 advisory / DOMPurify 3.2.4 release.


🏁 Script executed:

#!/bin/bash
# Check npm registry data for both packages to get version info and vulnerability status
npm view react-error-boundary@5.0.0 --json 2>/dev/null | head -50
npm view dompurify@3.2.7 --json 2>/dev/null | head -50

Repository: RocketChat/Rocket.Chat

Length of output: 1506


Consider updating to more current versions.

The versions specified are functional but outdated:

  • react-error-boundary@5.0.0 is 1–2 major versions behind the latest available (6.0.2). No known security vulnerabilities in 5.0.0 itself.
  • dompurify@3.2.7 is slightly behind the latest (3.3.1). The version includes fixes for critical CVEs like CVE-2025-26791 (mXSS with SAFE_FOR_TEMPLATES), so it is secure, but updating to 3.3.1 would be prudent for long-term maintainability.
🤖 Prompt for AI Agents
In @packages/ui-client/package.json around lines 23 - 24, The package.json
dependencies for the ui-client list older versions of dompurify and
react-error-boundary; update "dompurify" from "~3.2.7" to "3.3.1" (or a
compatible ^3.3.1 range) and "react-error-boundary" from "^5.0.0" to the current
stable (e.g., "^6.0.2") in the dependencies section, then run your package
manager (npm/yarn/pnpm) to refresh lockfiles and test the app to ensure no
breaking changes from the upgraded versions affect components that import
dompurify or the ErrorBoundary from react-error-boundary.

},
"devDependencies": {
"@react-aria/toolbar": "^3.0.0-nightly.5042",
Expand Down Expand Up @@ -54,6 +56,7 @@
"jest": "~30.2.0",
"overlayscrollbars": "^2.11.4",
"overlayscrollbars-react": "^0.5.6",
"preact": "^10.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for preact usage in the codebase

echo "=== Searching for preact imports ==="
rg -n "from ['\"]preact" packages/ui-client/ -g '!node_modules' -g '!dist' 2>/dev/null || echo "No matches found"

echo ""
echo "=== Searching for preact/compat usage ==="
rg -n "preact/compat" packages/ui-client/ -g '!node_modules' -g '!dist' 2>/dev/null || echo "No matches found"

echo ""
echo "=== Searching for preact in require statements ==="
rg -n "require.*preact" packages/ui-client/ -g '!node_modules' -g '!dist' 2>/dev/null || echo "No matches found"

echo ""
echo "=== Checking package.json for preact references ==="
cat packages/ui-client/package.json | grep -i preact || echo "No preact references in package.json"

echo ""
echo "=== Checking jest/webpack/vite configs ==="
fd -t f \( -name 'jest.config.*' -o -name 'webpack.config.*' -o -name 'vite.config.*' \) packages/ui-client/ 2>/dev/null | head -5 | xargs -I {} sh -c 'echo "File: {}"; grep -i preact {} 2>/dev/null || echo "  (no preact references)"'

Repository: RocketChat/Rocket.Chat

Length of output: 368


Remove the unused preact devDependency.

The preact dependency is not imported or used anywhere in the codebase and is not referenced in any build or test configurations. It should be removed from package.json.

🤖 Prompt for AI Agents
In @packages/ui-client/package.json at line 59, The package.json contains an
unused devDependency "preact"; remove the "preact" entry from devDependencies in
package.json, run the project package manager to update the lockfile (npm
install / yarn install / pnpm install as appropriate), and verify there are no
imports or build/test references to "preact" (grep for "preact" or search
IDE-wide) before committing the change.

"re-resizable": "^6.10.1",
"react": "~18.3.1",
"react-dom": "~18.3.1",
Expand Down
Loading