Skip to content

feat: discord plugin#50

Merged
elliotBraem merged 2 commits intomainfrom
feat/discord-plugin
Jun 5, 2025
Merged

feat: discord plugin#50
elliotBraem merged 2 commits intomainfrom
feat/discord-plugin

Conversation

@dungpt99
Copy link
Copy Markdown
Collaborator

@dungpt99 dungpt99 commented Jun 2, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a new Discord plugin that enables distribution of curated content to Discord channels.
    • Added default configuration options for the Discord plugin, including bot token and channel ID.
    • Registered the Discord plugin in the plugin manager for easy integration.
  • Documentation

    • Added comprehensive setup and configuration guides for the Discord plugin, including step-by-step instructions and configuration references.
    • Included a new README for the Discord plugin with usage details.
  • Chores

    • Added configuration and build files to support the new Discord plugin package.

@vercel
Copy link
Copy Markdown

vercel bot commented Jun 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
curatedotfun-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 5, 2025 0:17am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jun 2, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

A new Discord distributor plugin has been introduced, enabling curated content distribution to Discord channels. The update includes backend and frontend integration, default configuration, plugin registration, build and TypeScript configurations, and comprehensive documentation. The Discord plugin is implemented as a class and is packaged with all necessary metadata and build scripts.

Changes

File(s) Change Summary
apps/plugin-manager/backend/src/plugin-service/plugin-registry.ts Registered the new "@curatedotfun/discord" plugin with URL and type "distributor".
apps/plugin-manager/frontend/src/lib/plugin-context.tsx Added default configuration for the Discord plugin (botToken, channelId).
docs/docs/plugins/distributors/discord.md
packages/discord/README.md
Added user documentation and setup guides for the Discord distributor plugin.
packages/discord/package.json Created package metadata, scripts, dependencies, and export mappings for the new plugin.
packages/discord/rspack.config.cjs Added rspack build configuration with module federation and Node.js targeting for the Discord plugin.
packages/discord/src/index.ts Implemented DiscordPlugin class and DiscordConfig interface for sending messages to Discord channels.
packages/discord/tsconfig.build.json
packages/discord/tsconfig.json
Added TypeScript build and base configuration files for the Discord plugin package.

Sequence Diagram(s)

sequenceDiagram
    participant CurateApp
    participant DiscordPlugin
    participant DiscordAPI

    CurateApp->>DiscordPlugin: initialize(config: {botToken, channelId})
    DiscordPlugin->>DiscordAPI: login(botToken)
    DiscordPlugin->>DiscordAPI: fetchChannel(channelId)
    CurateApp->>DiscordPlugin: distribute(message)
    DiscordPlugin->>DiscordAPI: sendMessage(channelId, message)
    CurateApp->>DiscordPlugin: cleanup()
    DiscordPlugin->>DiscordAPI: logout()
Loading

Poem

A Discord bot hops into view,
Ready to share what's fresh and new.
With tokens and channels set just right,
It brings curated gems to Discord’s light.
Docs and configs now in place,
This bunny’s code hops with grace!
🐰✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d600e9 and 0468fc9.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • apps/plugin-manager/backend/src/plugin-service/plugin-registry.ts (1 hunks)
  • apps/plugin-manager/frontend/src/lib/plugin-context.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (9)
apps/plugin-manager/backend/src/plugin-service/plugin-registry.ts (1)

76-79: Consolidate plugin type validation
The validation block now includes "source" to support source plugins. Ensure the PluginType union in @curatedotfun/types is updated accordingly. Consider extracting the valid plugin types (["distributor", "transformer", "source"]) into a shared constant or enum to avoid duplication and improve maintainability.

packages/discord/tsconfig.build.json (1)

1-7: Confirm build output configuration
emitDeclarationOnly: true with noEmit: false will generate only .d.ts files. Verify that your base tsconfig.json specifies an outDir (e.g., "dist") to direct declaration outputs. Optionally, add "declarationMap": true to aid IDE navigation.

packages/discord/tsconfig.json (1)

