Skip to content

Conversation

@Coder-soft
Copy link
Owner

@Coder-soft Coder-soft commented Dec 6, 2025

Summary by CodeRabbit

  • Documentation

    • Added a complete docs site: homepage, API reference, getting-started, WebSocket events, site styling and theme toggle with persisted preference; included overview and quick-start.
  • New Features

    • Expanded real-time event coverage with many new event types and matching serialized payloads/types.
    • Enabled poll-related gateway intents to surface poll events.
  • Chores

    • Renamed product branding from "Discord Web Bridge" to "Holo Bridge" across docs and startup messages.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

Warning

Rate limit exceeded

@Coder-soft has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 13 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 33f4246 and 420d626.

📒 Files selected for processing (1)
  • src/discord/events/index.ts (7 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Rebrands to "Holo Bridge"; adds comprehensive static documentation (pages + stylesheet + llms.txt); expands Discord serializers and public Discord types; introduces many new Discord event handlers and payload types; adds poll gateway intents and updates startup log text. All changes are additive.

Changes

Cohort / File(s) Summary
Branding & Startup
\.env.example, README.md, src/index.ts
Updated branding from "Discord Web Bridge" to "Holo Bridge" in env header, README title/content and startup/log messages; README gained documentation links. No runtime config key changes.
Documentation — Pages
docs/index.html, docs/getting-started.html, docs/api-reference.html, docs/websocket.html
Added four full static documentation pages with content, examples, navigation, and a client-side theme toggle persisted to localStorage.
Documentation — Styling & Text
docs/styles.css, llms.txt
Added comprehensive docs stylesheet (dark/light theme, layout, components, responsive rules) and a plain-text overview llms.txt describing the project, endpoints, WebSocket usage, quick start, and file layout.
Discord Event Handlers
src/discord/events/index.ts
Added many new Discord event handlers (reactions/polls, userUpdate, channelPinsUpdate, webhookUpdate, thread events, emoji/sticker events, stage & scheduled events, auto-moderation events, interactions, invites, entitlements, etc.) that serialize payloads and broadcast via the existing mechanism.
Event Type Definitions
src/types/events.types.ts
Introduced numerous exported event interfaces (MessageReactionRemoveAllEvent, MessagePollVote*, UserUpdateEvent, Thread*, Emoji/Sticker, StageInstance*, GuildScheduledEvent*, AutoModeration*, InteractionCreateEvent, Invite*, Entitlement*, etc.), extended DiscordEventType and DiscordEventPayload unions, and removed deprecated guildEmojisUpdate.
Discord Serializers
src/discord/serializers.ts
Added many serializer functions and enum-to-name mappings (stickers, guild emojis, scheduled events, auto-mod rules/actions, stage instances, invites, audit log entries, interactions, entitlements, webhooks) producing JSON-safe Serialized* shapes.
Discord Public Types
src/types/discord.types.ts
Added exported Serialized* interfaces for Sticker, ScheduledEvent, AutoModRule, AutoModAction, StageInstance, Invite, AuditLogEntry, Interaction, Poll, Entitlement, Webhook and nested shapes used by serializers.
Gateway Intents
src/discord/client.ts
Added gateway intents for poll events: GuildMessagePolls and DirectMessagePolls. No other control-flow changes.
Misc / Manifest
package.json (manifest noted)
Manifest referenced; no functional changes indicated in diff.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay special attention to mapping consistency between:
    • src/discord/events/index.ts handlers and the event type strings declared in src/types/events.types.ts.
    • Serializer output shapes in src/discord/serializers.ts and the Serialized* interfaces in src/types/discord.types.ts.
  • Verify null/optional handling and guild-scoped vs global broadcast logic in event handlers.
  • Confirm added gateway intents in src/discord/client.ts are compatible with the discord library version and do not require permission changes.
  • Quick review of docs (docs/*.html, docs/styles.css) for broken links, theme-toggle persistence, and CSS regressions.

Poem

🐰 I hopped through types and stitched each line,
A bridge of holo-code, neat and fine.
Events now bloom, serializers hum,
Docs like carrots — oh what fun!
Hop along — the release is done. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Testingbranch' is vague and generic, providing no meaningful information about the substantial changes in this pull request, which include a project rename, extensive new event handlers, type definitions, serializers, and comprehensive documentation. Revise the title to clearly describe the main changes, such as 'Add Holo Bridge project rename, expanded Discord events support, and API documentation' or focus on the primary objective.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@Coder-soft
Copy link
Owner Author

@greptile review pls

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 6, 2025

Greptile Overview

Greptile Summary

This PR rebrands the project from "Discord Web Bridge" to "Holo Bridge" and significantly expands Discord event coverage from basic events to 45+ comprehensive event types including polls, automod, scheduled events, stage instances, and entitlements.

Major Changes:

  • Rebranded all references from "Discord Web Bridge" to "Holo Bridge" across codebase and documentation
  • Added poll event support with GuildMessagePolls and DirectMessagePolls intents
  • Expanded event handlers to cover 45+ Discord event types (messages, members, channels, threads, roles, guilds, emojis, stickers, voice, stage instances, scheduled events, automod, interactions, invites, entitlements)
  • Added comprehensive serialization functions for all new Discord entity types
  • Created complete documentation site with homepage, getting started guide, API reference, and WebSocket event reference
  • Added theme toggle with dark/light mode support in documentation

Issues Found:

  • Poll event handlers (messagePollVoteAdd, messagePollVoteRemove) broadcast empty strings when poll?.message is undefined instead of skipping the event or handling gracefully

Confidence Score: 4/5

  • This PR is mostly safe to merge with one logical issue in poll event handlers that should be addressed
  • Score reflects well-structured code expansion with comprehensive type safety and serialization, but poll event handlers have a logic bug where empty strings are broadcast instead of proper null handling when message data is unavailable. The rest of the changes are clean branding updates and documentation additions.
  • src/discord/events/index.ts requires attention for poll event handler null safety on lines 182-212

Important Files Changed

File Analysis

Filename Score Overview
src/index.ts 5/5 Updated console messages to use "Holo Bridge" branding
src/discord/client.ts 5/5 Added poll intents (GuildMessagePolls, DirectMessagePolls) for poll event support
src/discord/events/index.ts 4/5 Expanded event handlers with 45+ event types including poll, automod, scheduled events, stage instances, and entitlements. Poll events access nullable properties without null checks on lines 184-200
src/discord/serializers.ts 5/5 Added comprehensive serialization functions for new Discord features (stickers, scheduled events, automod, stage instances, invites, audit logs, interactions, entitlements, webhooks)
src/types/discord.types.ts 5/5 Added type definitions for new serialized Discord entities (stickers, scheduled events, automod, stage instances, invites, audit logs, interactions, polls, entitlements, webhooks)
src/types/events.types.ts 5/5 Extended event type system with 45+ new event payload definitions for comprehensive Discord event coverage

Sequence Diagram

sequenceDiagram
    participant Discord as Discord Gateway
    participant Client as Discord Client
    participant Events as Event Handlers
    participant Serializers as Serializers
    participant Broadcast as Socket.IO
    participant WebClient as Web Clients

    Discord->>Client: Event (messageCreate, etc.)
    Client->>Events: Trigger event handler
    Events->>Serializers: Serialize Discord objects
    Serializers-->>Events: JSON-safe data
    Events->>Events: Create event payload
    Events->>Broadcast: broadcastEvent(payload)
    alt Guild-specific event
        Broadcast->>WebClient: Emit to guild:${guildId} room
    else Global/DM event
        Broadcast->>WebClient: Emit to all clients
    end
    Note over WebClient: Receives 'discord' event
    Note over Events: 45+ event types supported
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

9 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +74 to +77
<a href="https://github.com" class="card" target="_blank">
<h4>💻 Source Code</h4>
<p>View the source code on GitHub.</p>
</a>
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Link points to generic https://github.com instead of the actual repository

Suggested change
<a href="https://github.com" class="card" target="_blank">
<h4>💻 Source Code</h4>
<p>View the source code on GitHub.</p>
</a>
<a href="https://github.com/coder-soft/holobridge" class="card" target="_blank">
<h4>💻 Source Code</h4>
<p>View the source code on GitHub.</p>
</a>
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/index.html
Line: 74:77

Comment:
**style:** Link points to generic `https://github.com` instead of the actual repository

```suggestion
                <a href="https://github.com/coder-soft/holobridge" class="card" target="_blank">
                    <h4>💻 Source Code</h4>
                    <p>View the source code on GitHub.</p>
                </a>
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
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 (5)
README.md (1)

1-1: Branding + docs link look good; consider adding a one‑liner about what’s at the docs URL

The rename to “Holo Bridge” and the new documentation link are consistent and helpful. You might optionally add a short description (e.g., “full API reference and getting‑started guide”) next to the link so readers know what to expect without clicking.

Also applies to: 106-108

.env.example (1)

1-1: Env header rename is fine; optionally remind users about secret safety

The header now matches the Holo Bridge branding, which is good. You might optionally add a brief comment below it like “Do not commit this file with real tokens/API keys” to nudge users toward safe handling of secrets.

llms.txt (1)

21-76: Align path parameter names with the HTML API reference for clarity

The endpoint list is solid, but here you use generic :id in several routes (e.g., /api/guilds/:id, /api/guilds/:id/roles) while docs/api-reference.html standardizes on :guildId, :roleId, etc. For humans and LLMs this small mismatch can be confusing.

I’d recommend updating llms.txt to match the more explicit parameter names from the HTML docs (e.g., :guildId, :channelId, :roleId) so all documentation tells the same story.

docs/index.html (1)

74-77: Point “Source Code” to this repository instead of the GitHub root

The docs page looks good. For the “💻 Source Code” card, consider updating the href from https://github.com to this project’s repo URL (e.g., https://github.com/Coder-soft/HoloBridge) so users land directly on the right codebase.

docs/getting-started.html (1)

21-21: Add accessible label to theme toggle button.

The theme toggle button lacks descriptive text or an aria-label for screen readers, making it unclear what the button does to users with assistive technologies.

-                <button class="theme-toggle" onclick="toggleTheme()">Toggle Theme</button>
+                <button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle between light and dark theme">🌙</button>

Alternatively, you can add a tooltip or visible text alongside the button to improve discoverability for all users.

Also applies to: 164-179

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f3d7ce and 188252d.

📒 Files selected for processing (9)
  • .env.example (1 hunks)
  • README.md (2 hunks)
  • docs/api-reference.html (1 hunks)
  • docs/getting-started.html (1 hunks)
  • docs/index.html (1 hunks)
  • docs/styles.css (1 hunks)
  • docs/websocket.html (1 hunks)
  • llms.txt (1 hunks)
  • src/index.ts (2 hunks)
🔇 Additional comments (3)
src/index.ts (1)

6-7: Startup log renaming is consistent and safe

Only user‑facing messages were updated to “Holo Bridge”; behavior and error handling stay the same. Looks good.

Also applies to: 23-25

docs/styles.css (1)

1-498: Theme and docs styling are cohesive with no obvious issues

The light/dark theme variables, layout, and docs‑specific components (cards, sidebar, tables, alerts) are structured cleanly and line up with how the HTML pages use them. I don’t see any functional or structural CSS problems here.

docs/api-reference.html (1)

26-773: API reference is accurate and fully synchronized with route implementations

All documented endpoints—including threads (create, list, archive, lock), bulk delete, role permissions, and member moderation (kick, ban, unban, timeout)—are correctly implemented and match the documentation. No drift detected.

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Copy link
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: 0

🧹 Nitpick comments (1)
docs/getting-started.html (1)

39-41: Add <pre><code> wrapper for consistency with other code examples.

The git clone commands on lines 40-41 are missing the <pre><code> wrapper, while all other code examples in the document (npm install, npm run commands, etc.) use it. This inconsistency affects styling and readability.

             <h3>1. Clone the Repository</h3>
+            <pre><code>git clone https://github.com/coder-soft/holobridge.git
-git clone https://github.com/coder-soft/holobridge.git
-cd holobridge
+cd holobridge</code></pre>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 188252d and 50b7f1e.

📒 Files selected for processing (1)
  • docs/getting-started.html (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.30.0)
docs/getting-started.html

[high] 139-141: Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource.

(curl-auth-header)

🔇 Additional comments (1)
docs/getting-started.html (1)

139-141: Clarify placeholder in curl documentation example.

Static analysis flagged this curl command as containing a potential authorization token. This is a false positive—your_api_key is clearly a placeholder for documentation purposes. To further signal this is an example, consider adding a comment in the example or using a more explicit placeholder name if desired, though the current form is acceptable and conventional for documentation.

Copy link
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50b7f1e and 27b079c.

📒 Files selected for processing (3)
  • docs/websocket.html (1 hunks)
  • src/discord/events/index.ts (1 hunks)
  • src/types/events.types.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/types/events.types.ts (1)
src/types/discord.types.ts (1)
  • SerializedChannel (50-63)
src/discord/events/index.ts (2)
src/discord/client.ts (1)
  • discordClient (9-44)
src/discord/serializers.ts (1)
  • serializeChannel (116-146)
🔇 Additional comments (5)
docs/websocket.html (1)

322-392: Thread events documentation is now accurate and complete!

The previous critical issue regarding undocumented/unimplemented thread events has been resolved. The documentation now correctly describes the four thread events (threadCreate, threadUpdate, threadDelete, threadMembersUpdate) that are implemented in src/discord/events/index.ts, and the data shapes match the type definitions in src/types/events.types.ts.

The examples are clear and accurate:

  • Thread create includes thread and newlyCreated flag
  • Thread update shows old and new structure
  • Thread delete provides essential identifiers
  • Thread members update correctly documents the member tracking structure
src/types/events.types.ts (2)

181-225: Well-defined thread event payload types.

The four new thread event interfaces are correctly structured and align perfectly with the implementation in src/discord/events/index.ts:

  • Consistent with existing event payload patterns
  • Appropriate nullable types for old values and optional fields
  • Thread-specific data structures properly capture Discord.js thread event details

332-335: Union type correctly extended.

The DiscordEventPayload union properly includes all four new thread event types, maintaining type safety for WebSocket event broadcasting.

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

220-254: Thread create, update, and delete handlers are well-implemented.

The three handlers correctly:

  • Follow the established event broadcasting pattern
  • Use serializeChannel to transform Discord.js thread objects
  • Handle partial objects appropriately in threadUpdate
  • Extract relevant fields in threadDelete for deleted threads

218-272: Thread event handlers successfully implemented.

All four thread event handlers are now registered and broadcasting events correctly. This resolves the documentation inconsistency flagged in the previous review of docs/websocket.html.

Comment on lines 256 to 272
discordClient.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => {
broadcastEvent({
event: 'threadMembersUpdate',
guildId: thread.guildId,
data: {
threadId: thread.id,
guildId: thread.guildId,
addedMembers: addedMembers.map((m) => ({
id: m.id,
threadId: m.thread?.id ?? thread.id,
joinedAt: m.joinTimestamp ? new Date(m.joinTimestamp).toISOString() : new Date().toISOString(),
})),
removedMemberIds: removedMembers.map((m) => m.id),
memberCount: thread.memberCount ?? 0,
},
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider more explicit handling for missing joinTimestamp.

Line 266 uses new Date() as a fallback when m.joinTimestamp is falsy, which could create misleading timestamps that don't reflect when members actually joined the thread. Consider whether it's better to use null or a sentinel value to indicate unknown join times, or verify that joinTimestamp is always present in Discord.js ThreadMember objects.

-                    joinedAt: m.joinTimestamp ? new Date(m.joinTimestamp).toISOString() : new Date().toISOString(),
+                    joinedAt: new Date(m.joinTimestamp ?? Date.now()).toISOString(),

Alternatively, if joinTimestamp can genuinely be null/undefined, document this behavior or make joinedAt nullable in the type definition.

📝 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
discordClient.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => {
broadcastEvent({
event: 'threadMembersUpdate',
guildId: thread.guildId,
data: {
threadId: thread.id,
guildId: thread.guildId,
addedMembers: addedMembers.map((m) => ({
id: m.id,
threadId: m.thread?.id ?? thread.id,
joinedAt: m.joinTimestamp ? new Date(m.joinTimestamp).toISOString() : new Date().toISOString(),
})),
removedMemberIds: removedMembers.map((m) => m.id),
memberCount: thread.memberCount ?? 0,
},
});
});
discordClient.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => {
broadcastEvent({
event: 'threadMembersUpdate',
guildId: thread.guildId,
data: {
threadId: thread.id,
guildId: thread.guildId,
addedMembers: addedMembers.map((m) => ({
id: m.id,
threadId: m.thread?.id ?? thread.id,
joinedAt: new Date(m.joinTimestamp ?? Date.now()).toISOString(),
})),
removedMemberIds: removedMembers.map((m) => m.id),
memberCount: thread.memberCount ?? 0,
},
});
});
🤖 Prompt for AI Agents
In src/discord/events/index.ts around lines 256 to 272, the current fallback for
missing m.joinTimestamp uses new Date(), producing misleading "now" timestamps;
change the emitted joinedAt to be nullable (e.g., joinedAt: m.joinTimestamp ?
new Date(m.joinTimestamp).toISOString() : null) and update any related
TypeScript types/DTOs and documentation to accept null for joinedAt (or choose a
clear sentinel), or alternatively validate that ThreadMember.joinTimestamp is
always present before emitting and omit the field when unknown.

Copy link
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: 4

♻️ Duplicate comments (1)
src/discord/events/index.ts (1)

364-380: Consider more explicit handling for missing joinTimestamp.

Line 374 uses new Date().toISOString() as a fallback when m.joinedTimestamp is falsy, which could create misleading timestamps that don't reflect when members actually joined the thread.

This was flagged in a previous review. Consider using null for unknown join times or verifying that joinedTimestamp is always present in Discord.js ThreadMember objects.

🧹 Nitpick comments (6)
src/discord/events/index.ts (2)

597-619: Scheduled event handlers use type assertions that may mask type errors.

The as any casts on lines 600, 607, and 617 bypass TypeScript's type checking. If the event object is partial and missing required fields, serializeScheduledEvent may throw or produce incorrect output.

Consider adding explicit partial checks similar to other handlers:

 discordClient.on('guildScheduledEventDelete', (event) => {
-    // event may be partial, but we still want to broadcast the deletion
+    if (event.partial) {
+        // For partial events, emit minimal deletion info
+        broadcastEvent({
+            event: 'guildScheduledEventDelete',
+            guildId: event.guildId,
+            data: { id: event.id, guildId: event.guildId, partial: true },
+        });
+        return;
+    }
     broadcastEvent({
         event: 'guildScheduledEventDelete',
         guildId: event.guildId,
-        data: serializeScheduledEvent(event as any),
+        data: serializeScheduledEvent(event),
     });
 });

739-753: Entitlement update handler discards old entitlement data.

Unlike other update handlers that emit { old, new } structure, entitlementUpdate only serializes newEntitlement. This inconsistency may confuse consumers expecting the standard update payload format.

For consistency with other update events:

 discordClient.on('entitlementUpdate', (oldEntitlement, newEntitlement) => {
     broadcastEvent({
         event: 'entitlementUpdate',
         guildId: newEntitlement.guildId,
-        data: serializeEntitlement(newEntitlement),
+        data: {
+            old: oldEntitlement ? serializeEntitlement(oldEntitlement) : null,
+            new: serializeEntitlement(newEntitlement),
+        },
     });
 });
src/discord/serializers.ts (3)

320-343: Imports placed mid-file break conventional module structure.

The additional imports are added after existing code (line 320-343) rather than at the top of the file with other imports. This works in TypeScript but deviates from standard conventions.

Consider moving these imports to the top of the file with the existing imports for better organization:

 import {
     Guild,
     GuildMember,
     User,
     // ... existing imports
+    Sticker,
+    GuildScheduledEvent,
+    AutoModerationRule,
+    // ... new imports
 } from 'discord.js';

450-450: Fallback to current date may produce misleading timestamps.

Lines 450 and 464 use new Date().toISOString() when scheduledStartAt or createdAt is undefined. This could create confusing data where timestamps don't reflect actual Discord values.

Consider using null to explicitly indicate missing data:

-scheduledStartTime: event.scheduledStartAt?.toISOString() ?? new Date().toISOString(),
+scheduledStartTime: event.scheduledStartAt?.toISOString() ?? null,
 // ...
-createdAt: event.createdAt?.toISOString() ?? new Date().toISOString(),
+createdAt: event.createdAt?.toISOString() ?? null,

Note: This would require updating SerializedScheduledEvent.scheduledStartTime and createdAt types to accept string | null.

Also applies to: 464-464


631-645: Entitlement createdAt uses synthetic current timestamp.

Line 643 assigns new Date().toISOString() with a comment noting "Entitlement doesn't have createdAt directly". This synthetic timestamp doesn't reflect when the entitlement was actually created.

Consider either:

  1. Using null to indicate the value isn't available
  2. Using the entitlement's startsAt as a proxy if appropriate
  3. Documenting this behavior clearly in the type definition
-createdAt: new Date().toISOString(), // Entitlement doesn't have createdAt directly
+createdAt: entitlement.startsAt?.toISOString() ?? null, // No direct createdAt available
src/types/events.types.ts (1)

336-350: Consider whether guildId in nested data should be non-nullable.

The data.guildId is typed as string (non-nullable) while the top-level guildId is string | null. Thread member updates only occur in guild contexts, so the nested guildId: string is correct, but the top-level guildId could also be string for consistency.

This is a minor inconsistency that doesn't affect functionality since thread member updates are guild-only events.

 export interface ThreadMembersUpdateEvent {
     event: 'threadMembersUpdate';
-    guildId: string | null;
+    guildId: string;
     data: {
         threadId: string;
         guildId: string;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 27b079c and 627a812.

📒 Files selected for processing (6)
  • docs/websocket.html (1 hunks)
  • src/discord/client.ts (1 hunks)
  • src/discord/events/index.ts (7 hunks)
  • src/discord/serializers.ts (1 hunks)
  • src/types/discord.types.ts (1 hunks)
  • src/types/events.types.ts (10 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/discord/events/index.ts (1)
src/discord/serializers.ts (12)
  • serializeUser (67-79)
  • serializeChannel (116-146)
  • serializeAuditLogEntry (555-578)
  • serializeGuildEmoji (429-439)
  • serializeSticker (410-427)
  • serializeStageInstance (524-535)
  • serializeScheduledEvent (441-466)
  • serializeAutoModRule (468-498)
  • serializeAutoModAction (500-522)
  • serializeInteraction (580-629)
  • serializeInvite (537-553)
  • serializeEntitlement (631-645)
src/discord/serializers.ts (1)
src/types/discord.types.ts (11)
  • SerializedSticker (222-237)
  • SerializedEmoji (65-73)
  • SerializedScheduledEvent (243-266)
  • SerializedAutoModRule (272-300)
  • SerializedAutoModAction (302-322)
  • SerializedStageInstance (328-337)
  • SerializedInvite (343-357)
  • SerializedAuditLogEntry (363-379)
  • SerializedInteraction (385-405)
  • SerializedEntitlement (435-447)
  • SerializedWebhook (453-468)
src/types/events.types.ts (1)
src/types/discord.types.ts (12)
  • SerializedUser (7-17)
  • SerializedChannel (50-63)
  • SerializedAuditLogEntry (363-379)
  • SerializedEmoji (65-73)
  • SerializedSticker (222-237)
  • SerializedStageInstance (328-337)
  • SerializedScheduledEvent (243-266)
  • SerializedAutoModRule (272-300)
  • SerializedAutoModAction (302-322)
  • SerializedInteraction (385-405)
  • SerializedInvite (343-357)
  • SerializedEntitlement (435-447)
🔇 Additional comments (13)
src/discord/events/index.ts (2)

259-270: User update handler correctly handles partial old user.

The userUpdate event appropriately checks for partial state before serializing the old user, and correctly sets guildId: null since this is a global user update event.


13-23: Event handler registration is comprehensive and well-structured.

The expanded imports and 45+ event handlers are properly organized by category with clear section comments. The registration message accurately reflects the scope of coverage.

Also applies to: 755-755

src/types/discord.types.ts (2)

385-405: SerializedInteraction includes sensitive token field.

The token field on line 393 allows responding to Discord interactions. Including this in a serialized type intended for API responses could pose security risks if exposed to unauthorized clients.

Verify that interaction payloads are only sent to authorized, trusted clients and consider whether the token should be included or redacted.


217-468: New serialized types are well-designed and comprehensive.

The type definitions properly handle:

  • Nullable fields with | null
  • Human-readable name fields alongside numeric enum values
  • Nested object structures for metadata
  • Consistent field naming conventions
src/discord/serializers.ts (1)

410-439: New serializers are well-implemented with proper null handling.

The serializers for stickers, emoji, automod rules/actions, stage instances, invites, and webhooks correctly:

  • Handle optional/nullable fields
  • Use spread operators to clone arrays (avoiding mutation)
  • Include human-readable name fields via lookup maps
  • Check for nested object existence before accessing properties

Also applies to: 468-522, 524-553, 647-676

docs/websocket.html (1)

1-944: Documentation accurately reflects all implemented WebSocket events.

All 60 documented events are confirmed to exist in src/discord/events/index.ts. The Socket.IO integration, event serialization, authentication, and subscription handling are properly implemented. The theme toggle functionality correctly manages localStorage persistence and system preference detection. No corrections needed.

src/discord/client.ts (1)

35-37: Poll intents correctly added to enable poll events.

The GuildMessagePolls and DirectMessagePolls intents are required for receiving poll-related events (messagePollVoteAdd, messagePollVoteRemove), which aligns with the new poll event handlers added in this PR.

src/types/events.types.ts (6)

1-21: LGTM!

The imports are well-organized and all necessary serialized types are imported for the new event definitions. Each import corresponds to a type that's properly used in the new event interfaces.


167-210: LGTM!

The new message event interfaces follow consistent patterns:

  • MessageReactionRemoveAllEvent and MessageReactionRemoveEmojiEvent correctly mirror Discord's gateway events
  • MessagePollVoteAddEvent and MessagePollVoteRemoveEvent properly type answerId as number (matching Discord's poll answer ID type)
  • All events correctly use guildId: string | null to support DM contexts

249-256: LGTM!

UserUpdateEvent correctly types guildId as literal null rather than string | null since user updates are global events not tied to any specific guild. The old/new pattern with Partial<SerializedUser> | null is consistent with other update events.


676-752: LGTM!

The DiscordEventPayload union is complete and well-organized. All event interfaces are included and properly categorized with comments matching the DiscordEventType union structure. This ensures type safety when handling Discord events.


27-102: LGTM!

The DiscordEventType union is comprehensive and well-organized with clear category comments. All new Discord gateway events (polls, webhooks, audit logs, emojis, stickers, stage instances, scheduled events, auto-moderation, invites, and entitlements) are properly included.


660-664: Inconsistent entitlement update event pattern — unable to fix due to API limitation.

EntitlementUpdateEvent doesn't follow the old/new pattern used by other update events (EmojiUpdateEvent, StickerUpdateEvent, GuildScheduledEventUpdateEvent, etc.). However, Discord's API provides only the current entitlement object in update payloads, not the previous state. This inconsistency cannot be resolved without Discord API providing historical entitlement data. The type system correctly reflects the API's actual behavior.

Comment on lines +697 to +705
// ========== INTERACTION EVENT ==========

discordClient.on('interactionCreate', (interaction) => {
broadcastEvent({
event: 'interactionCreate',
guildId: interaction.guildId,
data: serializeInteraction(interaction),
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Interaction token exposed in serialized payload.

The serializeInteraction function includes the interaction token field, which is sensitive and could potentially be misused if exposed to unauthorized clients. Interaction tokens allow responding to interactions.

Consider omitting or redacting the token in the broadcast payload, or ensure only authorized clients receive this data:

// In serializeInteraction or when broadcasting
-token: interaction.token,
+token: '[REDACTED]', // Or omit entirely

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/discord/events/index.ts around lines 697 to 705, the serialized
interaction sent to broadcastEvent currently includes the interaction.token
which is sensitive; remove or redact the token from the payload by changing
serializeInteraction to exclude the token (or return a copy with token set to
null/'[REDACTED]') before broadcasting, or add a conditional so token is only
included when the recipient is explicitly authorized; ensure the broadcastEvent
call uses the sanitized object so no raw interaction.token is emitted.

Comment on lines +555 to +578
export function serializeAuditLogEntry(entry: GuildAuditLogsEntry): SerializedAuditLogEntry {
// Handle partial executor
let executorSerialized = null;
if (entry.executor && !('partial' in entry.executor && entry.executor.partial)) {
executorSerialized = serializeUser(entry.executor as any);
}
return {
id: entry.id,
guildId: entry.targetId ?? '', // Best effort
actionType: entry.action,
actionTypeName: AuditLogEvent[entry.action] ?? 'unknown',
targetId: entry.targetId,
executorId: entry.executorId,
executor: executorSerialized,
reason: entry.reason ?? null,
changes: entry.changes.map(change => ({
key: change.key,
old: change.old,
new: change.new,
})),
extra: entry.extra,
createdAt: entry.createdAt.toISOString(),
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Audit log entry guildId fallback to targetId may be incorrect.

Line 563 uses entry.targetId ?? '' for guildId, but targetId is the ID of the target entity (user, channel, role, etc.), not the guild. This could produce incorrect guild associations.

The guildId should come from the guild context when the handler calls this serializer. Consider accepting it as a parameter:

-export function serializeAuditLogEntry(entry: GuildAuditLogsEntry): SerializedAuditLogEntry {
+export function serializeAuditLogEntry(entry: GuildAuditLogsEntry, guildId: string): SerializedAuditLogEntry {
     // ...
     return {
         id: entry.id,
-        guildId: entry.targetId ?? '', // Best effort
+        guildId,
         // ...
     };
 }

Then update the event handler to pass the guild ID from the event context.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +580 to +629
export function serializeInteraction(interaction: Interaction): SerializedInteraction {
const base: SerializedInteraction = {
id: interaction.id,
type: interaction.type,
typeName: interactionTypeNames[interaction.type] ?? 'unknown',
guildId: interaction.guildId,
channelId: interaction.channelId,
user: serializeUser(interaction.user),
member: interaction.member && 'id' in interaction.member
? serializeMember(interaction.member as GuildMember)
: null,
token: interaction.token,
applicationId: interaction.applicationId,
commandName: null,
commandId: null,
commandType: null,
customId: null,
componentType: null,
values: null,
targetId: null,
locale: interaction.locale,
guildLocale: interaction.guildLocale ?? null,
createdAt: interaction.createdAt.toISOString(),
};

if (interaction.isCommand()) {
base.commandName = interaction.commandName;
base.commandId = interaction.commandId;
base.commandType = interaction.commandType;
}

if (interaction.isMessageComponent()) {
base.customId = interaction.customId;
base.componentType = interaction.componentType;
}

if (interaction.isAnySelectMenu()) {
base.values = interaction.values;
}

if (interaction.isContextMenuCommand()) {
base.targetId = interaction.targetId;
}

if (interaction.isModalSubmit()) {
base.customId = interaction.customId;
}

return base;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Interaction serializer includes sensitive token - security concern.

Line 591 includes interaction.token in the serialized output. This token allows responding to Discord interactions and should be treated as sensitive data.

If this data is broadcast to potentially untrusted clients, the token should be redacted or omitted:

-token: interaction.token,
+token: '[REDACTED]', // Tokens are sensitive and should not be exposed

If legitimate use cases require the token, ensure the broadcast mechanism restricts access appropriately.

🤖 Prompt for AI Agents
In src/discord/serializers.ts around lines 580 to 629, the serializer currently
includes interaction.token (sensitive) in the serialized object; remove or
redact the token by omitting interaction.token from the returned object (or
replace with a constant like "[REDACTED]") and, if there is a legitimate
internal need to include it, add an explicit opt-in parameter (e.g.
includeSensitive?: boolean) that defaults to false and only includes the raw
token when true and only used in trusted/internal code paths; ensure any callers
that relied on the token are updated to use the opt-in flag and audit broadcast
paths so the token is never sent to untrusted clients.

@Coder-soft
Copy link
Owner Author

@greptile pls review

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

14 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Coder-soft and others added 2 commits December 6, 2025 22:24
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Copy link
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

♻️ Duplicate comments (3)
src/discord/events/index.ts (3)

182-216: Previous concerns addressed.

The poll vote handlers now correctly validate that message exists before broadcasting, eliminating the empty string issue raised in earlier reviews. The implementation is now safe.


368-384: Still using misleading fallback for missing joinTimestamp.

Line 378 uses new Date().toISOString() when joinedTimestamp is missing, creating timestamps that falsely suggest members joined at the current moment rather than their actual join time.

Apply this diff to use null for unknown join times:

                 addedMembers: addedMembers.map((m) => ({
                     id: m.id,
                     threadId: m.thread?.id ?? thread.id,
-                    joinedAt: m.joinedTimestamp ? new Date(m.joinedTimestamp).toISOString() : new Date().toISOString(),
+                    joinedAt: m.joinedTimestamp ? new Date(m.joinedTimestamp).toISOString() : null,
                 })),

You'll also need to update the corresponding TypeScript type to make joinedAt nullable.


701-709: Interaction token still exposed (security risk).

The serialized interaction includes the sensitive token field, as flagged in previous reviews. Interaction tokens allow responding to interactions and should not be broadcast to potentially unauthorized clients.

Modify serializeInteraction in src/discord/serializers.ts to omit or redact the token:

     return {
         id: interaction.id,
         type: interaction.type,
         // ... other fields
-        token: interaction.token,
+        // token: interaction.token, // Omitted for security
         applicationId: interaction.applicationId,
         // ... rest of fields
     };

Alternatively, if the token is needed for specific authorized use cases, add a parameter to control whether it's included and ensure only authorized clients receive it.

🧹 Nitpick comments (1)
src/discord/events/index.ts (1)

743-748: Consider including old entitlement data for consistency.

The entitlementUpdate handler only serializes the new entitlement, while most other update handlers throughout the file include both old and new data. If oldEntitlement is available and useful, consider including it to maintain consistency:

     discordClient.on('entitlementUpdate', (oldEntitlement, newEntitlement) => {
         broadcastEvent({
             event: 'entitlementUpdate',
             guildId: newEntitlement.guildId,
-            data: serializeEntitlement(newEntitlement),
+            data: {
+                old: oldEntitlement ? serializeEntitlement(oldEntitlement) : null,
+                new: serializeEntitlement(newEntitlement),
+            },
         });
     });

Alternatively, if the old entitlement data is not needed by consumers, document why this handler differs from the standard update pattern.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 627a812 and 33f4246.

📒 Files selected for processing (1)
  • src/discord/events/index.ts (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/discord/events/index.ts (1)
src/discord/serializers.ts (12)
  • serializeUser (67-79)
  • serializeChannel (116-146)
  • serializeAuditLogEntry (555-578)
  • serializeGuildEmoji (429-439)
  • serializeSticker (410-427)
  • serializeStageInstance (524-535)
  • serializeScheduledEvent (441-466)
  • serializeAutoModRule (468-498)
  • serializeAutoModAction (500-522)
  • serializeInteraction (580-629)
  • serializeInvite (537-553)
  • serializeEntitlement (631-645)
🔇 Additional comments (8)
src/discord/events/index.ts (8)

154-180: LGTM! Clean implementation of reaction removal events.

Both handlers follow the established broadcasting pattern and correctly extract the necessary identifiers from the event parameters.


263-274: LGTM! Correct handling of global user updates.

Appropriately treats user updates as global events (guildId: null) and handles partial old user data safely.


305-328: LGTM! Proper handling of channel pin and webhook events.

Both handlers correctly manage nullable values and appropriately filter events (webhookUpdate skips non-guild channels).


330-366: LGTM! Thread event handlers are well-structured.

All three handlers appropriately handle thread lifecycle events and safely manage partial data in the update handler.


473-489: LGTM! Appropriate handling of guild integration and audit log events.

Both handlers work within the constraints of the Discord.js event data, with audit log serialization safely handling partial executor data.


562-647: LGTM! Stage and scheduled event handlers are well-implemented.

The handlers appropriately manage partial data and use type assertions where necessary to work with Discord.js's partial event objects.


649-684: LGTM! AutoMod event handlers are correctly implemented.

All four handlers properly serialize auto-moderation data and handle nullable old values in the update handler.


759-759: LGTM! Helpful registration confirmation message.

The log message provides clear feedback about the event registration, making it easy to verify the system is properly initialized.

Comment on lines +520 to +547
// ========== STICKER EVENTS ==========

discordClient.on('stickerCreate', (sticker) => {
broadcastEvent({
event: 'stickerCreate',
guildId: sticker.guildId ?? '',
data: serializeSticker(sticker),
});
});

discordClient.on('stickerUpdate', (oldSticker, newSticker) => {
broadcastEvent({
event: 'stickerUpdate',
guildId: newSticker.guildId ?? '',
data: {
old: serializeSticker(oldSticker),
new: serializeSticker(newSticker),
},
});
});

discordClient.on('stickerDelete', (sticker) => {
broadcastEvent({
event: 'stickerDelete',
guildId: sticker.guildId ?? '',
data: serializeSticker(sticker),
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use null instead of empty string for missing guildId.

Lines 525, 533, and 544 use sticker.guildId ?? '', which creates type inconsistency. While guild stickers typically have a guildId, the fallback should be null to match the pattern used throughout the codebase for optional guild associations.

Apply this diff:

     discordClient.on('stickerCreate', (sticker) => {
         broadcastEvent({
             event: 'stickerCreate',
-            guildId: sticker.guildId ?? '',
+            guildId: sticker.guildId ?? null,
             data: serializeSticker(sticker),
         });
     });

     discordClient.on('stickerUpdate', (oldSticker, newSticker) => {
         broadcastEvent({
             event: 'stickerUpdate',
-            guildId: newSticker.guildId ?? '',
+            guildId: newSticker.guildId ?? null,
             data: {
                 old: serializeSticker(oldSticker),
                 new: serializeSticker(newSticker),
             },
         });
     });

     discordClient.on('stickerDelete', (sticker) => {
         broadcastEvent({
             event: 'stickerDelete',
-            guildId: sticker.guildId ?? '',
+            guildId: sticker.guildId ?? null,
             data: serializeSticker(sticker),
         });
     });
🤖 Prompt for AI Agents
In src/discord/events/index.ts around lines 520 to 547, the sticker event
handlers use `sticker.guildId ?? ''`, which introduces an empty-string fallback
and conflicts with the codebase pattern of using `null` for missing guild
associations; change each fallback to `null` so `guildId: sticker.guildId ??
null` for stickerCreate (line ~525), stickerUpdate (line ~533 using
newSticker.guildId), and stickerDelete (line ~544) to maintain consistent typing
and semantics.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Coder-soft Coder-soft merged commit 35ff513 into master Dec 6, 2025
1 check passed
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