Discord.js Integration
Discord bot implementation using discord.js v14 with slash commands and message content access.
Bot Configuration
Required intents:
GatewayIntentBits.Guilds– Guild information accessGatewayIntentBits.GuildMessages– Message history accessGatewayIntentBits.MessageContent– Message content and attachments
Message content intent:
Required for image URL extraction from Discord messages. Without this intent, bot cannot access attachment URLs or embed content.
Command Registration
Registration scope:
Guild-specific registration via REST API.
Registration endpoint:
Routes.applicationGuildCommands(clientId, guildId)
Registered commands:
/pin– Search for and pin images to Pinterest/prompt– Generate Midjourney prompts/sync– Sync Pinterest boards/auth– Authenticate with Pinterest/settings– Manage Pinterest accounts/restart– Restart bot process/editprompt– Edit system prompt sections/model– Configure OpenAI model
Registration timing:
Commands registered on ClientReady event after bot connects.
Command structure:
Each command exports:
data– SlashCommandBuilder instanceexecute– Async function handling interaction
Interaction Handling
Interaction types supported:
- Chat input commands (slash commands)
- String select menus (dropdowns)
- Modal submits (text input forms)
Interaction routing:
Main interaction handler in src/index.js routes interactions to command modules based on:
- Command name for slash commands
- Custom ID for select menus and modals
Deferred replies:
All commands use interaction.deferReply() for operations exceeding 3 seconds:
- Pinterest API calls
- OpenAI API calls
- Board synchronization
- Message history searches
Ephemeral messages:
Used for:
/auth– Authorization URLs (privacy)/settings– Account management (privacy)/model– Configuration (reduces channel clutter)/editprompt– Admin operations (security)/restart– Admin operations (security)
Message Fetching
Fetch methods:
channel.messages.fetch(messageId)– Single message by IDchannel.messages.fetch({ limit: N })– Recent messageschannel.messages.fetch({ before: id, limit: N })– Paginated backwardchannel.messages.fetch({ after: id, limit: N })– Paginated forward
Pagination limits:
- Maximum 100 messages per fetch
- Rate limited to prevent API throttling (100ms delay between batches)
/pinsearches up to 1000 messages maximum
Message content access:
message.content– Text contentmessage.attachments– Attachment collectionmessage.embeds– Embed arraymessage.interaction– Command interaction metadata
Image detection:
Bot checks multiple sources:
- Direct attachments:
message.attachments.first().url - Embed images:
message.embeds[0].image.url - Embed thumbnails:
message.embeds[0].thumbnail.url
Error Handling
Global error handlers:
unhandledRejection– Logs and continuesuncaughtException– Logs and exits with code 1SIGTERM– Graceful shutdown with client.destroy()SIGINT– Graceful shutdown with client.destroy()
Command error handling:
Centralized in interaction event handler:
- Try command execution
- Catch errors
- Respond with generic error message
- Multiple response strategies:
- Not replied/deferred: Use
reply()with ephemeral flag - Deferred: Use
editReply() - Already replied: Use
followUp()with ephemeral flag
- Not replied/deferred: Use
Component interaction timeouts:
Select menus and modals timeout after 60 seconds:
/settingsaccount selection/modelmodel selection- No timeout for
/editpromptmodal
Permission Checks
Permission system:
Commands verify Discord permissions before execution.
Permission levels:
- Manage Server (
ManageGuild):/model,/sync - Administrator (
Administrator):/editprompt,/restart
Permission check implementation:
interaction.member.permissions.has(PermissionsBitField.Flags.PermissionName)
Permission denied responses:
Ephemeral messages indicating insufficient permissions.
Login and Reconnection
Login retry logic:
- Maximum 3 retry attempts
- Exponential backoff: 2^retry * 1000ms
- Exit with code 1 if all retries fail
Connection events:
ClientReady– Initial connection establishedError– Client error occurredDisconnect– Client disconnectedReconnecting– Reconnection attempt in progressResume– Connection resumed after disconnect
Restart handling:
Bot reads data/restart_info.json on startup:
- Fetches original restart message
- Updates to "Restart successful."
- Deletes restart info file
- Logs success or errors
Environment Configuration
Required environment variables:
MJPIN_DISCORD_TOKEN– Bot authentication tokenMJPIN_DISCORD_CLIENT_ID– Application client IDMJPIN_DISCORD_GUILD_ID– Target guild for command registration
Token security:
Token logged as ‘[HIDDEN]’ in console output.