2-15: Enhance TypeScript strictness and output settings
The base config is solid. For clarity and stricter module compilation, consider adding:

  • "rootDir": "src" to enforce source boundaries
  • "isolatedModules": true to catch per-file errors
  • "declarationDir": "dist/types" if you want separate declaration output
    Also verify toolchain support for moduleResolution: "bundler".
packages/discord/README.md (2)

56-58: Fix grammar issues in the tip section.

The static analysis tool correctly identified grammar issues in the tip section.

Apply this diff to fix the grammar:

-   If your stream had been disabled and you have existing, approved curations, call `/api/feeds/:feedId/process` to process them.
+   If your stream has been disabled and you have existing approved curations, call `/api/feeds/:feedId/process` to process them.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~57-~57: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)


38-44: Security consideration: Clarify token security.

The documentation mentions that the bot token is "automatically injected" and that channel IDs "can be shared publicly," but it would be helpful to explicitly clarify the security implications of the bot token.

Consider adding a security note:

   The container is already set up with the Discord bot token, which handles the API requests from the bot to your Discord channel. It automatically gets hydrated into the curate.config.json on start-up, replacing `{DISCORD_BOT_TOKEN}`.

+   :::warning Security
+   Keep your bot token secure and never share it publicly. The bot token provides access to your Discord bot and should be treated as a sensitive credential.
+   :::

   You need to specify:
   - `channelId`: Your Discord channel ID (e.g., 123456789012345678)

   These values can be shared publicly.
docs/docs/plugins/distributors/discord.md (2)

60-62: Fix grammar issues in the tip section.

Same grammar issues as in the README file need to be addressed here as well.

Apply this diff to fix the grammar:

-   If your stream had been disabled and you have existing, approved curations, call `/api/feeds/:feedId/process` to process them.
+   If your stream has been disabled and you have existing approved curations, call `/api/feeds/:feedId/process` to process them.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~61-~61: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~61-~61: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)


1-76: Consider reducing documentation duplication.

This documentation file is nearly identical to the README.md in the packages/discord directory. Consider whether both files are necessary or if one could reference the other to reduce maintenance overhead.

Options to consider:

  1. Keep only one comprehensive documentation file and reference it from the other location
  2. Have the package README focus on development/technical details while the docs focus on user setup
  3. Use a shared content approach if the documentation system supports it
🧰 Tools
🪛 LanguageTool

[uncategorized] ~61-~61: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~61-~61: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)

packages/discord/src/index.ts (2)

33-33: Remove debug logging.

The console.log statement appears to be debug code that should be removed before production.

Apply this diff to remove the debug logging:

-    console.log("config", config);

47-51: Optimize channel validation to avoid duplication.

The channel fetching and validation logic is duplicated between initialize and distribute methods. Consider storing the validated channel reference.

Consider this approach to reduce duplication:

   private client: Client | null = null;
-  private channelId: string | null = null;
+  private channel: TextChannel | null = null;
   private botToken: string | null = null;

   // In initialize method:
-  this.channelId = config.channelId;
   // ... after client login
   const channel = await this.client.channels.fetch(config.channelId);
   if (!channel || !(channel instanceof TextChannel)) {
     throw new Error("Invalid channel ID or insufficient permissions");
   }
+  this.channel = channel;

   // In distribute method:
-  if (!this.client || !this.channelId) {
+  if (!this.client || !this.channel) {
     throw new Error("Discord plugin not initialized");
   }

-  const channel = await this.client.channels.fetch(this.channelId);
-  if (!channel || !(channel instanceof TextChannel)) {
-    throw new Error("Invalid channel ID or insufficient permissions");
-  }
-
-  await channel.send(content);
+  await this.channel.send(content);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d9f10a and 8d600e9.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • apps/plugin-manager/backend/src/plugin-service/plugin-registry.ts (1 hunks)
  • apps/plugin-manager/frontend/src/lib/plugin-context.tsx (1 hunks)
  • docs/docs/plugins/distributors/discord.md (1 hunks)
  • package.json (1 hunks)
  • packages/discord/README.md (1 hunks)
  • packages/discord/package.json (1 hunks)
  • packages/discord/rspack.config.cjs (1 hunks)
  • packages/discord/src/index.ts (1 hunks)
  • packages/discord/tsconfig.build.json (1 hunks)
  • packages/discord/tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/discord/src/index.ts (1)
packages/types/src/index.ts (2)
  • DistributorPlugin (37-43)
  • ActionArgs (46-49)
🪛 LanguageTool
docs/docs/plugins/distributors/discord.md

[uncategorized] ~61-~61: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~61-~61: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)

packages/discord/README.md

[uncategorized] ~57-~57: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~57-~57: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)

🔇 Additional comments (19)
apps/plugin-manager/backend/src/plugin-service/plugin-registry.ts (1)

52-55: Verify Discord plugin registration details
The new entry for @curatedotfun/discord points to http://localhost:3012/remoteEntry.js as a distributor plugin. Confirm that this URL and port match your development and production deployments.

package.json (1)

12-12: Review development filter changes
The dev script now filters only @curatedotfun/plugin-manager and @curatedotfun/discord. Ensure this aligns with your local workflows: other packages (e.g., frontend) may no longer start automatically.

packages/discord/README.md (1)

1-72: Documentation quality is excellent.

The documentation provides comprehensive setup instructions with clear step-by-step guidance, proper configuration examples, and helpful tips for users.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~57-~57: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...d channel. :::tip If your stream had been disabled and you have existing, ap...

(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)


[uncategorized] ~57-~57: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...:tip If your stream had been disabled and you have existing, approved curations, ...

(COMMA_COMPOUND_SENTENCE)

packages/discord/package.json (2)

8-14: Verify export configuration for ES modules.

The export configuration looks correct for supporting both CommonJS and ES modules, with proper TypeScript declarations.


34-38: Build and development scripts are well-configured.

The scripts properly handle building, type checking, and development with appropriate tools (rspack, TypeScript, vitest).

packages/discord/src/index.ts (6)

4-8: Well-defined configuration interface.

The DiscordConfig interface properly defines the required configuration with appropriate types and allows for extension with the index signature.


10-16: Proper implementation of DistributorPlugin interface.

The class correctly implements the DistributorPlugin interface with the required type property and private state management.


18-30: Excellent configuration validation.

The initialization method properly validates required configuration parameters and provides clear error messages.


37-43: Appropriate Discord client configuration.

The client is configured with the necessary intents for sending messages and reading content. The intent selection is minimal and appropriate for the use case.


58-76: Robust message distribution with error handling.

The distribute method includes proper error handling and validation before attempting to send messages.


78-86: Proper cleanup implementation.

The cleanup method ensures the Discord client is properly destroyed with appropriate error handling.

packages/discord/rspack.config.cjs (8)

1-4: LGTM! Standard and necessary imports.

The dependencies are correctly imported and all are necessary for the rspack configuration setup.


7-10: LGTM! Appropriate basic configuration for a Node.js plugin.

The entry point, mode switching, Node.js target, and source map configuration are all correctly set up for a Discord plugin.


12-16: LGTM! Correct externals configuration.

Properly excludes Node.js built-ins and discord.js from bundling, which is the right approach for a plugin that will be loaded by a host application.


18-24: LGTM! Well-configured output settings.

The output configuration correctly uses normalized remote naming for module federation, enables auto public path resolution, and sets appropriate library type for Node.js.


35-43: LGTM! Correct TypeScript processing configuration.

The module rules properly configure TypeScript compilation using the built-in swc-loader and correctly exclude node_modules.


45-53: LGTM! Smart handling of optional native dependencies.

The resolve configuration correctly handles optional native modules that discord.js might try to use, preventing bundling issues by aliasing them to false.


26-33:

Details

✅ Verification successful

Verify port consistency with plugin registry.

The dev server configuration looks good with appropriate settings for module federation. Please ensure that port 3012 matches the port configured in the plugin registry.


🏁 Script executed:

