diff --git a/apps/meteor/app/apps/server/bridges/activation.ts b/apps/meteor/app/apps/server/bridges/activation.ts index 72a5b882b18ab..dc5a0f57e0035 100644 --- a/apps/meteor/app/apps/server/bridges/activation.ts +++ b/apps/meteor/app/apps/server/bridges/activation.ts @@ -1,13 +1,11 @@ -import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; +import type { IAppServerOrchestrator, AppStatus } from '@rocket.chat/apps'; import type { ProxiedApp } from '@rocket.chat/apps-engine/server/ProxiedApp'; import { AppActivationBridge as ActivationBridge } from '@rocket.chat/apps-engine/server/bridges/AppActivationBridge'; import { Users } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppActivationBridge extends ActivationBridge { // eslint-disable-next-line no-empty-function - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/api.ts b/apps/meteor/app/apps/server/bridges/api.ts index a5767f11b9771..46bb70e3339a3 100644 --- a/apps/meteor/app/apps/server/bridges/api.ts +++ b/apps/meteor/app/apps/server/bridges/api.ts @@ -1,3 +1,4 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { RequestMethod } from '@rocket.chat/apps-engine/definition/accessors'; import type { IApiRequest, IApiEndpoint, IApi } from '@rocket.chat/apps-engine/definition/api'; import { ApiBridge } from '@rocket.chat/apps-engine/server/bridges/ApiBridge'; @@ -7,7 +8,6 @@ import express from 'express'; import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { authenticationMiddleware } from '../../../api/server/middlewares/authentication'; const apiServer = express(); @@ -24,8 +24,7 @@ interface IRequestWithPrivateHash extends Request { export class AppApisBridge extends ApiBridge { appRouters: Map; - // eslint-disable-next-line no-empty-function - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); this.appRouters = new Map(); diff --git a/apps/meteor/app/apps/server/bridges/cloud.ts b/apps/meteor/app/apps/server/bridges/cloud.ts index a0675c115f01e..30ca897240f81 100644 --- a/apps/meteor/app/apps/server/bridges/cloud.ts +++ b/apps/meteor/app/apps/server/bridges/cloud.ts @@ -1,11 +1,11 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IWorkspaceToken } from '@rocket.chat/apps-engine/definition/cloud/IWorkspaceToken'; import { CloudWorkspaceBridge } from '@rocket.chat/apps-engine/server/bridges/CloudWorkspaceBridge'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { getWorkspaceAccessTokenWithScope } from '../../../cloud/server'; export class AppCloudBridge extends CloudWorkspaceBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/commands.ts b/apps/meteor/app/apps/server/bridges/commands.ts index ee7e73e16eb5f..5e018c51de897 100644 --- a/apps/meteor/app/apps/server/bridges/commands.ts +++ b/apps/meteor/app/apps/server/bridges/commands.ts @@ -1,3 +1,4 @@ +import type { IAppServerOrchestrator, IAppsRoom, IAppsUser } from '@rocket.chat/apps'; import type { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem } from '@rocket.chat/apps-engine/definition/slashcommands'; import { SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { CommandBridge } from '@rocket.chat/apps-engine/server/bridges/CommandBridge'; @@ -5,14 +6,13 @@ import type { IMessage, RequiredField, SlashCommand, SlashCommandCallbackParams import { Meteor } from 'meteor/meteor'; import { Utilities } from '../../../../ee/lib/misc/Utilities'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { parseParameters } from '../../../../lib/utils/parseParameters'; import { slashCommands } from '../../../utils/server/slashCommand'; export class AppCommandsBridge extends CommandBridge { disabledCommands: Map; - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); this.disabledCommands = new Map(); } @@ -44,7 +44,7 @@ export class AppCommandsBridge extends CommandBridge { slashCommands.commands[cmd] = this.disabledCommands.get(cmd) as (typeof slashCommands.commands)[string]; this.disabledCommands.delete(cmd); - this.orch.getNotifier().commandUpdated(cmd); + void this.orch.getNotifier().commandUpdated(cmd); } protected async disableCommand(command: string, appId: string): Promise { @@ -69,7 +69,7 @@ export class AppCommandsBridge extends CommandBridge { this.disabledCommands.set(cmd, commandObj); delete slashCommands.commands[cmd]; - this.orch.getNotifier().commandDisabled(cmd); + void this.orch.getNotifier().commandDisabled(cmd); } // command: { command, paramsExample, i18nDescription, executor: function } @@ -95,7 +95,7 @@ export class AppCommandsBridge extends CommandBridge { ) as (typeof slashCommands.commands)[string]['previewCallback']; slashCommands.commands[cmd] = item; - this.orch.getNotifier().commandUpdated(cmd); + void this.orch.getNotifier().commandUpdated(cmd); } protected async registerCommand(command: ISlashCommand, appId: string): Promise { @@ -118,7 +118,7 @@ export class AppCommandsBridge extends CommandBridge { } as SlashCommand; slashCommands.commands[command.command.toLowerCase()] = item; - this.orch.getNotifier().commandAdded(command.command.toLowerCase()); + void this.orch.getNotifier().commandAdded(command.command.toLowerCase()); } protected async unregisterCommand(command: string, appId: string): Promise { @@ -132,7 +132,7 @@ export class AppCommandsBridge extends CommandBridge { this.disabledCommands.delete(cmd); delete slashCommands.commands[cmd]; - this.orch.getNotifier().commandRemoved(cmd); + void this.orch.getNotifier().commandRemoved(cmd); } private _verifyCommand(command: ISlashCommand): void { @@ -162,14 +162,15 @@ export class AppCommandsBridge extends CommandBridge { } private async _appCommandExecutor({ command, message, params, triggerId, userId }: SlashCommandCallbackParams): Promise { - const user = await this.orch.getConverters()?.get('users').convertById(userId); - const room = await this.orch.getConverters()?.get('rooms').convertById(message.rid); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const user: IAppsUser | undefined = await this.orch.getConverters()?.get('users').convertById(userId); + const room: IAppsRoom | undefined = await this.orch.getConverters()?.get('rooms').convertById(message.rid); const threadId = message.tmid; const parameters = parseParameters(params); const context = new SlashCommandContext( - Object.freeze(user), - Object.freeze(room), + Object.freeze(user as IAppsUser), + Object.freeze(room as IAppsRoom), Object.freeze(parameters) as string[], threadId, triggerId, @@ -183,12 +184,19 @@ export class AppCommandsBridge extends CommandBridge { parameters: any, message: RequiredField, 'rid'>, ): Promise { - const user = await this.orch.getConverters()?.get('users').convertById(Meteor.userId()); - const room = await this.orch.getConverters()?.get('rooms').convertById(message.rid); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const uid = Meteor.userId() as string; + const user: IAppsUser | undefined = await this.orch.getConverters()?.get('users').convertById(uid); + const room: IAppsRoom | undefined = await this.orch.getConverters()?.get('rooms').convertById(message.rid); const threadId = message.tmid; const params = parseParameters(parameters); - const context = new SlashCommandContext(Object.freeze(user), Object.freeze(room), Object.freeze(params) as string[], threadId); + const context = new SlashCommandContext( + Object.freeze(user as IAppsUser), + Object.freeze(room as IAppsRoom), + Object.freeze(params) as string[], + threadId, + ); return this.orch.getManager()?.getCommandManager().getPreviews(command, context); } @@ -199,14 +207,16 @@ export class AppCommandsBridge extends CommandBridge { preview: ISlashCommandPreviewItem, triggerId: string, ): Promise { - const user = await this.orch.getConverters()?.get('users').convertById(Meteor.userId()); - const room = await this.orch.getConverters()?.get('rooms').convertById(message.rid); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const uid = Meteor.userId() as string; + const user: IAppsUser | undefined = await this.orch.getConverters()?.get('users').convertById(uid); + const room: IAppsRoom | undefined = await this.orch.getConverters()?.get('rooms').convertById(message.rid); const threadId = message.tmid; const params = parseParameters(parameters); const context = new SlashCommandContext( - Object.freeze(user), - Object.freeze(room), + Object.freeze(user as IAppsUser), + Object.freeze(room as IAppsRoom), Object.freeze(params) as string[], threadId, triggerId, diff --git a/apps/meteor/app/apps/server/bridges/details.ts b/apps/meteor/app/apps/server/bridges/details.ts index 50709917183a5..3930cdd451cc7 100644 --- a/apps/meteor/app/apps/server/bridges/details.ts +++ b/apps/meteor/app/apps/server/bridges/details.ts @@ -1,18 +1,19 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import { AppDetailChangesBridge as DetailChangesBridge } from '@rocket.chat/apps-engine/server/bridges/AppDetailChangesBridge'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppDetailChangesBridge extends DetailChangesBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } protected onAppSettingsChange(appId: string, setting: ISetting): void { + const logFailure = () => console.warn('failed to notify about the setting change.', appId); + try { - this.orch.getNotifier().appSettingsChange(appId, setting); + this.orch.getNotifier().appSettingsChange(appId, setting).catch(logFailure); } catch (e) { - console.warn('failed to notify about the setting change.', appId); + logFailure(); } } } diff --git a/apps/meteor/app/apps/server/bridges/environmental.ts b/apps/meteor/app/apps/server/bridges/environmental.ts index 43b34674e95fc..705a27186dee7 100644 --- a/apps/meteor/app/apps/server/bridges/environmental.ts +++ b/apps/meteor/app/apps/server/bridges/environmental.ts @@ -1,11 +1,10 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import { EnvironmentalVariableBridge } from '@rocket.chat/apps-engine/server/bridges/EnvironmentalVariableBridge'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppEnvironmentalVariableBridge extends EnvironmentalVariableBridge { allowed: Array; - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); this.allowed = ['NODE_ENV', 'ROOT_URL', 'INSTANCE_IP']; } diff --git a/apps/meteor/app/apps/server/bridges/http.ts b/apps/meteor/app/apps/server/bridges/http.ts index a4b09e848c90f..1535a18823c54 100644 --- a/apps/meteor/app/apps/server/bridges/http.ts +++ b/apps/meteor/app/apps/server/bridges/http.ts @@ -1,10 +1,9 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors'; import type { IHttpBridgeRequestInfo } from '@rocket.chat/apps-engine/server/bridges'; import { HttpBridge } from '@rocket.chat/apps-engine/server/bridges/HttpBridge'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - const isGetOrHead = (method: string): boolean => ['GET', 'HEAD'].includes(method.toUpperCase()); // Previously, there was no timeout for HTTP requests. @@ -13,7 +12,7 @@ const isGetOrHead = (method: string): boolean => ['GET', 'HEAD'].includes(method const DEFAULT_TIMEOUT = 3 * 60 * 1000; export class AppHttpBridge extends HttpBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/internal.ts b/apps/meteor/app/apps/server/bridges/internal.ts index b41ffbb2889eb..c5cd9a3f1a601 100644 --- a/apps/meteor/app/apps/server/bridges/internal.ts +++ b/apps/meteor/app/apps/server/bridges/internal.ts @@ -1,14 +1,13 @@ -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; +import type { IAppServerOrchestrator, IAppsSetting } from '@rocket.chat/apps'; import { InternalBridge } from '@rocket.chat/apps-engine/server/bridges/InternalBridge'; -import type { ISubscription } from '@rocket.chat/core-typings'; +import type { ISetting, ISubscription } from '@rocket.chat/core-typings'; import { Settings, Subscriptions } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { isTruthy } from '../../../../lib/isTruthy'; import { deasyncPromise } from '../../../../server/deasync/deasync'; export class AppInternalBridge extends InternalBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } @@ -37,9 +36,13 @@ export class AppInternalBridge extends InternalBridge { return records.map((s: ISubscription) => s.u.username).filter(isTruthy); } - protected async getWorkspacePublicKey(): Promise { - const publicKeySetting = await Settings.findOneById('Cloud_Workspace_PublicKey'); + protected async getWorkspacePublicKey(): Promise { + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const publicKeySetting: ISetting | null = await Settings.findOneById('Cloud_Workspace_PublicKey'); - return this.orch.getConverters()?.get('settings').convertToApp(publicKeySetting); + return this.orch + .getConverters() + ?.get('settings') + .convertToApp(publicKeySetting as ISetting); } } diff --git a/apps/meteor/app/apps/server/bridges/livechat.ts b/apps/meteor/app/apps/server/bridges/livechat.ts index 2c5eaa841cdd8..bf175d1d14267 100644 --- a/apps/meteor/app/apps/server/bridges/livechat.ts +++ b/apps/meteor/app/apps/server/bridges/livechat.ts @@ -1,28 +1,22 @@ +import type { IAppServerOrchestrator, IAppsLivechatMessage } from '@rocket.chat/apps'; import type { IExtraRoomParams } from '@rocket.chat/apps-engine/definition/accessors/ILivechatCreator'; -import type { - ILivechatMessage, - IVisitor, - ILivechatRoom, - ILivechatTransferData, - IDepartment, -} from '@rocket.chat/apps-engine/definition/livechat'; +import type { IVisitor, ILivechatRoom, ILivechatTransferData, IDepartment } from '@rocket.chat/apps-engine/definition/livechat'; import type { IMessage as IAppsEngineMesage } from '@rocket.chat/apps-engine/definition/messages'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import { LivechatBridge } from '@rocket.chat/apps-engine/server/bridges/LivechatBridge'; -import type { SelectedAgent } from '@rocket.chat/core-typings'; +import type { ILivechatDepartment, IOmnichannelRoom, SelectedAgent, IMessage, ILivechatVisitor } from '@rocket.chat/core-typings'; import { OmnichannelSourceType } from '@rocket.chat/core-typings'; import { LivechatVisitors, LivechatRooms, LivechatDepartment, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { callbacks } from '../../../../lib/callbacks'; import { deasyncPromise } from '../../../../server/deasync/deasync'; import { getRoom } from '../../../livechat/server/api/lib/livechat'; -import { Livechat as LivechatTyped } from '../../../livechat/server/lib/LivechatTyped'; +import { type ILivechatMessage, Livechat as LivechatTyped } from '../../../livechat/server/lib/LivechatTyped'; import { settings } from '../../../settings/server'; export class AppLivechatBridge extends LivechatBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } @@ -36,16 +30,21 @@ export class AppLivechatBridge extends LivechatBridge { return LivechatTyped.online(departmentId); } - protected async createMessage(message: ILivechatMessage, appId: string): Promise { + protected async createMessage(message: IAppsLivechatMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is creating a new message.`); if (!message.token) { throw new Error('Invalid token for livechat message'); } + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const guest = this.orch.getConverters().get('visitors').convertAppVisitor(message.visitor); + const appMessage = (await this.orch.getConverters().get('messages').convertAppMessage(message)) as IMessage | undefined; + const livechatMessage = appMessage as ILivechatMessage | undefined; + const msg = await LivechatTyped.sendMessage({ - guest: this.orch.getConverters()?.get('visitors').convertAppVisitor(message.visitor), - message: await this.orch.getConverters()?.get('messages').convertAppMessage(message), + guest: guest as ILivechatVisitor, + message: livechatMessage as ILivechatMessage, agent: undefined, roomInfo: { source: { @@ -59,13 +58,16 @@ export class AppLivechatBridge extends LivechatBridge { return msg._id; } - protected async getMessageById(messageId: string, appId: string): Promise { + protected async getMessageById(messageId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the message: "${messageId}"`); - return this.orch.getConverters()?.get('messages').convertById(messageId); + const message = await this.orch.getConverters().get('messages').convertById(messageId); + + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + return message as IAppsLivechatMessage; } - protected async updateMessage(message: ILivechatMessage, appId: string): Promise { + protected async updateMessage(message: IAppsLivechatMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is updating a message.`); const data = { @@ -114,7 +116,8 @@ export class AppLivechatBridge extends LivechatBridge { extraParams: undefined, }); - return this.orch.getConverters()?.get('rooms').convertRoom(result.room); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + return this.orch.getConverters()?.get('rooms').convertRoom(result.room) as Promise; } protected async closeRoom(room: ILivechatRoom, comment: string, closer: IUser | undefined, appId: string): Promise { @@ -152,7 +155,8 @@ export class AppLivechatBridge extends LivechatBridge { result = await LivechatRooms.findOpenByVisitorToken(visitor.token, {}, extraQuery).toArray(); } - return Promise.all((result as unknown as ILivechatRoom[]).map((room) => this.orch.getConverters()?.get('rooms').convertRoom(room))); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + return Promise.all(result.map((room) => this.orch.getConverters()?.get('rooms').convertRoom(room) as Promise)); } protected async createVisitor(visitor: IVisitor, appId: string): Promise { @@ -208,8 +212,9 @@ export class AppLivechatBridge extends LivechatBridge { userId = transferredTo._id; } + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. return LivechatTyped.transfer( - await this.orch.getConverters()?.get('rooms').convertAppRoom(currentRoom), + (await this.orch.getConverters()?.get('rooms').convertAppRoom(currentRoom)) as IOmnichannelRoom, this.orch.getConverters()?.get('visitors').convertAppVisitor(visitor), { userId, departmentId, transferredBy, transferredTo }, ); @@ -275,7 +280,8 @@ export class AppLivechatBridge extends LivechatBridge { this.orch.debugLog(`The App ${appId} is looking for livechat departments.`); const converter = this.orch.getConverters()?.get('departments'); - const boundConverter = converter.convertDepartment.bind(converter); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const boundConverter = converter.convertDepartment.bind(converter) as (_: ILivechatDepartment) => Promise; return Promise.all((await LivechatDepartment.findEnabledWithAgents().toArray()).map(boundConverter)); } diff --git a/apps/meteor/app/apps/server/bridges/messages.ts b/apps/meteor/app/apps/server/bridges/messages.ts index 311e3aaca1e1b..18a68220998fa 100644 --- a/apps/meteor/app/apps/server/bridges/messages.ts +++ b/apps/meteor/app/apps/server/bridges/messages.ts @@ -1,39 +1,41 @@ -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; +import type { IAppServerOrchestrator, IAppsMessage, IAppsUser } from '@rocket.chat/apps'; import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import type { ITypingDescriptor } from '@rocket.chat/apps-engine/server/bridges/MessageBridge'; import { MessageBridge } from '@rocket.chat/apps-engine/server/bridges/MessageBridge'; import { api } from '@rocket.chat/core-services'; +import type { IMessage } from '@rocket.chat/core-typings'; import { Users, Subscriptions, Messages } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { deleteMessage } from '../../../lib/server/functions/deleteMessage'; import { updateMessage } from '../../../lib/server/functions/updateMessage'; import { executeSendMessage } from '../../../lib/server/methods/sendMessage'; import notifications from '../../../notifications/server/lib/Notifications'; export class AppMessageBridge extends MessageBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } - protected async create(message: IMessage, appId: string): Promise { + protected async create(message: IAppsMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is creating a new message.`); - const convertedMessage = await this.orch.getConverters()?.get('messages').convertAppMessage(message); - - const sentMessage = await executeSendMessage(convertedMessage.u._id, convertedMessage); + const convertedMessage: IMessage | undefined = await this.orch.getConverters()?.get('messages').convertAppMessage(message); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const definedMessage = convertedMessage as IMessage; + const sentMessage = await executeSendMessage(definedMessage.u._id, definedMessage); return sentMessage._id; } - protected async getById(messageId: string, appId: string): Promise { + protected async getById(messageId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the message: "${messageId}"`); - return this.orch.getConverters()?.get('messages').convertById(messageId); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const message: IAppsMessage | undefined = await this.orch.getConverters()?.get('messages').convertById(messageId); + return message as IAppsMessage; } - protected async update(message: IMessage, appId: string): Promise { + protected async update(message: IAppsMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is updating a message.`); if (!message.editor) { @@ -44,17 +46,18 @@ export class AppMessageBridge extends MessageBridge { throw new Error('A message must exist to update.'); } - const msg = await this.orch.getConverters()?.get('messages').convertAppMessage(message); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const msg: IMessage | undefined = await this.orch.getConverters()?.get('messages').convertAppMessage(message); const editor = await Users.findOneById(message.editor.id); if (!editor) { throw new Error('Invalid editor assigned to the message for the update.'); } - await updateMessage(msg, editor); + await updateMessage(msg as IMessage, editor); } - protected async delete(message: IMessage, user: IUser, appId: string): Promise { + protected async delete(message: IAppsMessage, user: IAppsUser, appId: string): Promise { this.orch.debugLog(`The App ${appId} is deleting a message.`); if (!message.id) { @@ -64,10 +67,10 @@ export class AppMessageBridge extends MessageBridge { const convertedMsg = await this.orch.getConverters()?.get('messages').convertAppMessage(message); const convertedUser = (await Users.findOneById(user.id)) || this.orch.getConverters()?.get('users').convertToRocketChat(user); - await deleteMessage(convertedMsg, convertedUser); + await deleteMessage(convertedMsg as IMessage, convertedUser); } - protected async notifyUser(user: IUser, message: IMessage, appId: string): Promise { + protected async notifyUser(user: IAppsUser, message: IAppsMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is notifying a user.`); const msg = await this.orch.getConverters()?.get('messages').convertAppMessage(message); @@ -81,21 +84,23 @@ export class AppMessageBridge extends MessageBridge { }); } - protected async notifyRoom(room: IRoom, message: IMessage, appId: string): Promise { + protected async notifyRoom(room: IRoom, message: IAppsMessage, appId: string): Promise { this.orch.debugLog(`The App ${appId} is notifying a room's users.`); if (!room?.id) { return; } - const msg = await this.orch.getConverters()?.get('messages').convertAppMessage(message); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const msg: IMessage | undefined = await this.orch.getConverters()?.get('messages').convertAppMessage(message); + const convertedMessage = msg as IMessage; const users = (await Subscriptions.findByRoomIdWhenUserIdExists(room.id, { projection: { 'u._id': 1 } }).toArray()).map((s) => s.u._id); await Users.findByIds(users, { projection: { _id: 1 } }).forEach( ({ _id }: { _id: string }) => void api.broadcast('notify.ephemeralMessage', _id, room.id, { - ...msg, + ...convertedMessage, }), ); } diff --git a/apps/meteor/app/apps/server/bridges/moderation.ts b/apps/meteor/app/apps/server/bridges/moderation.ts index 4581f9a6ac6bd..0f1e56bbdec35 100644 --- a/apps/meteor/app/apps/server/bridges/moderation.ts +++ b/apps/meteor/app/apps/server/bridges/moderation.ts @@ -1,13 +1,13 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import { ModerationBridge } from '@rocket.chat/apps-engine/server/bridges/ModerationBridge'; import { ModerationReports } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { reportMessage } from '../../../../server/lib/moderation/reportMessage'; export class AppModerationBridge extends ModerationBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/oauthApps.ts b/apps/meteor/app/apps/server/bridges/oauthApps.ts index 943c082ba85aa..ba8ed81246904 100644 --- a/apps/meteor/app/apps/server/bridges/oauthApps.ts +++ b/apps/meteor/app/apps/server/bridges/oauthApps.ts @@ -1,3 +1,4 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IOAuthApp, IOAuthAppParams } from '@rocket.chat/apps-engine/definition/accessors/IOAuthApp'; import { OAuthAppsBridge } from '@rocket.chat/apps-engine/server/bridges/OAuthAppsBridge'; import type { IOAuthApps } from '@rocket.chat/core-typings'; @@ -5,10 +6,8 @@ import { OAuthApps, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; import { v4 as uuidv4 } from 'uuid'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppOAuthAppsBridge extends OAuthAppsBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/persistence.ts b/apps/meteor/app/apps/server/bridges/persistence.ts index 3810ed367e990..857f6a561ed6f 100644 --- a/apps/meteor/app/apps/server/bridges/persistence.ts +++ b/apps/meteor/app/apps/server/bridges/persistence.ts @@ -1,11 +1,10 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; import { PersistenceBridge } from '@rocket.chat/apps-engine/server/bridges/PersistenceBridge'; -import type { InsertOneResult, UpdateResult } from 'mongodb'; - -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; +import type { InsertOneResult } from 'mongodb'; export class AppPersistenceBridge extends PersistenceBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } @@ -25,7 +24,7 @@ export class AppPersistenceBridge extends PersistenceBridge { return this.orch .getPersistenceModel() .insertOne({ appId, data }) - .then(({ insertedId }: InsertOneResult) => insertedId || ''); + .then(({ insertedId }: InsertOneResult) => (insertedId as unknown as string) || ''); } protected async createWithAssociations(data: object, associations: Array, appId: string): Promise { @@ -42,7 +41,7 @@ export class AppPersistenceBridge extends PersistenceBridge { return this.orch .getPersistenceModel() .insertOne({ appId, associations, data }) - .then(({ insertedId }: InsertOneResult) => insertedId || ''); + .then(({ insertedId }: InsertOneResult) => (insertedId as unknown as string) || ''); } protected async readById(id: string, appId: string): Promise { @@ -135,6 +134,6 @@ export class AppPersistenceBridge extends PersistenceBridge { return this.orch .getPersistenceModel() .update(query, { $set: { data } }, { upsert }) - .then(({ upsertedId }: UpdateResult) => upsertedId || ''); + .then(({ upsertedId }: any) => upsertedId || ''); } } diff --git a/apps/meteor/app/apps/server/bridges/roles.ts b/apps/meteor/app/apps/server/bridges/roles.ts index f973b7f49ed2a..aa0fcdc7b80b7 100644 --- a/apps/meteor/app/apps/server/bridges/roles.ts +++ b/apps/meteor/app/apps/server/bridges/roles.ts @@ -1,27 +1,30 @@ -import type { IRole } from '@rocket.chat/apps-engine/definition/roles'; +import type { IAppServerOrchestrator, IAppsRole } from '@rocket.chat/apps'; import { RoleBridge } from '@rocket.chat/apps-engine/server/bridges'; +import type { IRole } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppRoleBridge extends RoleBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } - protected async getOneByIdOrName(idOrName: IRole['id'] | IRole['name'], appId: string): Promise { + protected async getOneByIdOrName(idOrName: IAppsRole['id'] | IAppsRole['name'], appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the roleByIdOrName: "${idOrName}"`); - const role = await Roles.findOneByIdOrName(idOrName); - return this.orch.getConverters()?.get('roles').convertRole(role); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const role: IRole | null = await Roles.findOneByIdOrName(idOrName); + return this.orch + .getConverters() + ?.get('roles') + .convertRole(role as IRole); } - protected async getCustomRoles(appId: string): Promise> { + protected async getCustomRoles(appId: string): Promise> { this.orch.debugLog(`The App ${appId} is getting the custom roles`); const cursor = Roles.findCustomRoles(); - const roles: IRole[] = []; + const roles: IAppsRole[] = []; for await (const role of cursor) { const convRole = await this.orch.getConverters()?.get('roles').convertRole(role); diff --git a/apps/meteor/app/apps/server/bridges/rooms.ts b/apps/meteor/app/apps/server/bridges/rooms.ts index 91b0049513f0e..bbd24152716f0 100644 --- a/apps/meteor/app/apps/server/bridges/rooms.ts +++ b/apps/meteor/app/apps/server/bridges/rooms.ts @@ -1,3 +1,4 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; @@ -6,7 +7,6 @@ import { RoomBridge } from '@rocket.chat/apps-engine/server/bridges/RoomBridge'; import type { ISubscription, IUser as ICoreUser, IRoom as ICoreRoom } from '@rocket.chat/core-typings'; import { Subscriptions, Users, Rooms } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { createDirectMessage } from '../../../../server/methods/createDirectMessage'; import { createDiscussion } from '../../../discussion/server/methods/createDiscussion'; import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom'; @@ -15,7 +15,7 @@ import { createChannelMethod } from '../../../lib/server/methods/createChannel'; import { createPrivateGroupMethod } from '../../../lib/server/methods/createPrivateGroup'; export class AppRoomBridge extends RoomBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } @@ -65,13 +65,17 @@ export class AppRoomBridge extends RoomBridge { protected async getById(roomId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the roomById: "${roomId}"`); - return this.orch.getConverters()?.get('rooms').convertById(roomId); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('rooms').convertById(roomId); + return promise as Promise; } protected async getByName(roomName: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the roomByName: "${roomName}"`); - return this.orch.getConverters()?.get('rooms').convertByName(roomName); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('rooms').convertByName(roomName); + return promise as Promise; } protected async getCreatorById(roomId: string, appId: string): Promise { @@ -79,7 +83,7 @@ export class AppRoomBridge extends RoomBridge { const room = await Rooms.findOneById(roomId); - if (!room || !room.u || !room.u._id) { + if (!room?.u?._id) { return undefined; } @@ -91,7 +95,7 @@ export class AppRoomBridge extends RoomBridge { const room = await Rooms.findOneByName(roomName, {}); - if (!room || !room.u || !room.u._id) { + if (!room?.u?._id) { return undefined; } @@ -101,9 +105,12 @@ export class AppRoomBridge extends RoomBridge { protected async getMembers(roomId: string, appId: string): Promise> { this.orch.debugLog(`The App ${appId} is getting the room's members by room id: "${roomId}"`); const subscriptions = await Subscriptions.findByRoomId(roomId, {}); - return Promise.all( + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promises: Promise<(IUser | undefined)[]> = Promise.all( (await subscriptions.toArray()).map((sub: ISubscription) => this.orch.getConverters()?.get('users').convertById(sub.u?._id)), ); + + return promises as Promise; } protected async getDirectByUsernames(usernames: Array, appId: string): Promise { @@ -124,7 +131,7 @@ export class AppRoomBridge extends RoomBridge { const rm = await this.orch.getConverters()?.get('rooms').convertAppRoom(room); - await Rooms.updateOne({ _id: rm._id }, { $set: rm }); + await Rooms.updateOne({ _id: rm._id }, { $set: rm as Partial }); for await (const username of members) { const member = await Users.findOneByUsername(username, {}); @@ -162,9 +169,10 @@ export class AppRoomBridge extends RoomBridge { throw new Error('There must be a parent room to create a discussion.'); } + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. const discussion = { prid: rcRoom.prid, - t_name: rcRoom.fname, + t_name: rcRoom.fname as string, pmid: rcMessage ? rcMessage._id : undefined, reply: reply && reply.trim() !== '' ? reply : undefined, users: members.length > 0 ? members : [], @@ -198,7 +206,7 @@ export class AppRoomBridge extends RoomBridge { }[]; // Was this a bug? const users = await Users.findByIds(subs.map((user: { uid: string }) => user.uid)).toArray(); - const userConverter = this.orch.getConverters()!.get('users'); - return users.map((user: ICoreUser) => userConverter!.convertToApp(user)); + const userConverter = this.orch.getConverters().get('users'); + return users.map((user: ICoreUser) => userConverter.convertToApp(user)); } } diff --git a/apps/meteor/app/apps/server/bridges/scheduler.ts b/apps/meteor/app/apps/server/bridges/scheduler.ts index 0b2995166e630..2f4799c79d70c 100644 --- a/apps/meteor/app/apps/server/bridges/scheduler.ts +++ b/apps/meteor/app/apps/server/bridges/scheduler.ts @@ -1,13 +1,12 @@ import type { Job } from '@rocket.chat/agenda'; import { Agenda } from '@rocket.chat/agenda'; +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IProcessor, IOnetimeSchedule, IRecurringSchedule, IJobContext } from '@rocket.chat/apps-engine/definition/scheduler'; import { StartupType } from '@rocket.chat/apps-engine/definition/scheduler'; import { SchedulerBridge } from '@rocket.chat/apps-engine/server/bridges/SchedulerBridge'; import { ObjectID } from 'bson'; import { MongoInternals } from 'meteor/mongo'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - function _callProcessor(processor: IProcessor['processor']): (job: Job) => Promise { return (job) => { const data = job?.attrs?.data || {}; @@ -36,7 +35,7 @@ export class AppSchedulerBridge extends SchedulerBridge { private scheduler: Agenda; - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); this.scheduler = new Agenda({ mongo: (MongoInternals.defaultRemoteCollectionDriver().mongo as any).client.db(), diff --git a/apps/meteor/app/apps/server/bridges/settings.ts b/apps/meteor/app/apps/server/bridges/settings.ts index d61de9e8eca5e..e90171813df85 100644 --- a/apps/meteor/app/apps/server/bridges/settings.ts +++ b/apps/meteor/app/apps/server/bridges/settings.ts @@ -1,11 +1,10 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import { ServerSettingBridge } from '@rocket.chat/apps-engine/server/bridges/ServerSettingBridge'; import { Settings } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppSettingBridge extends ServerSettingBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/thread.ts b/apps/meteor/app/apps/server/bridges/thread.ts index 313f60ecc4ac9..099fe9184e004 100644 --- a/apps/meteor/app/apps/server/bridges/thread.ts +++ b/apps/meteor/app/apps/server/bridges/thread.ts @@ -1,10 +1,9 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; import { ThreadBridge } from '@rocket.chat/apps-engine/server/bridges/ThreadBridge'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class AppThreadBridge extends ThreadBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/uiInteraction.ts b/apps/meteor/app/apps/server/bridges/uiInteraction.ts index 5783ac2b4eb3a..fc68e4e30d3ff 100644 --- a/apps/meteor/app/apps/server/bridges/uiInteraction.ts +++ b/apps/meteor/app/apps/server/bridges/uiInteraction.ts @@ -1,13 +1,12 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IUIKitInteraction } from '@rocket.chat/apps-engine/definition/uikit'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import { UiInteractionBridge as AppsEngineUiInteractionBridge } from '@rocket.chat/apps-engine/server/bridges/UiInteractionBridge'; import { api } from '@rocket.chat/core-services'; import type * as UiKit from '@rocket.chat/ui-kit'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; - export class UiInteractionBridge extends AppsEngineUiInteractionBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } diff --git a/apps/meteor/app/apps/server/bridges/uploads.ts b/apps/meteor/app/apps/server/bridges/uploads.ts index df16704a31963..b9d0ff67de58e 100644 --- a/apps/meteor/app/apps/server/bridges/uploads.ts +++ b/apps/meteor/app/apps/server/bridges/uploads.ts @@ -1,9 +1,9 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IUpload } from '@rocket.chat/apps-engine/definition/uploads'; import type { IUploadDetails } from '@rocket.chat/apps-engine/definition/uploads/IUploadDetails'; import { UploadBridge } from '@rocket.chat/apps-engine/server/bridges/UploadBridge'; import { determineFileType } from '../../../../ee/lib/misc/determineFileType'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { FileUpload } from '../../../file-upload/server'; import { sendFileMessage } from '../../../file-upload/server/methods/sendFileMessage'; import { sendFileLivechatMessage } from '../../../livechat/server/methods/sendFileLivechatMessage'; @@ -16,14 +16,16 @@ const getUploadDetails = (details: IUploadDetails): Partial => { return details; }; export class AppUploadBridge extends UploadBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } protected async getById(id: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the upload: "${id}"`); - return this.orch.getConverters()?.get('uploads').convertById(id); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('uploads').convertById(id); + return promise as Promise; } protected async getBuffer(upload: IUpload, appId: string): Promise { diff --git a/apps/meteor/app/apps/server/bridges/users.ts b/apps/meteor/app/apps/server/bridges/users.ts index d3c7dbc2a3d20..b0dfedd6273bc 100644 --- a/apps/meteor/app/apps/server/bridges/users.ts +++ b/apps/meteor/app/apps/server/bridges/users.ts @@ -1,3 +1,4 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IUserCreationOptions, IUser, UserType } from '@rocket.chat/apps-engine/definition/users'; import { UserBridge } from '@rocket.chat/apps-engine/server/bridges/UserBridge'; import { Presence } from '@rocket.chat/core-services'; @@ -5,7 +6,6 @@ import type { UserStatus } from '@rocket.chat/core-typings'; import { Subscriptions, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { checkUsernameAvailability } from '../../../lib/server/functions/checkUsernameAvailability'; import { deleteUser } from '../../../lib/server/functions/deleteUser'; import { getUserCreatedByApp } from '../../../lib/server/functions/getUserCreatedByApp'; @@ -13,20 +13,23 @@ import { setUserActiveStatus } from '../../../lib/server/functions/setUserActive import { setUserAvatar } from '../../../lib/server/functions/setUserAvatar'; export class AppUserBridge extends UserBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } protected async getById(userId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the userId: "${userId}"`); - - return this.orch.getConverters()?.get('users').convertById(userId); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('users').convertById(userId); + return promise as Promise; } protected async getByUsername(username: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the username: "${username}"`); - return this.orch.getConverters()?.get('users').convertByUsername(username); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('users').convertByUsername(username); + return promise as Promise; } protected async getAppUser(appId?: string): Promise { @@ -61,7 +64,11 @@ export class AppUserBridge extends UserBridge { protected async create(userDescriptor: Partial, appId: string, options?: IUserCreationOptions): Promise { this.orch.debugLog(`The App ${appId} is requesting to create a new user.`); - const user = this.orch.getConverters()?.get('users').convertToRocketChat(userDescriptor); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const user = this.orch + .getConverters() + ?.get('users') + .convertToRocketChat(userDescriptor as IUser); if (!user._id) { user._id = Random.id(); @@ -74,7 +81,7 @@ export class AppUserBridge extends UserBridge { switch (user.type) { case 'bot': case 'app': - if (!(await checkUsernameAvailability(user.username))) { + if (!(await checkUsernameAvailability(user.username as string))) { throw new Error(`The username "${user.username}" is already being used. Rename or remove the user using it to install this App`); } @@ -139,9 +146,12 @@ export class AppUserBridge extends UserBridge { if (!userId) { throw new Error('Invalid user id'); } - const convertedUser = await this.orch.getConverters()?.get('users').convertById(userId); - await setUserActiveStatus(convertedUser.id, false, confirmRelinquish); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const convertedUser: IUser | undefined = await this.orch.getConverters()?.get('users').convertById(userId); + const { id: uid } = convertedUser as IUser; + + await setUserActiveStatus(uid, false, confirmRelinquish); return true; } diff --git a/apps/meteor/app/apps/server/bridges/videoConferences.ts b/apps/meteor/app/apps/server/bridges/videoConferences.ts index c70f7f562fab8..bebcb25a6f516 100644 --- a/apps/meteor/app/apps/server/bridges/videoConferences.ts +++ b/apps/meteor/app/apps/server/bridges/videoConferences.ts @@ -1,21 +1,23 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders'; import type { AppVideoConference, VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; import { VideoConferenceBridge } from '@rocket.chat/apps-engine/server/bridges/VideoConferenceBridge'; import { VideoConf } from '@rocket.chat/core-services'; -import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { videoConfProviders } from '../../../../server/lib/videoConfProviders'; import type { AppVideoConferencesConverter } from '../converters/videoConferences'; export class AppVideoConferenceBridge extends VideoConferenceBridge { - constructor(private readonly orch: AppServerOrchestrator) { + constructor(private readonly orch: IAppServerOrchestrator) { super(); } protected async getById(callId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the video conference byId: "${callId}"`); - return this.orch.getConverters()?.get('videoConferences').convertById(callId); + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const promise: Promise = this.orch.getConverters()?.get('videoConferences').convertById(callId); + return promise as Promise; } protected async create(call: AppVideoConference, appId: string): Promise { diff --git a/apps/meteor/app/apps/server/converters/departments.js b/apps/meteor/app/apps/server/converters/departments.js index 087d1956ca6bd..3fbfd07e9e99b 100644 --- a/apps/meteor/app/apps/server/converters/departments.js +++ b/apps/meteor/app/apps/server/converters/departments.js @@ -1,6 +1,6 @@ import { LivechatDepartment } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; export class AppDepartmentsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/messages.js b/apps/meteor/app/apps/server/converters/messages.js index 6243bd2c603ea..187a6519339a4 100644 --- a/apps/meteor/app/apps/server/converters/messages.js +++ b/apps/meteor/app/apps/server/converters/messages.js @@ -1,7 +1,7 @@ import { Messages, Rooms, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; export class AppMessagesConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/roles.ts b/apps/meteor/app/apps/server/converters/roles.ts index 4ac1f39564207..10841a038c933 100644 --- a/apps/meteor/app/apps/server/converters/roles.ts +++ b/apps/meteor/app/apps/server/converters/roles.ts @@ -1,10 +1,11 @@ +import type { IAppRolesConverter } from '@rocket.chat/apps'; import type { IRole as AppsEngineRole } from '@rocket.chat/apps-engine/definition/roles'; import type { IRole } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; -export class AppRolesConverter { +export class AppRolesConverter implements IAppRolesConverter { async convertById(roleId: string): Promise { const role = await Roles.findOneById(roleId); @@ -22,8 +23,8 @@ export class AppRolesConverter { mandatory2fa: 'mandatory2fa', protected: 'protected', scope: 'scope', - }; + } as const; - return (await transformMappedData(role, map)) as unknown as AppsEngineRole; + return transformMappedData(role, map); } } diff --git a/apps/meteor/app/apps/server/converters/rooms.js b/apps/meteor/app/apps/server/converters/rooms.js index 9055342128362..670c1a248a0f0 100644 --- a/apps/meteor/app/apps/server/converters/rooms.js +++ b/apps/meteor/app/apps/server/converters/rooms.js @@ -1,7 +1,7 @@ import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; import { LivechatVisitors, Rooms, LivechatDepartment, Users } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; export class AppRoomsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/threads.ts b/apps/meteor/app/apps/server/converters/threads.ts index 19d3b4aeae6d9..840f4f1613ebb 100644 --- a/apps/meteor/app/apps/server/converters/threads.ts +++ b/apps/meteor/app/apps/server/converters/threads.ts @@ -1,18 +1,20 @@ -import type { IMessage as AppsEngineMessage } from '@rocket.chat/apps-engine/definition/messages'; +import type { IAppRoomsConverter, IAppThreadsConverter, IAppUsersConverter, IAppsMessage, IAppsUser } from '@rocket.chat/apps'; +import type { IMessage as AppsEngineMessage, IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages'; import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; +import type { IUser } from '@rocket.chat/core-typings'; import { isEditedMessage, type IMessage } from '@rocket.chat/core-typings'; import { Messages } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; // eslint-disable-next-line @typescript-eslint/naming-convention interface Orchestrator { rooms: () => { - convertById(id: string): Promise; + convertById: IAppRoomsConverter['convertById']; }; users: () => { - convertById(id: string): Promise; - convertToApp(user: unknown): Promise; + convertById: IAppUsersConverter['convertById']; + convertToApp: IAppUsersConverter['convertToApp']; }; } @@ -34,7 +36,7 @@ const cachedFunction = any>(fn: F) => { }) as F; }; -export class AppThreadsConverter { +export class AppThreadsConverter implements IAppThreadsConverter { constructor( private readonly orch: { getConverters: () => { @@ -111,7 +113,7 @@ export class AppThreadsConverter { return convertUserById(editedBy._id); }, - attachments: async (message: IMessage) => { + attachments: async (message: IMessage): Promise => { if (!message.attachments) { return undefined; } @@ -119,26 +121,33 @@ export class AppThreadsConverter { delete message.attachments; return result; }, - sender: async (message: IMessage) => { + sender: async (message: IMessage): Promise => { + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. if (!message.u?._id) { - return undefined; + return undefined as unknown as IAppsUser; } - let user = await convertUserById(message.u._id); + let user: IAppsUser | undefined = await convertUserById(message.u._id); // When the sender of the message is a Guest (livechat) and not a user if (!user) { - user = await convertToApp(message.u); + user = await convertToApp(message.u as unknown as IUser); } - return user; + return user as IAppsUser; }, - }; + } as const; - return (await transformMappedData(msgObj, map)) as unknown as AppsEngineMessage; + // #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed. + const msgData = { + ...msgObj, + reactions: msgObj.reactions as unknown as AppsEngineMessage['reactions'], + } as IMessage & { reactions?: AppsEngineMessage['reactions'] }; + + return transformMappedData(msgData, map); } - async _convertAttachmentsToApp(attachments: NonNullable) { + async _convertAttachmentsToApp(attachments: NonNullable): Promise> { const map = { collapsed: 'collapsed', color: 'color', @@ -161,7 +170,7 @@ export class AppThreadsConverter { actions: 'actions', type: 'type', description: 'description', - author: (attachment: NonNullable[number]) => { + author: (attachment: NonNullable[number]): IMessageAttachment['author'] => { if (!('author_name' in attachment)) { return; } @@ -188,7 +197,7 @@ export class AppThreadsConverter { delete attachment.ts; return result; }, - }; + } as const; return Promise.all(attachments.map(async (attachment) => transformMappedData(attachment, map))); } diff --git a/apps/meteor/ee/lib/misc/transformMappedData.js b/apps/meteor/app/apps/server/converters/transformMappedData.ts similarity index 73% rename from apps/meteor/ee/lib/misc/transformMappedData.js rename to apps/meteor/app/apps/server/converters/transformMappedData.ts index 963f98cb6cf59..df2f16138d731 100644 --- a/apps/meteor/ee/lib/misc/transformMappedData.js +++ b/apps/meteor/app/apps/server/converters/transformMappedData.ts @@ -12,7 +12,7 @@ import cloneDeep from 'lodash.clonedeep'; * * ```javascript * const data = { _id: 'abcde123456', size: 10 }; - * const map = { id: '_id' } + * const map = Object.freeze({ id: '_id' }); * * transformMappedData(data, map); * // { id: 'abcde123456', _unmappedProperties_: { size: 10 } } @@ -43,14 +43,14 @@ import cloneDeep from 'lodash.clonedeep'; * // { id: 'abcde123456', newSize: 20, _unmappedProperties_: { size: 10 } } * * // You need to explicitly remove it from the original `data` - * const map = { + * const map = Object.freeze({ * id: '_id', * newSize: (data) => { * const result = data.size + 10; * delete data.size; * return result; * } - * }; + * }); * * transformMappedData(data, map); * // { id: 'abcde123456', newSize: 20, _unmappedProperties_: {} } @@ -62,9 +62,25 @@ import cloneDeep from 'lodash.clonedeep'; * @returns Object The data after transformations have been applied */ -export const transformMappedData = async (data, map) => { - const originalData = cloneDeep(data); - const transformedData = {}; +export const transformMappedData = async < + ResultType extends { + -readonly [p in keyof MapType]: MapType[p] extends keyof DataType + ? DataType[MapType[p]] + : MapType[p] extends (...args: any[]) => any + ? Awaited> + : never; + }, + DataType extends Record, + MapType extends { [p in string]: string | ((data: DataType) => Promise) | ((data: DataType) => unknown) }, + UnmappedProperties extends { + [p in keyof DataType as Exclude]: DataType[p]; + }, +>( + data: DataType, + map: MapType, +): Promise => { + const originalData: DataType = cloneDeep(data); + const transformedData: Record = {}; for await (const [to, from] of Object.entries(map)) { if (typeof from === 'function') { @@ -81,7 +97,8 @@ export const transformMappedData = async (data, map) => { } } - transformedData._unmappedProperties_ = originalData; - - return transformedData; + return { + ...(transformedData as ResultType), + _unmappedProperties_: originalData as unknown as UnmappedProperties, + }; }; diff --git a/apps/meteor/app/apps/server/converters/uploads.js b/apps/meteor/app/apps/server/converters/uploads.js index b6531854aa38a..60f85a8aa72f1 100644 --- a/apps/meteor/app/apps/server/converters/uploads.js +++ b/apps/meteor/app/apps/server/converters/uploads.js @@ -1,6 +1,6 @@ import { Uploads } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; export class AppUploadsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/videoConferences.ts b/apps/meteor/app/apps/server/converters/videoConferences.ts index 00eb4e9151379..7a9120bf8508a 100644 --- a/apps/meteor/app/apps/server/converters/videoConferences.ts +++ b/apps/meteor/app/apps/server/converters/videoConferences.ts @@ -1,27 +1,33 @@ -import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; +import type { IAppVideoConferencesConverter, AppsVideoConference } from '@rocket.chat/apps'; import { VideoConf } from '@rocket.chat/core-services'; -import type { IVideoConference } from '@rocket.chat/core-typings'; +import type { VideoConference } from '@rocket.chat/core-typings'; -export class AppVideoConferencesConverter { - async convertById(callId: string): Promise { +export class AppVideoConferencesConverter implements IAppVideoConferencesConverter { + async convertById(callId: string): Promise { const call = await VideoConf.getUnfiltered(callId); return this.convertVideoConference(call); } - convertVideoConference(call: IVideoConference | null): VideoConference | undefined { + convertVideoConference(call: undefined | null): undefined; + + convertVideoConference(call: VideoConference): AppsVideoConference; + + convertVideoConference(call: VideoConference | undefined | null): AppsVideoConference | undefined; + + convertVideoConference(call: VideoConference | undefined | null): AppsVideoConference | undefined { if (!call) { return; } return { ...call, - } as VideoConference; + } as AppsVideoConference; } - convertAppVideoConference(call: VideoConference): IVideoConference { + convertAppVideoConference(call: AppsVideoConference): VideoConference { return { ...call, - } as IVideoConference; + } as VideoConference; } } diff --git a/apps/meteor/app/apps/server/converters/visitors.js b/apps/meteor/app/apps/server/converters/visitors.js index a9f5d450efad6..c8fb0b7c4a21c 100644 --- a/apps/meteor/app/apps/server/converters/visitors.js +++ b/apps/meteor/app/apps/server/converters/visitors.js @@ -1,6 +1,6 @@ import { LivechatVisitors } from '@rocket.chat/models'; -import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; +import { transformMappedData } from './transformMappedData'; // TODO: check if functions from this converter can be async export class AppVisitorsConverter { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 6e1b6a0b3836f..08f3997dbcd15 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -122,6 +122,7 @@ "@types/later": "^1.2.8", "@types/ldapjs": "^2.2.5", "@types/less": "~3.0.5", + "@types/lodash.clonedeep": "^4.5.9", "@types/lodash.get": "^4.4.8", "@types/mailparser": "^3.4.3", "@types/marked": "^4.0.8", @@ -229,6 +230,7 @@ "@rocket.chat/account-utils": "workspace:^", "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", + "@rocket.chat/apps": "workspace:^", "@rocket.chat/apps-engine": "1.41.0", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", diff --git a/packages/apps/.eslintrc.json b/packages/apps/.eslintrc.json new file mode 100644 index 0000000000000..a83aeda48e66d --- /dev/null +++ b/packages/apps/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": ["@rocket.chat/eslint-config"], + "ignorePatterns": ["**/dist"] +} diff --git a/packages/apps/package.json b/packages/apps/package.json new file mode 100644 index 0000000000000..ab37d0d388b04 --- /dev/null +++ b/packages/apps/package.json @@ -0,0 +1,29 @@ +{ + "name": "@rocket.chat/apps", + "version": "0.0.1", + "private": true, + "devDependencies": { + "@types/jest": "~29.5.7", + "eslint": "~8.45.0", + "jest": "~29.6.4", + "ts-jest": "~29.1.1", + "typescript": "~5.3.2" + }, + "scripts": { + "lint": "eslint --ext .js,.jsx,.ts,.tsx .", + "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", + "test": "jest", + "build": "rm -rf dist && tsc -p tsconfig.json", + "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + }, + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "files": [ + "/dist" + ], + "dependencies": { + "@rocket.chat/apps-engine": "^1.41.0", + "@rocket.chat/core-typings": "workspace:^", + "@rocket.chat/model-typings": "workspace:^" + } +} diff --git a/packages/apps/src/AppsEngine.ts b/packages/apps/src/AppsEngine.ts new file mode 100644 index 0000000000000..117e93c0ec2f7 --- /dev/null +++ b/packages/apps/src/AppsEngine.ts @@ -0,0 +1,20 @@ +export type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; +export type { + IDepartment as IAppsDepartment, + ILivechatMessage as IAppsLivechatMessage, + ILivechatRoom as IAppsLivechatRoom, + IVisitor as IAppsVisitor, + IVisitorEmail as IAppsVisitorEmail, + IVisitorPhone as IAppsVisitorPhone, +} from '@rocket.chat/apps-engine/definition/livechat'; +export type { IMessage as IAppsMessage } from '@rocket.chat/apps-engine/definition/messages'; +export type { IUser as IAppsUser } from '@rocket.chat/apps-engine/definition/users'; +export type { IRole as IAppsRole } from '@rocket.chat/apps-engine/definition/roles'; +export type { IRoom as IAppsRoom } from '@rocket.chat/apps-engine/definition/rooms'; +export type { ISetting as IAppsSetting } from '@rocket.chat/apps-engine/definition/settings'; +export type { IUpload as IAppsUpload } from '@rocket.chat/apps-engine/definition/uploads'; +export type { + IVideoConference as IAppsVideoConference, + VideoConference as AppsVideoConference, +} from '@rocket.chat/apps-engine/definition/videoConferences'; +export { AppManager } from '@rocket.chat/apps-engine/server/AppManager'; diff --git a/packages/apps/src/IAppServerNotifier.ts b/packages/apps/src/IAppServerNotifier.ts new file mode 100644 index 0000000000000..954f4a2ba5df4 --- /dev/null +++ b/packages/apps/src/IAppServerNotifier.ts @@ -0,0 +1,14 @@ +import type { AppStatus, IAppsSetting } from './AppsEngine'; + +export interface IAppServerNotifier { + appAdded(appId: string): Promise; + appRemoved(appId: string): Promise; + appUpdated(appId: string): Promise; + appStatusUpdated(appId: string, status: AppStatus): Promise; + appSettingsChange(appId: string, setting: IAppsSetting): Promise; + commandAdded(command: string): Promise; + commandDisabled(command: string): Promise; + commandUpdated(command: string): Promise; + commandRemoved(command: string): Promise; + actionsChanged(): Promise; +} diff --git a/packages/apps/src/IAppServerOrchestrator.ts b/packages/apps/src/IAppServerOrchestrator.ts new file mode 100644 index 0000000000000..dbfc5aee7a20d --- /dev/null +++ b/packages/apps/src/IAppServerOrchestrator.ts @@ -0,0 +1,17 @@ +import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager'; +import type { Logger } from '@rocket.chat/logger'; +import type { IAppsPersistenceModel } from '@rocket.chat/model-typings'; + +import type { IAppServerNotifier } from './IAppServerNotifier'; +import type { IAppConvertersMap } from './converters'; + +export interface IAppServerOrchestrator { + initialize(): void; + getNotifier(): IAppServerNotifier; + isDebugging(): boolean; + debugLog(...args: any[]): void; + getManager(): AppManager; + getConverters(): IAppConvertersMap; + getPersistenceModel(): IAppsPersistenceModel; + getRocketChatLogger(): Logger; +} diff --git a/packages/apps/src/converters/IAppConvertersMap.ts b/packages/apps/src/converters/IAppConvertersMap.ts new file mode 100644 index 0000000000000..63c94d44cb75b --- /dev/null +++ b/packages/apps/src/converters/IAppConvertersMap.ts @@ -0,0 +1,27 @@ +import type { IAppDepartmentsConverter } from './IAppDepartmentsConverter'; +import type { IAppMessagesConverter } from './IAppMessagesConverter'; +import type { IAppRolesConverter } from './IAppRolesConverter'; +import type { IAppRoomsConverter } from './IAppRoomsConverter'; +import type { IAppSettingsConverter } from './IAppSettingsConverter'; +import type { IAppThreadsConverter } from './IAppThreadsConverter'; +import type { IAppUploadsConverter } from './IAppUploadsConverter'; +import type { IAppUsersConverter } from './IAppUsersConverter'; +import type { IAppVideoConferencesConverter } from './IAppVideoConferencesConverter'; +import type { IAppVisitorsConverter } from './IAppVisitorsConverter'; + +type AppConverters = { + departments: IAppDepartmentsConverter; + messages: IAppMessagesConverter; + rooms: IAppRoomsConverter; + roles: IAppRolesConverter; + settings: IAppSettingsConverter; + threads: IAppThreadsConverter; + uploads: IAppUploadsConverter; + users: IAppUsersConverter; + visitors: IAppVisitorsConverter; + videoConferences: IAppVideoConferencesConverter; +}; + +export interface IAppConvertersMap extends Map { + get(key: T): AppConverters[T]; +} diff --git a/packages/apps/src/converters/IAppDepartmentsConverter.ts b/packages/apps/src/converters/IAppDepartmentsConverter.ts new file mode 100644 index 0000000000000..8dee30caa38c2 --- /dev/null +++ b/packages/apps/src/converters/IAppDepartmentsConverter.ts @@ -0,0 +1,13 @@ +import type { ILivechatDepartment } from '@rocket.chat/core-typings'; + +import type { IAppsDepartment } from '../AppsEngine'; + +export interface IAppDepartmentsConverter { + convertById(departmentId: ILivechatDepartment['_id']): Promise; + convertDepartment(department: undefined | null): Promise; + convertDepartment(department: ILivechatDepartment): Promise; + convertDepartment(department: ILivechatDepartment | undefined | null): Promise; + convertAppDepartment(department: undefined | null): undefined; + convertAppDepartment(department: IAppsDepartment): ILivechatDepartment; + convertAppDepartment(department: IAppsDepartment | undefined | null): ILivechatDepartment | undefined; +} diff --git a/packages/apps/src/converters/IAppMessagesConverter.ts b/packages/apps/src/converters/IAppMessagesConverter.ts new file mode 100644 index 0000000000000..185e247895de2 --- /dev/null +++ b/packages/apps/src/converters/IAppMessagesConverter.ts @@ -0,0 +1,13 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import type { IAppsMessage } from '../AppsEngine'; + +export interface IAppMessagesConverter { + convertById(messageId: IMessage['_id']): Promise; + convertMessage(message: undefined | null): Promise; + convertMessage(message: IMessage): Promise; + convertMessage(message: IMessage | undefined | null): Promise; + convertAppMessage(message: undefined | null): Promise; + convertAppMessage(message: IAppsMessage): Promise; + convertAppMessage(message: IAppsMessage | undefined | null): Promise; +} diff --git a/packages/apps/src/converters/IAppRolesConverter.ts b/packages/apps/src/converters/IAppRolesConverter.ts new file mode 100644 index 0000000000000..07ed84232ade4 --- /dev/null +++ b/packages/apps/src/converters/IAppRolesConverter.ts @@ -0,0 +1,8 @@ +import type { IRole } from '@rocket.chat/core-typings'; + +import type { IAppsRole } from '../AppsEngine'; + +export interface IAppRolesConverter { + convertById(roleId: IRole['_id']): Promise; + convertRole(role: IRole): Promise; +} diff --git a/packages/apps/src/converters/IAppRoomsConverter.ts b/packages/apps/src/converters/IAppRoomsConverter.ts new file mode 100644 index 0000000000000..9408b3f9b63ca --- /dev/null +++ b/packages/apps/src/converters/IAppRoomsConverter.ts @@ -0,0 +1,14 @@ +import type { IRoom } from '@rocket.chat/core-typings'; + +import type { IAppsRoom, IAppsLivechatRoom } from '../AppsEngine'; + +export interface IAppRoomsConverter { + convertById(roomId: IRoom['_id']): Promise; + convertByName(roomName: IRoom['name']): Promise; + convertRoom(room: undefined | null): Promise; + convertRoom(room: IRoom): Promise; + convertRoom(room: IRoom | undefined | null): Promise; + convertAppRoom(room: undefined | null): Promise; + convertAppRoom(room: IAppsRoom): Promise; + convertAppRoom(room: IAppsRoom | undefined | null): Promise; +} diff --git a/packages/apps/src/converters/IAppSettingsConverter.ts b/packages/apps/src/converters/IAppSettingsConverter.ts new file mode 100644 index 0000000000000..32db63e06c704 --- /dev/null +++ b/packages/apps/src/converters/IAppSettingsConverter.ts @@ -0,0 +1,8 @@ +import type { ISetting } from '@rocket.chat/core-typings'; + +import type { IAppsSetting } from '../AppsEngine'; + +export interface IAppSettingsConverter { + convertById(settingId: ISetting['_id']): Promise; + convertToApp(setting: ISetting): IAppsSetting; +} diff --git a/packages/apps/src/converters/IAppThreadsConverter.ts b/packages/apps/src/converters/IAppThreadsConverter.ts new file mode 100644 index 0000000000000..5253651c2683e --- /dev/null +++ b/packages/apps/src/converters/IAppThreadsConverter.ts @@ -0,0 +1,14 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import type { IAppsMessage, IAppsRoom } from '../AppsEngine'; +import type { IAppUsersConverter } from './IAppUsersConverter'; + +export interface IAppThreadsConverter { + convertById(threadId: string): Promise; + convertMessage( + msgObj: IMessage, + room: IAppsRoom, + convertUserById: IAppUsersConverter['convertById'], + convertToApp: IAppUsersConverter['convertToApp'], + ): Promise; +} diff --git a/packages/apps/src/converters/IAppUploadsConverter.ts b/packages/apps/src/converters/IAppUploadsConverter.ts new file mode 100644 index 0000000000000..4c7e4c2855c9a --- /dev/null +++ b/packages/apps/src/converters/IAppUploadsConverter.ts @@ -0,0 +1,13 @@ +import type { IUpload } from '@rocket.chat/core-typings'; + +import type { IAppsUpload } from '../AppsEngine'; + +export interface IAppUploadsConverter { + convertById(uploadId: string): Promise; + convertToApp(upload: undefined | null): Promise; + convertToApp(upload: IUpload): Promise; + convertToApp(upload: IUpload | undefined | null): Promise; + convertToRocketChat(upload: undefined | null): undefined; + convertToRocketChat(upload: IAppsUpload): IUpload; + convertToRocketChat(upload: IAppsUpload | undefined | null): IUpload | undefined; +} diff --git a/packages/apps/src/converters/IAppUsersConverter.ts b/packages/apps/src/converters/IAppUsersConverter.ts new file mode 100644 index 0000000000000..8d67cb9e5240d --- /dev/null +++ b/packages/apps/src/converters/IAppUsersConverter.ts @@ -0,0 +1,14 @@ +import type { IUser } from '@rocket.chat/core-typings'; + +import type { IAppsUser } from '../AppsEngine'; + +export interface IAppUsersConverter { + convertById(userId: IUser['_id']): Promise; + convertByUsername(username: IUser['username']): Promise; + convertToApp(user: undefined | null): undefined; + convertToApp(user: IUser): IAppsUser; + convertToApp(user: IUser | undefined | null): IAppsUser | undefined; + convertToRocketChat(user: undefined | null): undefined; + convertToRocketChat(user: IAppsUser): IUser; + convertToRocketChat(user: IAppsUser | undefined | null): IUser | undefined; +} diff --git a/packages/apps/src/converters/IAppVideoConferencesConverter.ts b/packages/apps/src/converters/IAppVideoConferencesConverter.ts new file mode 100644 index 0000000000000..b599c29e38641 --- /dev/null +++ b/packages/apps/src/converters/IAppVideoConferencesConverter.ts @@ -0,0 +1,11 @@ +import type { VideoConference } from '@rocket.chat/core-typings'; + +import type { AppsVideoConference } from '../AppsEngine'; + +export interface IAppVideoConferencesConverter { + convertById(videoConferenceId: VideoConference['_id']): Promise; + convertVideoConference(videoConference: undefined | null): undefined; + convertVideoConference(videoConference: VideoConference): AppsVideoConference; + convertVideoConference(videoConference: VideoConference | undefined | null): AppsVideoConference | undefined; + convertAppVideoConference(videoConference: AppsVideoConference): VideoConference; +} diff --git a/packages/apps/src/converters/IAppVisitorsConverter.ts b/packages/apps/src/converters/IAppVisitorsConverter.ts new file mode 100644 index 0000000000000..575845b57c105 --- /dev/null +++ b/packages/apps/src/converters/IAppVisitorsConverter.ts @@ -0,0 +1,14 @@ +import type { ILivechatVisitor } from '@rocket.chat/core-typings'; + +import type { IAppsVisitor } from '../AppsEngine'; + +export interface IAppVisitorsConverter { + convertById(visitorId: ILivechatVisitor['_id']): Promise; + convertByToken(token: string): Promise; + convertVisitor(visitor: undefined | null): Promise; + convertVisitor(visitor: ILivechatVisitor): Promise; + convertVisitor(visitor: ILivechatVisitor | undefined | null): Promise; + convertAppVisitor(visitor: undefined | null): undefined; + convertAppVisitor(visitor: IAppsVisitor): ILivechatVisitor; + convertAppVisitor(visitor: IAppsVisitor | undefined | null): ILivechatVisitor | undefined; +} diff --git a/packages/apps/src/converters/index.ts b/packages/apps/src/converters/index.ts new file mode 100644 index 0000000000000..61560afb5a4e4 --- /dev/null +++ b/packages/apps/src/converters/index.ts @@ -0,0 +1,11 @@ +export * from './IAppConvertersMap'; +export * from './IAppDepartmentsConverter'; +export * from './IAppMessagesConverter'; +export * from './IAppRolesConverter'; +export * from './IAppRoomsConverter'; +export * from './IAppSettingsConverter'; +export * from './IAppThreadsConverter'; +export * from './IAppUploadsConverter'; +export * from './IAppUsersConverter'; +export * from './IAppVideoConferencesConverter'; +export * from './IAppVisitorsConverter'; diff --git a/packages/apps/src/index.ts b/packages/apps/src/index.ts new file mode 100644 index 0000000000000..e137fa3cf0078 --- /dev/null +++ b/packages/apps/src/index.ts @@ -0,0 +1,4 @@ +export * from './converters'; +export * from './AppsEngine'; +export * from './IAppServerNotifier'; +export * from './IAppServerOrchestrator'; diff --git a/packages/apps/tsconfig.json b/packages/apps/tsconfig.json new file mode 100644 index 0000000000000..52e9dd8c4976b --- /dev/null +++ b/packages/apps/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.server.json", + "compilerOptions": { + "declaration": true, + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*"] +} diff --git a/yarn.lock b/yarn.lock index c1d3600c0f656..59cfd23cadfe5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8919,7 +8919,7 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/apps-engine@npm:1.41.0": +"@rocket.chat/apps-engine@npm:1.41.0, @rocket.chat/apps-engine@npm:^1.41.0": version: 1.41.0 resolution: "@rocket.chat/apps-engine@npm:1.41.0" dependencies: @@ -8937,6 +8937,21 @@ __metadata: languageName: node linkType: hard +"@rocket.chat/apps@workspace:^, @rocket.chat/apps@workspace:packages/apps": + version: 0.0.0-use.local + resolution: "@rocket.chat/apps@workspace:packages/apps" + dependencies: + "@rocket.chat/apps-engine": ^1.41.0 + "@rocket.chat/core-typings": "workspace:^" + "@rocket.chat/model-typings": "workspace:^" + "@types/jest": ~29.5.7 + eslint: ~8.45.0 + jest: ~29.6.4 + ts-jest: ~29.1.1 + typescript: ~5.3.2 + languageName: unknown + linkType: soft + "@rocket.chat/authorization-service@workspace:ee/apps/authorization-service": version: 0.0.0-use.local resolution: "@rocket.chat/authorization-service@workspace:ee/apps/authorization-service" @@ -9711,6 +9726,7 @@ __metadata: "@rocket.chat/account-utils": "workspace:^" "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" + "@rocket.chat/apps": "workspace:^" "@rocket.chat/apps-engine": 1.41.0 "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" @@ -9818,6 +9834,7 @@ __metadata: "@types/ldapjs": ^2.2.5 "@types/less": ~3.0.5 "@types/lodash": ^4.14.200 + "@types/lodash.clonedeep": ^4.5.9 "@types/lodash.debounce": ^4.0.8 "@types/lodash.get": ^4.4.8 "@types/mailparser": ^3.4.3 @@ -14169,6 +14186,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.clonedeep@npm:^4.5.9": + version: 4.5.9 + resolution: "@types/lodash.clonedeep@npm:4.5.9" + dependencies: + "@types/lodash": "*" + checksum: ef85512b7dce7a4f981a818ae44d11982907e1f26b5b26bedf0957c35e8591eb8e1d24fa31ca851d4b40e0a1ee88563853d762412691fe5f357e8335cead2325 + languageName: node + linkType: hard + "@types/lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "@types/lodash.debounce@npm:4.0.8"