Skip to content

And now, it's time to put this to the real test#112

Merged
Mewtwo2387 merged 17 commits intomasterfrom
DockerTest
Jan 14, 2026
Merged

And now, it's time to put this to the real test#112
Mewtwo2387 merged 17 commits intomasterfrom
DockerTest

Conversation

@Mewtwo2387
Copy link
Copy Markdown
Owner

@Mewtwo2387 Mewtwo2387 commented Jan 14, 2026

Summary by CodeRabbit

  • Infrastructure

    • Added container build/push CI and updated deployment to use Docker Compose; added service image and persistence mount.
    • Introduced multi-stage container image and updated ignore rules for build/runtime artifacts.
  • Performance

    • Migrated runtime to Bun; swapped HTTP client to native fetch across commands.
    • Database access reworked for Bun-based SQLite with WAL enabled.
  • Chores

    • Updated project scripts and dependencies for Bun workflows; moved database and log files into persistence.
  • Bug Fixes

    • Removed redundant dotenv initialization and surfaced persistent log paths.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 14, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Migrates runtime to Bun (removes explicit dotenv), replaces axios with native fetch, swaps sqlite3 for Bun's bun:sqlite with synchronous DB APIs, moves database/logs into persistence/, adds Dockerfile/docker-compose, and updates CI to build/push Docker images and deploy via docker compose.

Changes

Cohort / File(s) Summary
Environment & Runtime
.dockerignore, .gitignore, index.js, classes/silverwolf.js, classes/babyScheduler.js, classes/birthdayScheduler.js, classes/handlers/... (aprilFoolsHandler.js, christmasHandler.js, halloweenHandler.js, normalHandler.js), commands/birthday_test.js, commands/marriage_propose.js, commands/sex_start.js, tests/deepseek.js, utils/accessControl.js, utils/ai.js
Removed explicit dotenv.config() calls (relying on Bun auto-loading); added/adjusted ignore patterns; minor env-related comments.
HTTP Client Migration
commands/cat.js, commands/f1Standings.js, commands/genshinProfile.js, commands/grabEmoji.js, commands/hsrProfile.js, commands/randomjoke.js, classes/bitcoin.js
Replaced axios usage with global fetch, added response.ok checks, explicit parsing (json/text/arrayBuffer), and adjusted error handling.
Database & Persistence Paths
database/Database.js, classes/database.js, commands/dbdump.js, utils/log.js
Replaced sqlite3 with bun:sqlite using synchronous APIs; changed DB/log file locations to ./persistence/; adapted query/create/update APIs to Bun semantics.
Docker & Deployment
Dockerfile, docker-compose.yaml, .github/workflows/deploy.yml
Added two-stage Bun Dockerfile, new bot service in compose with ./persistence volume, and GitHub Actions job to build/push multi-platform images and deploy via docker compose on target host.
Package & Scripts
package.json
Switched scripts to Bun-oriented commands, removed dotenv and sqlite3 deps, updated canvas version, and added trustedDependencies.
Miscellaneous
utils/log.js exports
Updated log paths and exported logFilePath/logErrorFilePath.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Registry as Docker Registry
    participant Server as Deployment Host
    participant Docker as Docker Compose on Server
    GH->>GH: checkout, buildx setup
    GH->>Registry: docker buildx build & push (multi-platform)
    GH->>Server: SSH & run docker compose pull
    Server->>Docker: docker compose pull -> docker compose up -d
    Docker-->>Server: services updated
    Server-->>GH: deployment result/status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

silverwolf is very hot, unfucking fucked code

Poem

🐰 I hopped from Node to Bun so spry,

Logs and DBs in a cozy pie,
Fetch took axios' little hat,
Docker hummed — I tipped my hat,
Bun gardens grow where pods now lie. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and does not clearly convey what the pull request accomplishes; it uses a metaphorical phrase without describing any specific technical changes. Replace the title with a specific summary of the main change, such as 'Migrate to Docker deployment with Bun runtime' or 'Add Docker containerization and switch to Bun runtime.'
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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



📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db4ee60 and e0a5685.

📒 Files selected for processing (1)
  • docker-compose.yaml

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

Copy link
Copy Markdown

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
commands/birthday_test.js (1)

17-48: Race condition: forEach with async callback doesn't await results.

