feat: add channel id for thread message#21
Conversation
WalkthroughA new asynchronous function, Changes
Sequence Diagram(s)sequenceDiagram
participant DiscordGateway
participant MessageHandler
participant Activities
participant DatabaseManager
participant ThreadRepository
DiscordGateway->>MessageHandler: Receives message create event
MessageHandler->>Activities: mapMessageCreateData(data)
alt If channel type is thread (10, 11, 12)
MessageHandler->>Activities: getChannelIdFromThread(data)
Activities->>DatabaseManager: getConnection(data.guild_id)
DatabaseManager-->>Activities: connection
Activities->>ThreadRepository: find thread by data.channel_id
ThreadRepository-->>Activities: thread entity
Activities-->>MessageHandler: parent_id (channelId)
MessageHandler->>Activities: createRawInfo(mapped with channelId)
else Not a thread
MessageHandler->>Activities: createRawInfo(mapped)
end
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 6
🔭 Outside diff range comments (1)
src/activities/discord/gateway/mapping.activity.ts (1)
1-175: Add missing export for getChannelIdFromThreadThe
getChannelIdFromThreadfunction is implemented inadd-channelId.activity.tsand used inmessage.handler.ts, but it isn’t exported from the gateway activities entry point—this will break the import viaactivities.getChannelIdFromThread.• File: src/activities/discord/gateway/index.ts
Add the following line to ensure the new function is publicly available:+ export { getChannelIdFromThread } from './add-channelId.activity';
🧹 Nitpick comments (5)
src/libs/telegram/helpers/transformTelegramChat.ts (3)
39-43: Mark constant arrays asreadonlyto prevent accidental mutationThe three Dict arrays are now one-liners (great for readability), but they remain mutable. A stray write anywhere in the codebase would silently alter the behaviour of
transformTelegramChat.-const privateChatOptionalDict = ['chat_photo', 'chat_shared']; +const privateChatOptionalDict: readonly string[] = ['chat_photo', 'chat_shared'] as const;Apply the same
readonly/as constpattern togroupChatOptionalDictandchannelOptionalDict.
68-69: Consider aligning the naming with actual contentsEvery variable here ends with
Dictbut stores an array, not a dictionary / map. Using a suffix such asFields(or dropping the suffix altogether) would better signal intent and avoid mental overhead.
70-104: Tighten the return type & avoidany
transformTelegramChatcurrently returnsRecord<string, any>, which forfeits type-safety and makes downstream consumers fall back toany.
If the exact shape is difficult to express, at least narrow tounknowninstead ofany, e.g.:-export function transformTelegramChat(chat: Chat): Record<string, any> { +export function transformTelegramChat(chat: Chat): Record<string, unknown> {That forces callers to perform explicit narrowing and reduces the chance of runtime errors propagating unnoticed.
src/libs/telegram/services/chat.service.ts (1)
12-14: Inconsistent awaiting ofrunbetween transactional and non-transactional paths
neo4jService.runis awaited, buttx.runisn’t.
Althoughtx.runreturns aResultsynchronously, it will still perform network I/O once the transaction is committed; awaiting it keeps both branches semantically aligned and ensures errors propagate identically.- if (tx) { - tx.run(CREATE_OR_UPDATE_CHAT, { chat: transformTelegramChat(chat) }); + if (tx) { + await tx.run(CREATE_OR_UPDATE_CHAT, { chat: transformTelegramChat(chat) });(Same observation applies to
migrateChatbelow.)src/activities/discord/gateway/add-channelId.activity.ts (1)
4-20: Add JSDoc documentation.The function should have proper documentation explaining its purpose, parameters, and return value.
+/** + * Retrieves the parent channel ID for a Discord thread channel. + * @param data - Discord gateway message create dispatch data containing guild_id and channel_id + * @returns Promise resolving to the parent channel ID + * @throws Error if thread is not found or has no parent channel + */ export async function getChannelIdFromThread(
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/activities/discord/gateway/add-channelId.activity.ts(1 hunks)src/activities/discord/gateway/index.ts(1 hunks)src/activities/discord/gateway/mapping.activity.ts(1 hunks)src/activities/discord/gateway/persistence.activity.ts(2 hunks)src/examples/client/discordGateway.example.ts(1 hunks)src/libs/telegram/helpers/transformTelegramChat.ts(3 hunks)src/libs/telegram/services/chat.service.ts(1 hunks)src/workflows/discord/gateway/handlers/message.handler.ts(3 hunks)src/workflows/discord/gateway/handlers/thread.handler.ts(1 hunks)src/workflows/discord/gateway/mappers/message.mapper.ts(1 hunks)src/workflows/telegram/TelegramEventWorkflow.ts(1 hunks)src/workflows/telegram/index.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/libs/telegram/services/chat.service.ts (3)
src/libs/neo4j/Neo4jClient.ts (1)
neo4jService(45-45)src/libs/telegram/neo4j/cyphers/chat.ts (1)
CREATE_OR_UPDATE_CHAT(1-11)src/libs/telegram/helpers/transformTelegramChat.ts (1)
transformTelegramChat(70-104)
🔇 Additional comments (12)
src/workflows/telegram/index.ts (1)
5-6: LGTM! Good formatting practice.Adding a trailing newline at the end of the file follows standard formatting conventions.
src/workflows/telegram/TelegramEventWorkflow.ts (1)
34-41: LGTM! Improved readability.The multi-line formatting with proper indentation and trailing comma improves readability and makes future modifications easier.
src/examples/client/discordGateway.example.ts (2)
1-4: LGTM! Improved import readability.Multi-line import formatting improves readability and makes future import modifications easier to track in diffs.
9-12: LGTM! Consistent import formatting.The multi-line format aligns with the discord-api-types import above and maintains consistency across the file.
src/workflows/discord/gateway/mappers/message.mapper.ts (1)
1-7: LGTM! Enhanced import organization.The multi-line import format significantly improves readability when importing multiple related types from the same package.
src/activities/discord/gateway/mapping.activity.ts (2)
1-19: LGTM! Much better organization for large import lists.The multi-line format with consistent indentation greatly improves readability when importing many types from the same package.
24-29: LGTM! Consistent local import formatting.The multi-line format maintains consistency with the discord-api-types imports above.
src/workflows/discord/gateway/handlers/thread.handler.ts (1)
2-4: LGTM! Import formatting improvement.The reformatting of import statements improves consistency and readability across the codebase.
src/activities/discord/gateway/persistence.activity.ts (1)
5-20: LGTM! Import formatting improvement.The reformatting of import statements improves consistency and readability.
src/activities/discord/gateway/index.ts (1)
5-5: LGTM! Proper module export.The export follows the established pattern and correctly exposes the new add-channelId activity.
src/workflows/discord/gateway/handlers/message.handler.ts (2)
2-9: LGTM! Import formatting improvement.The reformatting of import statements improves consistency and readability.
61-61: LGTM! Formatting improvement.The added blank line improves readability.
| data: IRawInfo, | ||
| ): Promise<void> { | ||
| try { | ||
| console.log('Creating raw info', data); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Replace console.log with proper logging.
Using console.log in production code is not recommended. Use the existing logger instead for consistency and proper log management.
- console.log('Creating raw info', data);
+ logger.debug({ guildId, data }, 'Creating raw info');📝 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.
| console.log('Creating raw info', data); | |
| - console.log('Creating raw info', data); | |
| + logger.debug({ guildId, data }, 'Creating raw info'); |
🤖 Prompt for AI Agents
In src/activities/discord/gateway/persistence.activity.ts at line 153, replace
the console.log statement with the existing logger instance used in the project.
Use the appropriate logging method (e.g., logger.info or logger.debug) to log
the message 'Creating raw info' along with the data object, ensuring consistent
and manageable logging across the codebase.
| } catch (error) { | ||
| console.error('Error in getChannelIdFromThread:', error); | ||
| throw error; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use proper logging instead of console.error.
Consistent with other parts of the codebase, use a proper logger instead of console.error.
+import parentLogger from '../../../config/logger.config';
+
+const logger = parentLogger.child({ activity: 'discord:gateway:add-channelId' });
} catch (error) {
- console.error('Error in getChannelIdFromThread:', error);
+ logger.error({ error, guildId: data.guild_id, channelId: data.channel_id }, 'Failed to get channel ID from thread');
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.
| } catch (error) { | |
| console.error('Error in getChannelIdFromThread:', error); | |
| throw error; | |
| } | |
| import parentLogger from '../../../config/logger.config'; | |
| const logger = parentLogger.child({ activity: 'discord:gateway:add-channelId' }); | |
| // … other code … | |
| } catch (error) { | |
| logger.error( | |
| { error, guildId: data.guild_id, channelId: data.channel_id }, | |
| 'Failed to get channel ID from thread' | |
| ); | |
| throw error; | |
| } |
🤖 Prompt for AI Agents
In src/activities/discord/gateway/add-channelId.activity.ts around lines 16 to
19, replace the use of console.error with the project's standard logging utility
to maintain consistency. Import the appropriate logger if not already imported,
then use it to log the error instead of console.error, ensuring the log message
includes the error details clearly.
| export async function getChannelIdFromThread( | ||
| data: GatewayMessageCreateDispatchData, | ||
| ) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add explicit return type and parameter validation.
The function should have an explicit return type and validate required parameters.
-export async function getChannelIdFromThread(
- data: GatewayMessageCreateDispatchData,
-) {
+export async function getChannelIdFromThread(
+ data: GatewayMessageCreateDispatchData,
+): Promise<string> {
+ if (!data.guild_id || !data.channel_id) {
+ throw new Error('Missing required guild_id or channel_id');
+ }📝 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.
| export async function getChannelIdFromThread( | |
| data: GatewayMessageCreateDispatchData, | |
| ) { | |
| export async function getChannelIdFromThread( | |
| data: GatewayMessageCreateDispatchData, | |
| ): Promise<string> { | |
| if (!data.guild_id || !data.channel_id) { | |
| throw new Error('Missing required guild_id or channel_id'); | |
| } | |
| // …rest of implementation unchanged |
🤖 Prompt for AI Agents
In src/activities/discord/gateway/add-channelId.activity.ts around lines 4 to 6,
the function getChannelIdFromThread lacks an explicit return type and does not
validate its input parameter. Add an explicit return type that matches the
expected output of the function. Also, include validation logic to check that
the required properties exist on the data parameter before processing, and
handle cases where the input is invalid by returning an appropriate value or
throwing an error.
| let channelId: string; | ||
| const dbConnection = await DatabaseManager.getInstance().getGuildDb( | ||
| data.guild_id, | ||
| ); | ||
| const threadRepository = makeThreadRepository(dbConnection); | ||
| channelId = (await threadRepository.findOne({ id: data.channel_id })) | ||
| .parent_id; |
There was a problem hiding this comment.
Fix potential null pointer exception and improve error handling.
The code doesn't handle the case where the thread is not found in the database, which will cause a runtime error when trying to access .parent_id on null/undefined.
- try {
- let channelId: string;
- const dbConnection = await DatabaseManager.getInstance().getGuildDb(
- data.guild_id,
- );
- const threadRepository = makeThreadRepository(dbConnection);
- channelId = (await threadRepository.findOne({ id: data.channel_id }))
- .parent_id;
- return channelId;
+ try {
+ const dbConnection = await DatabaseManager.getInstance().getGuildDb(
+ data.guild_id,
+ );
+ const threadRepository = makeThreadRepository(dbConnection);
+ const thread = await threadRepository.findOne({ id: data.channel_id });
+
+ if (!thread) {
+ throw new Error(`Thread not found: ${data.channel_id}`);
+ }
+
+ if (!thread.parent_id) {
+ throw new Error(`Thread ${data.channel_id} has no parent channel`);
+ }
+
+ return thread.parent_id;📝 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.
| let channelId: string; | |
| const dbConnection = await DatabaseManager.getInstance().getGuildDb( | |
| data.guild_id, | |
| ); | |
| const threadRepository = makeThreadRepository(dbConnection); | |
| channelId = (await threadRepository.findOne({ id: data.channel_id })) | |
| .parent_id; | |
| const dbConnection = await DatabaseManager.getInstance().getGuildDb( | |
| data.guild_id, | |
| ); | |
| const threadRepository = makeThreadRepository(dbConnection); | |
| const thread = await threadRepository.findOne({ id: data.channel_id }); | |
| if (!thread) { | |
| throw new Error(`Thread not found: ${data.channel_id}`); | |
| } | |
| if (!thread.parent_id) { | |
| throw new Error(`Thread ${data.channel_id} has no parent channel`); | |
| } | |
| return thread.parent_id; |
🤖 Prompt for AI Agents
In src/activities/discord/gateway/add-channelId.activity.ts around lines 8 to
14, the code assigns channelId from the parent_id of a thread fetched from the
database without checking if the thread exists. To fix this, add a null check
after fetching the thread; if the thread is null or undefined, handle the error
appropriately (e.g., throw an error or return early) before accessing parent_id
to prevent a runtime null pointer exception.
| import { | ||
| DatabaseManager, | ||
| makeChannelRepository, | ||
| makeRawInfoRepository, | ||
| makeThreadRepository, | ||
| } from '@togethercrew.dev/db'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remove unused imports.
These database-related imports are not used anywhere in the file and should be removed to avoid confusion.
-import {
- DatabaseManager,
- makeChannelRepository,
- makeRawInfoRepository,
- makeThreadRepository,
-} from '@togethercrew.dev/db';📝 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.
| import { | |
| DatabaseManager, | |
| makeChannelRepository, | |
| makeRawInfoRepository, | |
| makeThreadRepository, | |
| } from '@togethercrew.dev/db'; |
🤖 Prompt for AI Agents
In src/workflows/discord/gateway/handlers/message.handler.ts between lines 15
and 20, remove the imports DatabaseManager, makeChannelRepository,
makeRawInfoRepository, and makeThreadRepository from '@togethercrew.dev/db' as
they are not used anywhere in the file and only add unnecessary clutter.
| // TODO: Need to remove this section | ||
| const tempData: any = data; | ||
| const isThreadMessage = | ||
| tempData.channel_type === 10 || | ||
| tempData.channel_type === 11 || | ||
| tempData.channel_type === 12; | ||
| if (isThreadMessage) { | ||
| const channelId = await activities.getChannelIdFromThread(data); | ||
| mapped.channelId = channelId; | ||
| } | ||
| // TODO: Until Here |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve type safety and use constants for channel types.
The current implementation has several issues: type casting to any, hard-coded magic numbers, and no error handling for the async call.
+// Discord channel types constants
+const DISCORD_CHANNEL_TYPES = {
+ GUILD_PUBLIC_THREAD: 11,
+ GUILD_PRIVATE_THREAD: 12,
+ GUILD_NEWS_THREAD: 10,
+} as const;
- // TODO: Need to remove this section
- const tempData: any = data;
- const isThreadMessage =
- tempData.channel_type === 10 ||
- tempData.channel_type === 11 ||
- tempData.channel_type === 12;
- if (isThreadMessage) {
- const channelId = await activities.getChannelIdFromThread(data);
- mapped.channelId = channelId;
- }
- // TODO: Until Here
+ // TODO: Need to remove this section
+ const isThreadMessage =
+ 'channel_type' in data && (
+ data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_NEWS_THREAD ||
+ data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_PUBLIC_THREAD ||
+ data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_PRIVATE_THREAD
+ );
+ if (isThreadMessage) {
+ try {
+ const channelId = await activities.getChannelIdFromThread(data);
+ mapped.channelId = channelId;
+ } catch (error) {
+ // Log error but don't fail the entire operation
+ console.error('Failed to get channel ID from thread:', error);
+ }
+ }
+ // TODO: Until Here📝 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.
| // TODO: Need to remove this section | |
| const tempData: any = data; | |
| const isThreadMessage = | |
| tempData.channel_type === 10 || | |
| tempData.channel_type === 11 || | |
| tempData.channel_type === 12; | |
| if (isThreadMessage) { | |
| const channelId = await activities.getChannelIdFromThread(data); | |
| mapped.channelId = channelId; | |
| } | |
| // TODO: Until Here | |
| // Discord channel types constants | |
| const DISCORD_CHANNEL_TYPES = { | |
| GUILD_PUBLIC_THREAD: 11, | |
| GUILD_PRIVATE_THREAD: 12, | |
| GUILD_NEWS_THREAD: 10, | |
| } as const; | |
| // TODO: Need to remove this section | |
| const isThreadMessage = | |
| 'channel_type' in data && ( | |
| data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_NEWS_THREAD || | |
| data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_PUBLIC_THREAD || | |
| data.channel_type === DISCORD_CHANNEL_TYPES.GUILD_PRIVATE_THREAD | |
| ); | |
| if (isThreadMessage) { | |
| try { | |
| const channelId = await activities.getChannelIdFromThread(data); | |
| mapped.channelId = channelId; | |
| } catch (error) { | |
| // Log error but don't fail the entire operation | |
| console.error('Failed to get channel ID from thread:', error); | |
| } | |
| } | |
| // TODO: Until Here |
🤖 Prompt for AI Agents
In src/workflows/discord/gateway/handlers/message.handler.ts around lines 42 to
52, replace the use of 'any' type casting with proper typing for the data
object, define and use named constants or enums for the channel_type values
instead of hard-coded numbers 10, 11, and 12, and add error handling for the
asynchronous call to activities.getChannelIdFromThread to handle potential
failures gracefully.
Summary by CodeRabbit