#!/bin/bash
# Description: Verify that port 3012 is used consistently in the plugin registry configuration
# Expected: Port 3012 should be referenced in plugin registry files

rg -A 3 -B 3 "3012" --type js --type ts

Length of output: 637


Port consistency confirmed.

The development server’s port (3012) matches the plugin registry configuration:

No further changes required.


55-71:

Details

❓ Verification inconclusive

Verify shared dependencies configuration for optimal loading.

The Module Federation configuration is well-structured with correct runtime plugins for Node.js and appropriate singleton sharing. Please verify that the shared dependencies configuration works optimally with the plugin manager, particularly the non-eager loading of shared modules.


🏁 Script executed:

#!/bin/bash
# Description: Check how shared dependencies are configured in other plugin configurations
# Expected: Consistent shared dependency patterns across plugins

rg -A 5 -B 5 "shared.*singleton" --type js --type ts

Length of output: 54


Verify shared dependencies configuration for consistency

The ripgrep search didn’t find any other shared singleton configurations in the codebase. Please manually confirm that:

  • All Module Federation plugin configurations across packages use the same shared dependency settings.
  • Non-eager loading of shared modules works correctly with your plugin manager.

Key location to review:

  • packages/discord/rspack.config.cjs (lines 55–71)

Comment on lines +76 to +79
"@curatedotfun/discord": {
botToken: "{DISCORD_BOT_TOKEN}",
channelId: "123456789012345678",
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use placeholders and externalize sensitive defaults
Hardcoding the channelId ("123456789012345678") may expose production IDs. Use a placeholder like "{DISCORD_CHANNEL_ID}" or load defaults from environment variables. Similarly, ensure botToken remains a secret and isn’t shipped to the client unencrypted.

🤖 Prompt for AI Agents
In apps/plugin-manager/frontend/src/lib/plugin-context.tsx around lines 76 to
79, the channelId is hardcoded as "123456789012345678", which risks exposing
sensitive production IDs. Replace this with a placeholder string like
"{DISCORD_CHANNEL_ID}" or load it from environment variables to avoid leaking
secrets. Also, verify that botToken is handled securely and not exposed
unencrypted in the client code.

"@types/jest": "^29.5.14",
"typescript": "^5.0.0",
"vitest": "^3.0.7",
"discord.js": "^14.14.1"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Move discord.js to runtime dependencies.

Discord.js is currently listed as a devDependency, but it's required at runtime for the plugin to function properly when distributed.

Apply this diff to move discord.js to runtime dependencies:

   "devDependencies": {
     "@curatedotfun/types": "workspace:*",
     "@curatedotfun/utils": "workspace:*",
     "@rspack/cli": "latest",
     "@types/jest": "^29.5.14",
     "typescript": "^5.0.0",
-    "vitest": "^3.0.7",
-    "discord.js": "^14.14.1"
+    "vitest": "^3.0.7"
   },
   "dependencies": {
     "@module-federation/node": "^2.7.2",
-    "ws": "^8.16.0"
+    "ws": "^8.16.0",
+    "discord.js": "^14.14.1"
   }
📝 Committable suggestion

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

Suggested change
"discord.js": "^14.14.1"
"devDependencies": {
"@curatedotfun/types": "workspace:*",
"@curatedotfun/utils": "workspace:*",
"@rspack/cli": "latest",
"@types/jest": "^29.5.14",
"typescript": "^5.0.0",
"vitest": "^3.0.7"
},
"dependencies": {
"@module-federation/node": "^2.7.2",
"ws": "^8.16.0",
"discord.js": "^14.14.1"
}
🤖 Prompt for AI Agents
In packages/discord/package.json at line 47, discord.js is incorrectly listed
under devDependencies but is needed at runtime. Move the discord.js entry from
the devDependencies section to the dependencies section to ensure it is
installed and available when the plugin runs in production.

@elliotBraem elliotBraem merged commit 3246958 into main Jun 5, 2025
3 of 4 checks passed
@elliotBraem elliotBraem deleted the feat/discord-plugin branch June 5, 2025 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants