Skip to content

feat(bot): add reusable embed builder helpers - #503

Merged
LucasSantana-Dev merged 4 commits into
mainfrom
feat/bot-reusable-embeds
Apr 9, 2026
Merged

LucasSantana-Dev merged 4 commits into
mainfrom
feat/bot-reusable-embeds

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Apr 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

Phase 1 of v2.6.66 command response polish wave — shared embed builders that Phases 2-5 will build on.

New helpers in packages/bot/src/utils/general/responseEmbeds/:

  • buildTrackEmbed(track, kind, requestedBy?) — track display for /queue show, /songinfo, /history, /recommendation show. Kinds: playing | queued | recommended | history. Platform colors (Spotify/YouTube/SoundCloud/Apple Music/Vimeo).
  • buildUserProfileEmbed(user, stats?) — avatar + XP/level/rank/progress bar for /level rank, /lastfm status.
  • buildListPageEmbed(items, page, config) — fields-per-item paginated list with Page N/M footer for /level leaderboard, /cases, /starboard top, etc.
  • buildPlatformAttribEmbed(platform, body) — Last.fm/Spotify/YouTube branding for /lastfm link|status, /songinfo.

Test plan

  • 56 new unit tests (4 spec files), all passing
  • Build clean
  • Mirror pattern from nowPlayingEmbed.spec.ts

Summary by CodeRabbit

  • New Features

    • Added paginated list display with customizable items per page and empty state messaging
    • Added platform-specific branding for music services (Spotify, YouTube, Last.fm)
    • Added track information display with source detection and requester attribution
    • Added user profile display with stats, levels, ranks, and XP progress visualization
  • Tests

    • Added comprehensive test coverage for all new display utilities

- buildTrackEmbed: general-purpose track display with source detection
- buildUserProfileEmbed: user stat snapshot with progress bars
- buildListPageEmbed: paginated list helper with field-per-item layout
- buildPlatformAttribEmbed: external service branding (Last.fm, Spotify, YouTube)

All helpers include comprehensive unit tests covering edge cases and variants.
@coderabbitai

coderabbitai Bot commented Apr 9, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@LucasSantana-Dev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 5 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 8 minutes and 5 seconds.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a2f16e8e-8f3a-4568-b29b-05fb6c64c8c6

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec69e8 and 53e2204.

📒 Files selected for processing (3)
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
📝 Walkthrough

Walkthrough

Introduces four new Discord embed builder utilities with comprehensive test coverage: paginated list embeds, platform-attributed embeds with branding, music track embeds with source detection, and user profile embeds displaying stats with progress bars. Each module is paired with Jest tests verifying functionality.

Changes

Cohort / File(s) Summary
Track Embed Builder
packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts, buildTrackEmbed.spec.ts
New utility for constructing Discord embeds for music tracks, featuring source detection via URL/source mapping (YouTube, Spotify, SoundCloud), configurable embed context (queued, playing, recommended, history), and conditional fields for duration and requester attribution.
User Profile Embed Builder
packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts, buildUserProfileEmbed.spec.ts
New utility for building user profile embeds with optional stats (level, rank, XP), including computed XP progress bars and fallback messaging when stats are unavailable.
List Page Embed Builder
packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts, buildListPageEmbed.spec.ts
New utility for paginated list embeds, supporting configurable items-per-page, dynamic page footer formatting, and customizable empty-state messaging.
Platform Attribution Embed Builder
packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts, buildPlatformAttribEmbed.spec.ts
New utility for platform-specific embeds (Last.fm, Spotify, YouTube) with branding (emoji + label) and platform-specific colors, conditionally rendering title, description, thumbnail, and URL fields.
Module Exports
packages/bot/src/utils/general/responseEmbeds/index.ts
New barrel export exposing all four embed builders and associated type definitions for public consumption.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Suggested labels

bot, size/l

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(bot): add reusable embed builder helpers' directly and clearly describes the main change: adding new reusable embed builder utility functions for the bot package.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/bot-reusable-embeds

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.

@vercel

vercel Bot commented Apr 9, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lucky Ready Ready Preview, Comment Apr 9, 2026 9:52pm

Request Review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts (1)

13-25: Prefer shared progress-bar utility over local duplicate.

createProgressBar duplicates behavior that already exists in shared embed utilities (packages/shared/src/utils/general/embeds/core.ts). Reuse the shared function to keep output consistency across bot responses.