The forEach loop contains an async callback, but forEach doesn't await these callbacks. This means the reply at line 48 will execute before any channel tests complete, always showing empty results.

🐛 Proposed fix using for...of or Promise.all
-    // Loop through all the channel IDs and attempt to send a message
-    channelIds.forEach(async (channelId) => {
+    // Loop through all the channel IDs and attempt to send a message
+    for (const channelId of channelIds) {
       const channel = this.client.channels.cache.get(channelId);
       if (channel) {
         try {
           const testEmbed = new EmbedBuilder()
             .setTitle('Test: Birthday Scheduler')
             .setDescription('This is a test to verify the birthday scheduler can send messages.')
             .setColor(0x00FF00);

           await channel.send({ embeds: [testEmbed] });
           successChannels.push(channelId); // Add to success list if the message was sent successfully
         } catch (error) {
           logError(`Error sending message to channel ${channelId}:`, error);
           failedChannels.push(channelId); // Add to failed list if there was an error
         }
       } else {
         logError(`Channel ID ${channelId} is invalid or not found.`);
         failedChannels.push(channelId); // Add to failed list if the channel is not found
       }
-    });
+    }
classes/database.js (1)

1-972: Delete classes/database.js entirely—it has been replaced.

A new database implementation using bun:sqlite already exists at database/Database.js and is actively used throughout the codebase (tests, models, and silverwolf.js all import from the new location). The ~970 lines of commented-out sqlite3 code in classes/database.js serves no purpose.

Remove this file; git history preserves it if you need to reference the implementation later.

index.js (1)

15-16: Security risk: Sensitive credentials logged to output.

Logging the TOKEN exposes the Discord bot token in logs, which could lead to token compromise if logs are accessible. Consider removing this log statement or masking the token.

Suggested fix
-log('TOKEN: ', TOKEN);
-log('CLIENT_ID: ', CLIENT_ID);
+log('TOKEN: ', TOKEN ? '[REDACTED]' : 'undefined');
+log('CLIENT_ID: ', CLIENT_ID);

Or simply remove the TOKEN log entirely:

-log('TOKEN: ', TOKEN);
 log('CLIENT_ID: ', CLIENT_ID);
utils/accessControl.js (1)

6-6: Type inconsistency: fallback returns a string instead of an array.

When ALLOWED_SERVERS is not provided, this returns BASEMENT_ID (a string) instead of an array. The isAllowedServer() function on line 21 uses .includes(), which behaves differently on strings vs arrays—String.includes() matches substrings, so a guild ID like "969" would incorrectly match.

Suggested fix
-const ALLOWED_SERVERS = process.env.ALLOWED_SERVERS ? process.env.ALLOWED_SERVERS.split(',') : BASEMENT_ID;
+const ALLOWED_SERVERS = process.env.ALLOWED_SERVERS ? process.env.ALLOWED_SERVERS.split(',') : [BASEMENT_ID];
commands/f1Standings.js (1)

119-124: Missing return after invalid year check.

After sending the error reply for an invalid year, the function continues execution and makes an unnecessary API request. Add a return statement to exit early.

Proposed fix
     if (year > currentYear || year < minYear) {
-      interaction.editReply({
+      await interaction.editReply({
         content: `Invalid year for ${type} standings. Must be between ${minYear} and ${currentYear}.`,
         ephemeral: true,
       });
+      return;
     }
classes/birthdayScheduler.js (1)

35-41: Potential null pointer exception on discordUser.

discordUser can be null (line 35 catches errors and returns null), but line 41 calls discordUser.displayAvatarURL() without a null guard. This will throw if the user fetch fails.

Proposed fix
               const birthdayEmbed = new EmbedBuilder()
                 .setTitle('🎉 Birthday Alert! 🎉')
                 .setDescription(`Today is ${username}'s birthday! Let's all wish them a great day! 🥳`)
-                .setImage(discordUser.displayAvatarURL({ dynamic: true, format: 'png', size: 4096 }))
+                .setImage(discordUser?.displayAvatarURL({ dynamic: true, format: 'png', size: 4096 }) || null)
                 .setColor(0x00FF00);
database/Database.js (1)

90-105: Use stmt.run() return value to eliminate unnecessary queries.

The current implementation discards the return value of stmt.run(), which already contains { changes, lastInsertRowid }. Instead of making two separate database queries, capture this object directly.

♻️ Correct optimization
  async executeQuery(query, params = []) {
    try {
      const stmt = this.db.query(query);
-     stmt.run(...params);
+     const result = stmt.run(...params);

      return {
-       changes: this.db.query('SELECT changes() as changes').get().changes,
-       lastID: this.db.query('SELECT last_insert_rowid() as id').get().id
+       changes: result.changes,
+       lastID: result.lastInsertRowid
      };
    } catch (error) {
      logError(`Error executing query "${query}":`, error);
      return { changes: 0, lastID: null };
    }
  }
🤖 Fix all issues with AI agents
In @.github/workflows/deploy.yml:
- Around line 37-39: Replace the hardcoded host value and unpinned action
reference: swap the literal IP "51.75.21.146" used with the appleboy/ssh-action
invocation to a GitHub Actions secret (e.g., use `${{ secrets.DEPLOY_HOST }}`)
and change the action reference `appleboy/ssh-action@master` to a fixed release
tag (e.g., `appleboy/ssh-action@vX.Y.Z`) to avoid breaking changes; update the
workflow inputs where `host:` is set and the `uses:` line accordingly.
- Around line 43-45: The workflow runs "docker compose pull" against the
repository's docker-compose.yaml which still references the placeholder image
name DOCKERHUB_USERNAME_PLACEHOLDER/silverwolf-bot:latest; replace that
placeholder with the real Docker Hub repo (or update the compose file to use an
image from your registry) or add a step in the deploy job to substitute the
placeholder with a runtime secret before running "docker compose pull" so the
compose file contains a valid image reference when executing the commands shown
(cd /opt/silverwolf, docker compose pull, docker compose up -d).

In `@Dockerfile`:
- Around line 17-18: The Dockerfile currently uses the non-standard global
install command "RUN bun add -g node-gyp"; replace this with an explicit "npm
install -g node-gyp" to ensure node-gyp is available for native compilations,
and add system build deps (install python3, python3-dev, build-essential via
apt-get) plus a python symlink (ln -sf /usr/bin/python3 /usr/bin/python) before
installing node-gyp so packages like canvas can compile reliably.

In `@package.json`:
- Around line 56-60: The trustedDependencies array currently includes
"skia-canvas" which isn’t a real dependency or referenced; remove the
"skia-canvas" entry from the trustedDependencies list so it only contains
"canvas", leaving the trustedDependencies array with the actual dependency
("canvas") and ensuring no other parts of the code or package.json reference
"skia-canvas".
- Line 23: Replace the pre-release canvas dependency entry "canvas":
"^3.0.0-rc3" in package.json with a stable release (for example "canvas":
"^3.2.0") so the project uses a non-RC version; update the version string, run
your package manager's install (npm/yarn/pnpm) to refresh lockfiles, and verify
builds/tests pass after the upgrade.

In `@utils/accessControl.js`:
- Line 4: ALLOWED_USERS initialization calls
process.env.ALLOWED_USERS.split(',') which throws if ALLOWED_USERS is undefined;
update the code that defines ALLOWED_USERS to guard against a missing env var by
checking process.env.ALLOWED_USERS first and defaulting to an empty string or
empty array, e.g., use a conditional or fallback (refer to the ALLOWED_USERS
constant and process.env.ALLOWED_USERS) so the value becomes an empty array when
unset and downstream code won’t crash.
🧹 Nitpick comments (6)
docker-compose.yaml (1)

1-12: Configuration looks good for containerized deployment.

The setup correctly handles persistence via volume mount and uses resource limits. The placeholder image name will presumably be replaced during CI/CD.

Consider adding a healthcheck for better observability, though this is optional for a Discord bot:

Optional: Add healthcheck
 services:
   bot:
     image: DOCKERHUB_USERNAME_PLACEHOLDER/silverwolf-bot:latest
     container_name: silverwolf-bot
     restart: unless-stopped
     env_file: .env
     volumes:
       - ./persistence:/app/persistence
     deploy:
       resources:
         limits:
           memory: 512M
+    healthcheck:
+      test: ["CMD", "pgrep", "-x", "bun"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
tests/deepseek.js (1)

30-33: Consider adding error handling for failed responses.

The test doesn't check response.ok before parsing JSON. If the API returns an error status, response.json() may fail or return unexpected data. Since this is a test file, this is a minor concern.

Optional: Add response validation
   const data = await response.json();
+  if (!response.ok) {
+    console.error('API Error:', response.status, data);
+    return;
+  }
   console.log(JSON.stringify(data, null, 2)); // Pretty-print JSON
.gitignore (1)

15-17: .DS_Store entry is misplaced under the whitelist section.

The .DS_Store ignore rule appears after the # whitelist comment, which is misleading since it's not a whitelist entry. Move it above the whitelist section for clarity.

Suggested fix
 persistence/
 
 *.db-wal
 *.db-shm
+.DS_Store
 
 # whitelist
 !data/SilverwolfSystemPrompt.txt
-.DS_Store
classes/babyScheduler.js (1)

22-37: Pre-existing: forEach with async callbacks doesn't await properly.

The forEach callback is async but forEach doesn't await the returned promises, meaning errors won't propagate and the function returns before all operations complete. This applies to dailyAutomations, tenMinuteAutomations, dailyNuggieClaim, and tenMinuteGamble.

Consider using for...of or Promise.all(array.map(...)) if you want proper awaiting in a future refactor.

commands/genshinProfile.js (1)

35-41: Fetch migration looks correct; consider adding a timeout.

The migration from axios to native fetch is well done with proper response.ok checking and error logging. However, native fetch doesn't have a built-in timeout, which could cause the request to hang indefinitely if the API is unresponsive.

💡 Optional: Add AbortController timeout
+    const controller = new AbortController();
+    const timeout = setTimeout(() => controller.abort(), 10000);
     try {
-      const response = await fetch(url, { headers });
+      const response = await fetch(url, { headers, signal: controller.signal });
+      clearTimeout(timeout);
       if (!response.ok) {
utils/log.js (1)

4-5: Ensure persistence directory exists before logging.

The log paths now point to ../persistence/. If this directory doesn't exist when the application starts (outside Docker, or on first run), fs.appendFile will fail silently (error caught but logs lost). Consider adding directory creation logic.

💡 Add directory existence check
 const fs = require('fs');
 const path = require('path');

+const persistenceDir = path.join(__dirname, '../persistence');
+if (!fs.existsSync(persistenceDir)) {
+  fs.mkdirSync(persistenceDir, { recursive: true });
+}
+
 const logFilePath = path.join(__dirname, '../persistence/logs.txt');
 const logErrorFilePath = path.join(__dirname, '../persistence/logs_error.txt');
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b49ebe0 and db4ee60.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (31)
  • .dockerignore
  • .github/workflows/deploy.yml
  • .gitignore
  • Dockerfile
  • classes/babyScheduler.js
  • classes/birthdayScheduler.js
  • classes/bitcoin.js
  • classes/database.js
  • classes/handlers/aprilFoolsHandler.js
  • classes/handlers/christmasHandler.js
  • classes/handlers/halloweenHandler.js
  • classes/handlers/normalHandler.js
  • classes/silverwolf.js
  • commands/birthday_test.js
  • commands/cat.js
  • commands/dbdump.js
  • commands/f1Standings.js
  • commands/genshinProfile.js
  • commands/grabEmoji.js
  • commands/hsrProfile.js
  • commands/marriage_propose.js
  • commands/randomjoke.js
  • commands/sex_start.js
  • database/Database.js
  • docker-compose.yaml
  • index.js
  • package.json
  • tests/deepseek.js
  • utils/accessControl.js
  • utils/ai.js
  • utils/log.js
🧰 Additional context used
🧬 Code graph analysis (8)
classes/bitcoin.js (1)
tests/deepseek.js (1)
  • response (4-29)
commands/f1Standings.js (1)
tests/deepseek.js (1)
  • response (4-29)
commands/dbdump.js (8)
classes/silverwolf.js (1)
  • path (5-5)
commands/genshinProfile.js (1)
  • path (2-2)
commands/hsrProfile.js (1)
  • path (2-2)
commands/arlecchino.js (1)
  • path (2-2)
commands/fortune.js (1)
  • path (2-2)
commands/hilichurl.js (1)
  • path (2-2)
commands/misfortune.js (1)
  • path (2-2)
commands/slots.js (1)
  • path (3-3)
classes/silverwolf.js (1)
tests/database/user.test.js (1)
  • Database (1-1)
commands/grabEmoji.js (1)
tests/deepseek.js (1)
  • response (4-29)
commands/hsrProfile.js (1)
tests/deepseek.js (2)
  • response (4-29)
  • data (31-31)
commands/genshinProfile.js (1)
tests/deepseek.js (2)
  • response (4-29)
  • data (31-31)
commands/randomjoke.js (1)
tests/deepseek.js (2)
  • response (4-29)
  • data (31-31)
🔇 Additional comments (36)
classes/handlers/normalHandler.js (1)

6-6: LGTM - consistent with Bun migration.

The dotenv removal aligns with the project-wide migration to Bun. Note that this file doesn't actually reference any environment variables, so the original dotenv import was likely unnecessary.

commands/marriage_propose.js (1)

1-1: LGTM - Bun environment loading is correct.

The migration from explicit dotenv.config() to Bun's automatic .env loading is appropriate. The process.env.ALLOWED_USERS access on line 20 will continue to work as expected with Bun.

classes/silverwolf.js (2)

10-10: LGTM - consistent with Bun migration.

The dotenv removal is appropriate for Bun runtime. Environment variables like GUILD_ID (line 307) will continue to work with Bun's automatic .env loading.


36-36: This is already properly handled in the Docker configuration.

The /app/persistence directory is explicitly created in the Dockerfile (line 43: RUN mkdir -p /app/persistence && chown -R bun:bun /app/persistence), with correct permissions set for the bun user, before the application starts. No further action is required.

commands/sex_start.js (1)

1-1: LGTM - consistent with Bun migration.

The migration from explicit dotenv to Bun's automatic .env loading is correct. The process.env.ALLOWED_USERS access on line 22 will function properly with Bun.

classes/handlers/christmasHandler.js (1)

7-7: LGTM - consistent with Bun migration.

The dotenv removal aligns with the project-wide migration. This file doesn't reference any environment variables, so the original dotenv dependency was unused.

utils/ai.js (1)

5-5: LGTM!

The removal of explicit dotenv.config() in favor of Bun's automatic .env loading is appropriate for the Bun runtime migration. Environment variables will be available when the module initializes.

classes/handlers/aprilFoolsHandler.js (1)

4-4: LGTM!

Consistent with the project-wide migration to Bun's automatic .env loading. This file doesn't directly use environment variables, so the change is purely for consistency.

.dockerignore (1)

1-9: LGTM!

Well-structured .dockerignore file that properly excludes:

  • Build artifacts and dependencies (node_modules)
  • Sensitive files (.env)
  • Runtime data (persistence/, database.db, logs.txt)
  • VCS and OS artifacts (.git, .DS_Store)

This aligns with the PR's data persistence strategy and prevents secrets from being baked into the Docker image.

commands/birthday_test.js (1)

1-1: LGTM!

Consistent with the project-wide migration to Bun's automatic .env loading.

index.js (1)

5-5: LGTM on the Bun migration comment.

The comment correctly documents the Bun behavior for future maintainers.

commands/dbdump.js (1)

109-109: Path update aligns with persistence directory migration.

The change from ../database.db to ../persistence/database.db is consistent with the broader project migration documented in the AI summary.

commands/grabEmoji.js (1)

60-63: LGTM! Clean migration from axios to fetch.

The fetch implementation correctly handles binary data by converting ArrayBuffer to Buffer. Error handling with response.ok check is appropriate, and the thrown error will be caught by the outer try-catch block at line 107.

classes/handlers/halloweenHandler.js (1)

6-6: Acceptable for Bun runtime migration.

The comment accurately documents that Bun automatically reads .env files. This change is consistent with the project-wide migration to Bun. Ensure that the deployment environment uses Bun as the runtime; otherwise, environment variables won't be loaded.

commands/f1Standings.js (1)

130-133: LGTM! Proper fetch implementation for HTML content.

The migration from axios to fetch is correctly implemented. Using response.text() is appropriate for HTML content, and the error message includes the HTTP status code for better debugging.

classes/birthdayScheduler.js (1)

4-4: Acceptable for Bun runtime migration.

The comment correctly documents Bun's automatic .env file loading behavior.

classes/bitcoin.js (1)

10-14: LGTM! Clean fetch implementation for JSON API.

The migration from axios to fetch is well-implemented. The response.ok check, response.json() parsing, and error handling pattern are all correct and consistent with the existing code structure.

commands/randomjoke.js (1)

12-16: LGTM! Clean migration to fetch.

The axios-to-fetch migration follows the correct pattern with proper response.ok check and JSON parsing. Consistent with the other fetch implementations in this PR.

.gitignore (1)

10-13: Good additions for the persistence and SQLite migration.

Adding persistence/ and the SQLite WAL/SHM file patterns (*.db-wal, *.db-shm) correctly aligns with the database relocation and Bun's SQLite implementation which uses WAL mode by default.

classes/babyScheduler.js (1)

3-3: LGTM! Correct adjustment for Bun runtime.

The comment accurately documents that Bun automatically loads .env files, making explicit dotenv.config() unnecessary.

commands/hsrProfile.js (2)

38-44: LGTM! Clean fetch migration with proper error handling.

Good error handling pattern with early return on non-OK responses. Logging the status code and statusText provides useful debugging information.


99-109: Formatting-only changes, no functional impact.

The embed description construction logic is unchanged; these are just line continuation style adjustments.

commands/cat.js (1)

34-52: LGTM! Well-structured fetch migration with good error handling.

Both fetch calls follow the correct pattern with response.ok checks. The additional validation for empty picData array (lines 46-48) is good defensive coding that preserves the original error handling behavior.

Dockerfile (1)

1-55: Well-structured multi-stage Dockerfile.

Good practices observed:

  • Multi-stage build reducing final image size
  • Non-root bun user for security
  • Cache mount for dependency installation
  • Proper cleanup of apt lists
  • Runtime-only libraries in final stage
commands/genshinProfile.js (1)

71-75: Formatting changes are cosmetic only.

These string concatenation adjustments maintain consistent indentation without changing functionality.

.github/workflows/deploy.yml (1)

9-30: Build-and-push job is well structured.

Good setup with Docker Buildx, proper login action, and cache-enabled builds. The single-platform (linux/amd64) approach is appropriate if that's the target deployment architecture.

utils/log.js (1)

47-53: Exporting log file paths is a good addition.

Exposing logFilePath and logErrorFilePath allows other modules (e.g., log rotation utilities, diagnostics commands) to reference the log locations consistently.

package.json (1)

7-13: Good dual-runtime script setup.

Providing both Bun (start, dev, test) and Node (start:node, dev:node, test:jest) variants allows flexibility during migration and for developers who may not have Bun installed locally.

database/Database.js (8)

10-25: Good migration pattern preserving async compatibility.

The async IIFE stored in this.ready maintains backward compatibility with code that awaits database initialization while wrapping the synchronous bun:sqlite operations. WAL mode is a good choice for improved concurrency.


36-38: Table/column names are interpolated directly into SQL.

Since tableJSON originates from the internal ./tables module (trusted config), this is acceptable. Just ensure these table definitions are never derived from user input, as SQLite doesn't support parameterized identifiers.


44-57: Sequential column addition is safer for migrations.

Good change from Promise.all to sequential for...of loop. This ensures schema migrations complete in order and any errors are easier to trace.


60-81: Proper initialization sequence.

Enabling foreign keys after all tables are created (line 80) is the correct order to avoid constraint violations during setup.


83-88: Correct synchronous bun:sqlite pattern.

PRAGMA statements don't support parameterization, so the interpolation is expected. The .query().all() usage is correct for bun:sqlite.


107-117: Correct single-row fetch pattern.

The .get() method and null-coalescing logic are appropriate for bun:sqlite's API.


119-129: Correct multi-row fetch pattern.

The .all() method usage and empty array fallback on error are appropriate.


131-154: Dump methods correctly use the updated query interface.

The dumpTable method and its variants properly delegate to executeSelectAllQuery, maintaining the same API while using the new bun:sqlite backend.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 37 to 39
uses: appleboy/ssh-action@master
with:
host: 51.75.21.146
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

Hardcoded IP address and unpinned action version.

Two concerns:

  1. The VM IP address 51.75.21.146 is hardcoded. Consider using a GitHub secret (e.g., ${{ secrets.DEPLOY_HOST }}) for maintainability and to avoid exposing infrastructure details.
  2. appleboy/ssh-action@master is unpinned. Using @master can introduce breaking changes unexpectedly. Pin to a specific version tag (e.g., @v1.0.3).
🔧 Suggested improvement
       - name: Deploy to VM
-        uses: appleboy/ssh-action@master
+        uses: appleboy/ssh-action@v1.0.3
         with:
-          host: 51.75.21.146
+          host: ${{ secrets.DEPLOY_HOST }}
           username: deploy
📝 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
uses: appleboy/ssh-action@master
with:
host: 51.75.21.146
- name: Deploy to VM
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: deploy
🤖 Prompt for AI Agents
In @.github/workflows/deploy.yml around lines 37 - 39, Replace the hardcoded
host value and unpinned action reference: swap the literal IP "51.75.21.146"
used with the appleboy/ssh-action invocation to a GitHub Actions secret (e.g.,
use `${{ secrets.DEPLOY_HOST }}`) and change the action reference
`appleboy/ssh-action@master` to a fixed release tag (e.g.,
`appleboy/ssh-action@vX.Y.Z`) to avoid breaking changes; update the workflow
inputs where `host:` is set and the `uses:` line accordingly.

Comment thread .github/workflows/deploy.yml
Comment thread Dockerfile
Comment on lines +17 to +18
# 2. [NEW] Install node-gyp globally so 'canvas' can use it to compile
RUN bun add -g node-gyp
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

🧩 Analysis chain

🌐 Web query:

how to install node-gyp globally Bun Docker container native module compilation

💡 Result:

Short answer: install the system build tools + Python, then globally install node-gyp (npm -g) in your Bun-based image so lifecycle scripts and native builds can run. Example Dockerfile + notes:

Dockerfile (Debian/Ubuntu-based Bun image)

  • installs Python, make and C/C++ toolchain
  • installs node-gyp globally
FROM jarredsumner/bun:latest    # or bun/base (use the official Bun image you prefer)

# install system build deps
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 python3-dev build-essential ca-certificates \
  && rm -rf /var/lib/apt/lists/*

# ensure python points to python3 for node-gyp
RUN ln -sf /usr/bin/python3 /usr/bin/python

# install node-gyp globally so lifecycle scripts can call it
RUN npm install -g node-gyp

WORKDIR /app
COPY package.json package-lock.json* bun.lockb* ./
# use bun to install packages (node-gyp will be available for native modules)
RUN bun install

COPY . .
CMD ["bun", "run", "start"]

Key notes and why:

  • node-gyp requires Python and a C/C++ toolchain (make/g++). Install via apt (or apk for Alpine). (github.com)
  • Bun will fallback/symlink to bunx/node-gyp in some cases, but having node-gyp and system build tools in the container avoids lifecycle errors and makes native module compilation reliable. (bun.com)
  • On Alpine use apk add build-base python3 and adjust python symlink; on Debian/Ubuntu use build-essential + python3 as shown. See node-gyp docs and common Docker advice. (github.com)

If you want a smaller image, run the build step in a builder stage (install build deps + node-gyp, run bun install, then copy built artifacts to a slimmer runtime image).

Citations:


Use npm install -g node-gyp instead of bun add -g node-gyp for global installation.

bun add -g is non-standard for node-gyp. Official guidance recommends npm install -g node-gyp in Bun environments to ensure node-gyp is available during lifecycle scripts and native module compilation. While Bun can fallback to bundled node-gyp in some cases, explicit npm installation prevents lifecycle errors and ensures reliable builds for packages like canvas.

Additionally, ensure system build dependencies are installed: apt-get install -y python3 python3-dev build-essential (and create the Python symlink if needed: ln -sf /usr/bin/python3 /usr/bin/python).

🤖 Prompt for AI Agents
In `@Dockerfile` around lines 17 - 18, The Dockerfile currently uses the
non-standard global install command "RUN bun add -g node-gyp"; replace this with
an explicit "npm install -g node-gyp" to ensure node-gyp is available for native
compilations, and add system build deps (install python3, python3-dev,
build-essential via apt-get) plus a python symlink (ln -sf /usr/bin/python3
/usr/bin/python) before installing node-gyp so packages like canvas can compile
reliably.

Comment thread package.json
"@google/generative-ai": "^0.16.0",
"axios": "^1.7.3",
"canvas": "^2.11.2",
"canvas": "^3.0.0-rc3",
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

🧩 Analysis chain

🌐 Web query:

canvas npm package latest version 2025 release

💡 Result:

The latest canvas (node-canvas) npm package version is 3.2.0 (published/released in 2025). [1][2]

Sources:
[1] npm package page for canvas.
[2] Maven/NPM mirror listing (canvas 3.2.0, Aug 19, 2025).


Update canvas to a stable version.

canvas@^3.0.0-rc3 is a release candidate version. Stable releases are now available, including version 3.2.0. Use ^3.2.0 or another stable release instead of the pre-release version for production code.

🤖 Prompt for AI Agents
In `@package.json` at line 23, Replace the pre-release canvas dependency entry
"canvas": "^3.0.0-rc3" in package.json with a stable release (for example
"canvas": "^3.2.0") so the project uses a non-RC version; update the version
string, run your package manager's install (npm/yarn/pnpm) to refresh lockfiles,
and verify builds/tests pass after the upgrade.

Comment thread package.json
Comment on lines +56 to +60
},
"trustedDependencies": [
"canvas",
"skia-canvas"
]
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if skia-canvas is used anywhere in the codebase
rg 'skia-canvas' --type js || echo "skia-canvas not referenced in JS files"

Repository: Mewtwo2387/silverwolf

Length of output: 103


🏁 Script executed:

# Also check package.json to see actual dependencies
cat package.json | head -100

Repository: Mewtwo2387/silverwolf

Length of output: 1555


🏁 Script executed:

# Search more broadly for skia-canvas references (not just JS)
rg 'skia-canvas' || echo "skia-canvas not referenced anywhere in codebase"

Repository: Mewtwo2387/silverwolf

Length of output: 95


Remove skia-canvas from trustedDependencies.

skia-canvas is not listed in dependencies and is not referenced anywhere in the codebase. It should be removed from trustedDependencies as it serves no purpose. Keep only canvas, which is an actual dependency.

🤖 Prompt for AI Agents
In `@package.json` around lines 56 - 60, The trustedDependencies array currently
includes "skia-canvas" which isn’t a real dependency or referenced; remove the
"skia-canvas" entry from the trustedDependencies list so it only contains
"canvas", leaving the trustedDependencies array with the actual dependency
("canvas") and ensuring no other parts of the code or package.json reference
"skia-canvas".

Comment thread utils/accessControl.js
require('dotenv').config();
// Note: Bun automatically reads .env files

const ALLOWED_USERS = process.env.ALLOWED_USERS.split(',');
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 | 🔴 Critical

Missing null check will crash if ALLOWED_USERS is not set.

If the environment variable is missing, process.env.ALLOWED_USERS is undefined, and calling .split(',') will throw a TypeError.

Suggested fix
-const ALLOWED_USERS = process.env.ALLOWED_USERS.split(',');
+const ALLOWED_USERS = process.env.ALLOWED_USERS ? process.env.ALLOWED_USERS.split(',') : [];
📝 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 ALLOWED_USERS = process.env.ALLOWED_USERS.split(',');
const ALLOWED_USERS = process.env.ALLOWED_USERS ? process.env.ALLOWED_USERS.split(',') : [];
🤖 Prompt for AI Agents
In `@utils/accessControl.js` at line 4, ALLOWED_USERS initialization calls
process.env.ALLOWED_USERS.split(',') which throws if ALLOWED_USERS is undefined;
update the code that defines ALLOWED_USERS to guard against a missing env var by
checking process.env.ALLOWED_USERS first and defaulting to an empty string or
empty array, e.g., use a conditional or fallback (refer to the ALLOWED_USERS
constant and process.env.ALLOWED_USERS) so the value becomes an empty array when
unset and downstream code won’t crash.

@Mewtwo2387 Mewtwo2387 merged commit e53faed into master Jan 14, 2026
1 check was pending
@Mewtwo2387 Mewtwo2387 deleted the DockerTest branch March 27, 2026 01:52
@coderabbitai coderabbitai Bot mentioned this pull request Mar 31, 2026
@coderabbitai coderabbitai Bot mentioned this pull request May 5, 2026
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