As per coding guidelines, "Use embed and reply utilities from @lucky/shared for consistent message formatting and error sanitization across the bot".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts`
around lines 13 - 25, The local createProgressBar function duplicates shared
logic; remove this local definition and import the shared progress-bar utility
instead (use the exported createProgressBar from the shared embeds utilities in
`@lucky/shared`), update any local calls in buildUserProfileEmbed to call the
imported createProgressBar, and adjust parameters or add a small wrapper if the
shared function's signature differs so behavior and formatting remain consistent
with other embeds.
packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts (1)

4-135: Add boundary tests for invalid pagination inputs.

Please add tests for page <= 0, page > totalPages, and itemsPerPage <= 0 to lock down pagination behavior and prevent regressions around edge handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts`
around lines 4 - 135, Add tests calling buildListPageEmbed to cover invalid
pagination: assert that when page <= 0 (e.g., page = 0 or -1) it behaves like
page 1 (footer shows "Page 1 / X" and fields are the first page), when page >
totalPages (e.g., page = 999) it clamps to the last page (footer shows "Page N /
N" and fields are the final items), and when itemsPerPage <= 0 (e.g., 0 or -5 in
options) it falls back to the default itemsPerPage (verify fields length and
footer match default paging). Use the same patterns as other tests (construct
items arrays, call buildListPageEmbed(items, page, { title, itemsPerPage? }),
then assert embed.data.fields length and embed.data.footer?.text) and reference
buildListPageEmbed, itemsPerPage, and footer text to locate where to add the
specs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts`:
- Around line 24-42: Clamp and validate pagination inputs before computing
indices: ensure itemsPerPage (from config.itemsPerPage) is at least 1 (fallback
to DEFAULT_ITEMS_PER_PAGE if <=0 or NaN), recompute totalPages using the
validated itemsPerPage, then clamp page into the range [1, totalPages]; after
these validations compute startIndex, endIndex and slice pageItems as before.
Update references in this block (itemsPerPage, totalPages, page, startIndex,
endIndex, pageItems) so all derived values use the validated/clamped numbers.

In `@packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts`:
- Around line 40-43: The function buildUserProfileEmbed treats any non-null
stats object as usable, so when stats contains only non-numeric/undefined values
(e.g. { xp: undefined }) it proceeds and ends up adding no fields; update the
logic in buildUserProfileEmbed to treat such “defined but unusable” stats as
empty by computing the derived fields array (the one passed to embed.addFields)
and checking if fields.length === 0 before calling embed.addFields — if zero,
set embed.setDescription('No stats available.') and return the embed; ensure
this same guard is applied in the code paths around the existing embed.addFields
and the later return (lines referenced by addFields and the existing
embed.setDescription).

---

Nitpick comments:
In `@packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts`:
- Around line 4-135: Add tests calling buildListPageEmbed to cover invalid
pagination: assert that when page <= 0 (e.g., page = 0 or -1) it behaves like
page 1 (footer shows "Page 1 / X" and fields are the first page), when page >
totalPages (e.g., page = 999) it clamps to the last page (footer shows "Page N /
N" and fields are the final items), and when itemsPerPage <= 0 (e.g., 0 or -5 in
options) it falls back to the default itemsPerPage (verify fields length and
footer match default paging). Use the same patterns as other tests (construct
items arrays, call buildListPageEmbed(items, page, { title, itemsPerPage? }),
then assert embed.data.fields length and embed.data.footer?.text) and reference
buildListPageEmbed, itemsPerPage, and footer text to locate where to add the
specs.

In `@packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts`:
- Around line 13-25: The local createProgressBar function duplicates shared
logic; remove this local definition and import the shared progress-bar utility
instead (use the exported createProgressBar from the shared embeds utilities in
`@lucky/shared`), update any local calls in buildUserProfileEmbed to call the
imported createProgressBar, and adjust parameters or add a small wrapper if the
shared function's signature differs so behavior and formatting remain consistent
with other embeds.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac1ac318-d6f2-4956-85cc-6b0f2d0ce3b1

📥 Commits

Reviewing files that changed from the base of the PR and between e8bb664 and 4ec69e8.

📒 Files selected for processing (9)
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Quality Gates
  • GitHub Check: SonarCloud Scan
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{js,jsx,ts,tsx,vue,html}

📄 CodeRabbit inference engine (.cursor/rules/accessibility-openness.mdc)

Provide accessible UI components using semantic HTML and ARIA attributes where necessary

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/dependency-injection.mdc)

**/*.{ts,tsx,js,jsx}: Prefer constructor injection for classes that require dependencies
Avoid global mutable singletons unless necessary
Use explicit interfaces for external dependencies to make testing easier

**/*.{ts,tsx,js,jsx}: Include required references in PRs/code for non-trivial logic: TypeScript (official docs), MDN (JavaScript reference), and official docs for any runtime/framework/libraries used (e.g., Node.js, React) as applicable.
Before assuming behavior of an API, include the doc link and a ≤25-word quote when the change relies on it.

**/*.{ts,tsx,js,jsx}: Prefer named exports for clear usage and easier refactors in TypeScript/JavaScript
Keep import order consistent: external first, then internal modules
Remove dead code and unused imports

**/*.{ts,tsx,js,jsx}: Use PascalCase naming convention for React/UI components
Use camelCase naming convention for variables and functions
Use UPPER_SNAKE_CASE naming convention for constants
Maintain consistent import grouping and ordering within the project, keeping third-party imports separate from local imports
For external data sources (HTTP, database), always validate and sanitize input using type guards or schema validators

**/*.{ts,tsx,js,jsx}: Use Prettier with no semicolons, single quotes, 4-space indent, 80 character width
Files must not exceed 250 lines and this is enforced

Implement TypeScript typecheck and linter in CI quality checks

**/*.{ts,tsx,js,jsx}: Use TypeScript for enhanced type safety
Implement error handling and error logging
Avoid commenting code unless extremely necessary - code should explain itself with descriptive names
Leave NO todos, placeholders or missing pieces in the code
Variables and functions must use camelCase
Constants must use UPPER_SNAKE_CASE
Use arrow functions for methods and computed properties
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements
Maintain consistent import grouping/order: external imports first, then...

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

**/*.{js,jsx,ts,tsx}: Never throw strings. Throw Error (or typed subclasses) with descriptive messages
Include causal error as cause when available for better debugging
Define clear, stable error codes (e.g., ERR_AUTH_EXPIRED, ERR_NETWORK_TIMEOUT)
Provide optional metadata (e.g., details, retryable, status, correlationId) in error objects
Use domain error classes per area (e.g., AuthenticationError, ValidationError, NetworkError)
Log errors with structure (message, code, stack, cause, correlationId, user context where appropriate)
Mark retryable vs nonRetryable errors where helpful for operations
Set timeouts and handle aborts/cancellations; avoid dangling requests in API/network code
Implement backoff for transient failures; avoid infinite retries
Map HTTP status → domain errors; 4xx vs 5xx behave differently (e.g., retry for 5xx/network)

**/*.{js,jsx,ts,tsx}: Use functional components with hooks in React/React Native. Avoid class components.
Keep components focused on a single responsibility; extract complex logic into custom hooks.
Keep state local when possible. Use Context/Zustand/Redux only when necessary for state management.
If props or state traverse more than 3 levels, consider using context or a feature-scoped store instead of prop drilling.
Use performance optimization techniques: React.memo, useMemo, useCallback, Suspense (web), and virtualization for long lists; avoid unnecessary re-renders.
Web accessibility: use semantic HTML, labels, focus management, keyboard navigation, and aria-* attributes as needed.
React Native accessibility: use accessibility props (accessible, accessibilityLabel), proper roles and labels.
Identify and extract repetitive UI components proactively to components/ with clear props and minimal coupling.
Web styles: prefer co-located styles or design system tokens; avoid global style leakage.
React Native styles: prefer StyleSheet.create, design tokens, and theme providers; avoid in...

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)

**/*.{test,spec}.{js,jsx,ts,tsx}: Test behavior, not implementation. Prefer Testing Library utilities for testing React/React Native components.
For React Native tests: mock native modules and test component interactions and accessibility labels.

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)

Introduce interfaces at module boundaries to enable testing and substitutions

**/*.{ts,tsx}: Avoid using any type in TypeScript. If unavoidable, use unknown with type guards and justify with a code comment
Prefer interface for defining public object shapes in TypeScript, use type for unions and utility types
Use TypeScript utility types such as Partial, Pick, Omit, Readonly, and Record when appropriate
Use I{Name} naming convention for interfaces in TypeScript
Use T{Name} naming convention for type aliases and utility types in TypeScript

**/*.{ts,tsx}: Functions must be less than 50 lines with cyclomatic complexity less than 10
Do not use any types - ESLint enforces this at error level

**/*.{ts,tsx}: Prefer types over interfaces for most cases
Don't ever use any - type safety always
Avoid enums; use const objects instead
For complex types, create a separate file to declare them and import them
Avoid using any type; if unavoidable, use unknown with type guards and justify with code comment
Prefer interface for public API shapes; use type for unions and utility types
Use TypeScript utility types (Partial, Pick, Omit, Readonly, Record)

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Test behavior, not implementation details
Prefer unit tests for core logic; add integration tests at meaningful boundaries

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing-quality.mdc)

**/*.{test,spec}.{js,ts,jsx,tsx}: Use Jest + a React testing library for unit and component tests as applicable
Test behavior, not implementation details

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/documentation.mdc)

**/*.{js,ts,tsx,jsx}: Minimize comments in code; explain the 'why' when non-obvious, let code express the 'what' through clear naming
Document trade-offs briefly when deviating from ideal patterns

**/*.{js,ts,tsx,jsx}: Store secrets, ports, and hosts in environment variables (.env, .env.example) and never hardcode them
Avoid redundant or decorative AI comments; code should be self-explanatory and only commented when logic is non-obvious; prefer refactoring over lengthy comments

Never hardcode secrets, IPs, or ports; use .env and docs/ for required configuration variables

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
packages/bot/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/lucky-discord-bot.mdc)

packages/bot/**/*.{ts,tsx}: Use useMainPlayer() from discord-player to access the player instance; do not instantiate player directly
Do not duplicate queue or player state outside Discord Player; use shared services from @lucky/shared for persistent data like track history and session information
Use errorLog and debugLog from @lucky/shared/utils for logging throughout the bot package
Use embed and reply utilities from @lucky/shared for consistent message formatting and error sanitization across the bot
Use services from @lucky/shared (DatabaseService, Redis client) for database and cache access; do not instantiate Prisma or Redis directly in the bot package

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
packages/bot/**

📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)

The bot package depends on shared and contains Discord bot commands and player handlers using Discord.js and Discord Player

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{js,mjs,ts,mts}

📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)

Use Node.js version ≥22 with ESM (ECMAScript modules) only; no CommonJS

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.{spec,test}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)

**/*.{spec,test}.{ts,tsx,js,jsx}: Use Jest for unit and integration tests
Test behavior, not implementation details
Run unit, integration tests, and coverage report in CI quality checks

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)

Unit tests must use naming convention *.spec.ts

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
packages/bot/src/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)

Use @lucky/shared for database, Redis, logging, and embed utilities instead of implementing them locally

Files:

  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/index.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts
  • packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts
  • packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.spec.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)

Use index.ts only to re-export a small, intentional surface per module

Files:

  • packages/bot/src/utils/general/responseEmbeds/index.ts
🔇 Additional comments (6)
packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.ts (1)

29-59: Clean and reusable embed construction.

This helper is well-scoped and the conditional field application is correct for optional body props.

packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.ts (1)

92-127: Nice builder ergonomics and fallback handling.

Defaults (Unknown Track / Unknown artist) and conditional footer/fields make this utility robust for varied track payloads.

packages/bot/src/utils/general/responseEmbeds/buildTrackEmbed.spec.ts (1)

9-152: Test suite coverage looks solid for the builder contract.

Good behavioral coverage across source detection, kind-specific headers, optional fields, and fallback content.

packages/bot/src/utils/general/responseEmbeds/index.ts (1)

1-11: Good, intentional barrel export surface.

This keeps consumer imports clean while exposing only the intended helper API.

packages/bot/src/utils/general/responseEmbeds/buildPlatformAttribEmbed.spec.ts (1)

4-116: Comprehensive behavioral coverage for platform embed output.

Nice coverage of branding correctness plus conditional title/description/thumbnail/url behavior.

packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.spec.ts (1)

10-93: Strong behavioral coverage for profile embed branches.

The suite validates the important output paths (rank: 0, missing/empty stats, XP modes, username fallback) and is robust for regression protection.

As per coding guidelines, "Test behavior, not implementation details."

Comment on lines +24 to +42
const itemsPerPage = config.itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE
const totalPages = items.length === 0 ? 1 : Math.ceil(items.length / itemsPerPage)

const embed = new EmbedBuilder()
.setTitle(config.title)
.setColor(config.color ?? DEFAULT_COLOR)
.setTimestamp()
.setFooter({
text: `Page ${page} / ${totalPages}`,
})

if (items.length === 0) {
embed.setDescription(config.emptyMessage ?? 'No items to display.')
return embed
}

const startIndex = (page - 1) * itemsPerPage
const endIndex = Math.min(startIndex + itemsPerPage, items.length)
const pageItems = items.slice(startIndex, endIndex)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate and clamp pagination inputs before slicing.

itemsPerPage and page are used unchecked. Invalid values (e.g., itemsPerPage: 0, page: 0, or page > total) produce incorrect pagination state and empty/non-sensical pages for non-empty lists.

✅ Suggested fix
 export function buildListPageEmbed(
     items: ListItem[],
     page: number,
     config: ListPageConfig,
 ): EmbedBuilder {
-    const itemsPerPage = config.itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE
-    const totalPages = items.length === 0 ? 1 : Math.ceil(items.length / itemsPerPage)
+    const rawItemsPerPage = config.itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE
+    const itemsPerPage =
+        Number.isInteger(rawItemsPerPage) && rawItemsPerPage > 0
+            ? rawItemsPerPage
+            : DEFAULT_ITEMS_PER_PAGE
+    const totalPages = Math.max(1, Math.ceil(items.length / itemsPerPage))
+    const safePage = Math.min(Math.max(page, 1), totalPages)
@@
         .setTimestamp()
         .setFooter({
-            text: `Page ${page} / ${totalPages}`,
+            text: `Page ${safePage} / ${totalPages}`,
         })
@@
-    const startIndex = (page - 1) * itemsPerPage
+    const startIndex = (safePage - 1) * itemsPerPage
     const endIndex = Math.min(startIndex + itemsPerPage, items.length)
     const pageItems = items.slice(startIndex, endIndex)
📝 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
const itemsPerPage = config.itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE
const totalPages = items.length === 0 ? 1 : Math.ceil(items.length / itemsPerPage)
const embed = new EmbedBuilder()
.setTitle(config.title)
.setColor(config.color ?? DEFAULT_COLOR)
.setTimestamp()
.setFooter({
text: `Page ${page} / ${totalPages}`,
})
if (items.length === 0) {
embed.setDescription(config.emptyMessage ?? 'No items to display.')
return embed
}
const startIndex = (page - 1) * itemsPerPage
const endIndex = Math.min(startIndex + itemsPerPage, items.length)
const pageItems = items.slice(startIndex, endIndex)
const rawItemsPerPage = config.itemsPerPage ?? DEFAULT_ITEMS_PER_PAGE
const itemsPerPage =
Number.isInteger(rawItemsPerPage) && rawItemsPerPage > 0
? rawItemsPerPage
: DEFAULT_ITEMS_PER_PAGE
const totalPages = Math.max(1, Math.ceil(items.length / itemsPerPage))
const safePage = Math.min(Math.max(page, 1), totalPages)
const embed = new EmbedBuilder()
.setTitle(config.title)
.setColor(config.color ?? DEFAULT_COLOR)
.setTimestamp()
.setFooter({
text: `Page ${safePage} / ${totalPages}`,
})
if (items.length === 0) {
embed.setDescription(config.emptyMessage ?? 'No items to display.')
return embed
}
const startIndex = (safePage - 1) * itemsPerPage
const endIndex = Math.min(startIndex + itemsPerPage, items.length)
const pageItems = items.slice(startIndex, endIndex)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/general/responseEmbeds/buildListPageEmbed.ts` around
lines 24 - 42, Clamp and validate pagination inputs before computing indices:
ensure itemsPerPage (from config.itemsPerPage) is at least 1 (fallback to
DEFAULT_ITEMS_PER_PAGE if <=0 or NaN), recompute totalPages using the validated
itemsPerPage, then clamp page into the range [1, totalPages]; after these
validations compute startIndex, endIndex and slice pageItems as before. Update
references in this block (itemsPerPage, totalPages, page, startIndex, endIndex,
pageItems) so all derived values use the validated/clamped numbers.

Comment on lines +40 to +43
if (!stats || Object.keys(stats).length === 0) {
embed.setDescription('No stats available.')
return embed
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle “defined but unusable” stats as empty state.

If stats is present but all values are non-numeric/undefined (e.g. { xp: undefined }), Line 40 skips the fallback and Line 72 returns an embed with no stats content. Add a fields.length === 0 fallback before addFields.

💡 Suggested fix
     if (!stats || Object.keys(stats).length === 0) {
         embed.setDescription('No stats available.')
         return embed
     }
@@
-    embed.addFields(fields)
+    if (fields.length === 0) {
+        embed.setDescription('No stats available.')
+        return embed
+    }
+
+    embed.addFields(fields)
     return embed
 }

Also applies to: 72-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/general/responseEmbeds/buildUserProfileEmbed.ts`
around lines 40 - 43, The function buildUserProfileEmbed treats any non-null
stats object as usable, so when stats contains only non-numeric/undefined values
(e.g. { xp: undefined }) it proceeds and ends up adding no fields; update the
logic in buildUserProfileEmbed to treat such “defined but unusable” stats as
empty by computing the derived fields array (the one passed to embed.addFields)
and checking if fields.length === 0 before calling embed.addFields — if zero,
set embed.setDescription('No stats available.') and return the embed; ensure
this same guard is applied in the code paths around the existing embed.addFields
and the later return (lines referenced by addFields and the existing
embed.setDescription).

Fixes critical SSRF in axios (GHSA-3p68-rc4w-qgx5) and moderate CVEs in
hono/hono-node-server. npm audit --audit-level=high now clean.
@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 324 kB

ℹ️ View Unchanged
Filename Size
packages/frontend/dist/assets/ActionPanel-DNyixsRN.js 400 B
packages/frontend/dist/assets/api-DsLAIu-l.js 2.9 kB
packages/frontend/dist/assets/authStore-Bo_PbbZd.js 557 B
packages/frontend/dist/assets/AutoMessages-CMx6p29r.js 2.69 kB
packages/frontend/dist/assets/AutoMod-H-4xwkmt.js 4.09 kB
packages/frontend/dist/assets/avatar-BYVlC9R1.js 1.79 kB
packages/frontend/dist/assets/badge-kekZ5uai.js 498 B
packages/frontend/dist/assets/Button-Chq_jJX6.js 766 B
packages/frontend/dist/assets/Card-DY7pU8Q5.js 457 B
packages/frontend/dist/assets/chunk-QFMPRPBF-ySVqcpZB.js 14.8 kB
packages/frontend/dist/assets/CommandsConfig-D5HhVE8J.js 1.49 kB
packages/frontend/dist/assets/Config-D0yyrS5J.js 1.74 kB
packages/frontend/dist/assets/CustomCommands-D6roNyDQ.js 2.15 kB
packages/frontend/dist/assets/DashboardOverview-B7ZvaNvW.js 3.42 kB
packages/frontend/dist/assets/dialog-DCGuWOQz.js 949 B
packages/frontend/dist/assets/dist-Bzdj1j8i.js 416 B
packages/frontend/dist/assets/EmbedBuilder-Rq0Aksdt.js 3.35 kB
packages/frontend/dist/assets/EmptyState-D-FW84dc.js 432 B
packages/frontend/dist/assets/Features-CWZ4j0-1.js 2.85 kB
packages/frontend/dist/assets/GuildAutomation-K29WisHS.js 2.94 kB
packages/frontend/dist/assets/guildStore-D5pntH7c.js 791 B
packages/frontend/dist/assets/index-BvzPtzfc.js 11.7 kB
packages/frontend/dist/assets/index-DoLe_VYd.css 14.4 kB
packages/frontend/dist/assets/input-B8xLKRen.js 465 B
packages/frontend/dist/assets/label-9gyU3CvE.js 485 B
packages/frontend/dist/assets/LastFm-rG5GrbYY.js 1.74 kB
packages/frontend/dist/assets/Levels-DLo4t0Rt.js 2.65 kB
packages/frontend/dist/assets/Login-C5vaBplo.js 2.54 kB
packages/frontend/dist/assets/Lyrics-C6bZmDoy.js 1.33 kB
packages/frontend/dist/assets/Moderation-Ceej5Axm.js 3.87 kB
packages/frontend/dist/assets/Music-DwHM3KDy.js 6.17 kB
packages/frontend/dist/assets/MusicConfig-BkgUtXsR.js 1.62 kB
packages/frontend/dist/assets/PrivacyPolicy-BMYU-0jY.js 1.38 kB
packages/frontend/dist/assets/rbac-BN1DzQHh.js 152 B
packages/frontend/dist/assets/ReactionRoles-D-ubvLwR.js 1.9 kB
packages/frontend/dist/assets/rolldown-runtime-COnpUsM8.js 467 B
packages/frontend/dist/assets/scroll-area-C8T6RLOh.js 522 B
packages/frontend/dist/assets/SectionHeader-C0yb_DFu.js 385 B
packages/frontend/dist/assets/select-CHLbPSDw.js 1.23 kB
packages/frontend/dist/assets/ServerLogs-BtUuCMku.js 2.9 kB
packages/frontend/dist/assets/ServerSettings-4VsKJdYy.js 4.22 kB
packages/frontend/dist/assets/ServersPage-CLyZtYdk.js 2.95 kB
packages/frontend/dist/assets/Skeleton-Z9dBUKZD.js 236 B
packages/frontend/dist/assets/Starboard-xddi8bqd.js 2.09 kB
packages/frontend/dist/assets/StatTile-DI0Q4bgV.js 606 B
packages/frontend/dist/assets/switch-nhTZOPm5.js 543 B
packages/frontend/dist/assets/TermsOfService-SB9iOf3u.js 1.37 kB
packages/frontend/dist/assets/TrackHistory-Brg7jkn6.js 1.91 kB
packages/frontend/dist/assets/TwitchNotifications-BrtUbdEd.js 2.29 kB
packages/frontend/dist/assets/useGuildSelection-CNWhdqGT.js 488 B
packages/frontend/dist/assets/usePageMetadata-C6uKjjUo.js 325 B
packages/frontend/dist/assets/utils-ayWzbeKE.js 148 B
packages/frontend/dist/assets/vendor-forms-DmZCnE0r.js 25.4 kB
packages/frontend/dist/assets/vendor-radix-DyTfqI7p.js 33.5 kB
packages/frontend/dist/assets/vendor-react-DlFk5rSD.js 55.6 kB
packages/frontend/dist/assets/vendor-state-1dKZOhDf.js 22.2 kB
packages/frontend/dist/assets/vendor-ui-B32-89km.js 64.2 kB

compressed-size-action

@github-actions github-actions Bot removed dependencies Pull requests that update a dependency file frontend shared labels Apr 9, 2026
@LucasSantana-Dev
LucasSantana-Dev enabled auto-merge (squash) April 9, 2026 21:53
@sonarqubecloud

sonarqubecloud Bot commented Apr 9, 2026

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev merged commit 0008010 into main Apr 9, 2026
12 checks passed
LucasSantana-Dev added a commit that referenced this pull request Apr 10, 2026
* feat(bot): add reusable embed builder helpers

- buildTrackEmbed: general-purpose track display with source detection
- buildUserProfileEmbed: user stat snapshot with progress bars
- buildListPageEmbed: paginated list helper with field-per-item layout
- buildPlatformAttribEmbed: external service branding (Last.fm, Spotify, YouTube)

All helpers include comprehensive unit tests covering edge cases and variants.

* fix(deps): bump axios to ^1.15.0 and hono to >=4.12.12

Fixes critical SSRF in axios (GHSA-3p68-rc4w-qgx5) and moderate CVEs in
hono/hono-node-server. npm audit --audit-level=high now clean.

* refactor(bot): import detectSource from nowPlayingEmbed, remove duplication
LucasSantana-Dev added a commit that referenced this pull request May 13, 2026
* feat(bot): add reusable embed builder helpers

- buildTrackEmbed: general-purpose track display with source detection
- buildUserProfileEmbed: user stat snapshot with progress bars
- buildListPageEmbed: paginated list helper with field-per-item layout
- buildPlatformAttribEmbed: external service branding (Last.fm, Spotify, YouTube)

All helpers include comprehensive unit tests covering edge cases and variants.

* fix(deps): bump axios to ^1.15.0 and hono to >=4.12.12

Fixes critical SSRF in axios (GHSA-3p68-rc4w-qgx5) and moderate CVEs in
hono/hono-node-server. npm audit --audit-level=high now clean.

* refactor(bot): import detectSource from nowPlayingEmbed, remove duplication
@LucasSantana-Dev
LucasSantana-Dev deleted the feat/bot-reusable-embeds branch May 23, 2026 02:21

This branch was successfully deployed

1 active deployment
Preview — 53e2204e Deployed Apr 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant