Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huge Migration #17

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open

Huge Migration #17

wants to merge 42 commits into from

Conversation

AstroX11
Copy link
Owner

@AstroX11 AstroX11 commented Jan 18, 2025

Fix all most all things

Summary by CodeRabbit

Release Notes

  • Code Quality and Maintenance

    • Added ESLint and Prettier configurations for consistent code formatting.
    • Refactored database interactions from Sequelize to file-based JSON storage.
    • Improved code readability and standardized formatting across project files.
  • New Features

    • Added new commands in plugins:
      • Pairing code retrieval.
      • Support contact information.
      • Mathematical expression solving.
      • URL shortening.
      • GitHub repository branch download.
      • Image processing tools (enhance, recolor, dehaze).
      • Anti-call and anti-delete functionality streamlined.
      • Added commands for managing notes and greetings.
      • Enhanced BGM management with new functionalities.
      • Introduced a streamlined auto-react feature.
      • Added commands for managing user bans and anti-spam settings.
      • Improved greeting management with file-based storage.
  • Performance and Stability

    • Simplified data management by transitioning from database to JSON file storage.
    • Enhanced error handling in various plugin and utility functions.
    • Improved configuration management.
  • Documentation

    • Updated README with more detailed setup and deployment instructions.
    • Added badges for repository interaction.
    • Clarified session and deployment guidelines.

This release focuses on improving code quality, adding utility features, and simplifying the project's data management approach.

Copy link

coderabbitai bot commented Jan 18, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive refactoring of the project's data management approach, transitioning from a Sequelize-based database system to a file-based JSON storage mechanism. The changes span multiple files across the project, focusing on simplifying data persistence and reducing database dependencies. Key modifications include replacing database models with JSON file storage, updating import statements, and modifying functions to read, write, and manipulate data directly through file system operations.

Changes

File/Directory Change Summary
.github/ Multiple formatting and configuration updates across workflow and template files
bot/ Code formatting and minor logic adjustments in various bot-related files
lib/ Significant changes in client and event handling logic
plugins/ Reformatting of bot commands and some functionality updates
sql/ Complete transition from Sequelize database to JSON file-based storage
config.js, index.js Minor updates and formatting changes
package.json Added linting and formatting scripts, new dev dependencies

Poem

🐰 A Rabbit's Ode to Code Transformation

From database rows to JSON's embrace,
Sequelize fades with elegant grace.
File-based storage, simple and light,
Refactoring code with pure delight!

🌟 Hop, hop, hooray for cleaner design! 🌟

Finishing Touches

  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

plugins/plugin.js Dismissed Show dismissed Hide dismissed
@AstroX11 AstroX11 closed this Jan 18, 2025
@AstroX11 AstroX11 reopened this Jan 18, 2025
coderabbitai bot added a commit that referenced this pull request Jan 18, 2025
Docstrings generation was requested by @AstroX11.

* #17 (comment)

The following files were modified:

* `.github/js/panel.js`
* `bot/antidelete.js`
* `bot/antilink.js`
* `bot/antispam.js`
* `bot/antiviewonce.js`
* `bot/antiword.js`
* `bot/autokick.js`
* `bot/greetings.js`
* `bot/group_events.js`
* `bot/stickercmd.js`
* `lib/events.js`
* `lib/files.js`
* `lib/logger.js`
* `lib/message.js`
* `lib/plugins.js`
* `lib/session.js`
* `plugins/afk.js`
* `plugins/call.js`
* `plugins/structure.js`
* `sql/afk.js`
* `sql/antibot.js`
* `sql/anticall.js`
* `sql/antidelete.js`
* `sql/antilink.js`
* `sql/antispam.js`
* `sql/antivv.js`
* `sql/antiword.js`
* `sql/areact.js`
* `sql/bgm.js`
* `sql/config.js`
* `sql/filters.js`
* `sql/greetings.js`
* `sql/mention.js`
* `sql/notes.js`
* `sql/plugins.js`
* `sql/scheduler.js`
* `sql/stickercmd.js`
Copy link

coderabbitai bot commented Jan 18, 2025

Note

We have generated docstrings for this pull request, at #18

@AstroX11 AstroX11 added documentation Improvements or additions to documentation enhancement New feature or request labels Jan 18, 2025
@AstroX11 AstroX11 self-assigned this Jan 18, 2025
@AstroX11 AstroX11 marked this pull request as draft January 18, 2025 07:23
@AstroX11 AstroX11 marked this pull request as ready for review January 18, 2025 13:00
Copy link

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (208)
sql/areact.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol in Node.js built-in module imports

To explicitly indicate that you are importing Node.js built-in modules, you should prefix the module names with 'node:' in your import statements. This is a recommended best practice in recent Node.js versions.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


6-8: ⚠️ Potential issue

Ensure 'store' directory exists before writing 'areact.json'

If the 'store' directory does not exist, fs.writeFileSync will throw an error when attempting to write 'areact.json'. You need to ensure the directory exists before writing the file.

Apply this diff to create the directory if it doesn't exist:

 if (!fs.existsSync(store)) {
+  fs.mkdirSync(path.dirname(store), { recursive: true });
   fs.writeFileSync(store, JSON.stringify({ status: false }));
 }

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

sql/antidelete.js (1)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol in Node.js built-in module imports

To explicitly indicate that you are importing Node.js built-in modules, you should prefix the module names with 'node:' in your import statements. This is a recommended best practice in recent Node.js versions.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/antispam.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol in Node.js built-in module imports

To explicitly indicate that you are importing Node.js built-in modules, you should prefix the module names with 'node:' in your import statements. This is a recommended best practice in recent Node.js versions.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
 import { isJidGroup } from 'baileys';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


7-7: ⚠️ Potential issue

Ensure 'store' directory exists before writing 'antispam.json'

If the 'store' directory does not exist, fs.writeFileSync will throw an error when attempting to write 'antispam.json'. You need to ensure the directory exists before writing the file.

Apply this diff to create the directory if it doesn't exist and use proper braces:

-if (!fs.existsSync(store)) fs.writeFileSync(store, JSON.stringify({}));
+if (!fs.existsSync(store)) {
+  fs.mkdirSync(path.dirname(store), { recursive: true });
+  fs.writeFileSync(store, JSON.stringify({}));
+}
📝 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.

if (!fs.existsSync(store)) {
  fs.mkdirSync(path.dirname(store), { recursive: true });
  fs.writeFileSync(store, JSON.stringify({}));
}
sql/antivv.js (4)

9-10: 🧹 Nitpick (assertive)

Use asynchronous file operations within async functions

The functions are marked async but use synchronous file operations like fs.readFileSync and fs.writeFileSync. This can block the event loop and degrade performance, especially under heavy load. Consider using asynchronous versions of these methods with await.

Refactored code:

-const readDB = () => JSON.parse(fs.readFileSync(store, 'utf8'));
+const readDB = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));

-const writeDB = (data) => fs.writeFileSync(store, JSON.stringify(data, null, 2));
+const writeDB = async (data) => await fs.promises.writeFile(store, JSON.stringify(data, null, 2));

 async function setViewOnce(status) {
-  const db = readDB();
+  const db = await readDB();
   db.isEnabled = status;
-  writeDB(db);
+  await writeDB(db);
   return true;
 }

 async function isViewOnceEnabled() {
-  const db = readDB();
+  const db = await readDB();
   return db.isEnabled;
 }

 async function setViewOnceType(type) {
-  const db = readDB();
+  const db = await readDB();
   db.type = type;
-  writeDB(db);
+  await writeDB(db);
   return true;
 }

 async function getSettings() {
-  const db = readDB();
+  const db = await readDB();
   return db;
 }

Also applies to: 13-16, 20-21, 25-28, 32-33


9-10: ⚠️ Potential issue

Handle JSON parsing errors to prevent crashes

When reading and parsing the JSON file, errors may occur if the file is corrupted or improperly formatted. Adding error handling ensures that the application can handle such situations gracefully.

Apply this diff:

-const readDB = () => JSON.parse(fs.readFileSync(store, 'utf8'));
+const readDB = async () => {
+  try {
+    const data = await fs.promises.readFile(store, 'utf8');
+    return JSON.parse(data);
+  } catch (error) {
+    console.error('Failed to read or parse the JSON file:', error);
+    return { type: 'all', isEnabled: false };
+  }
+};
📝 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.

const readDB = async () => {
  try {
    const data = await fs.promises.readFile(store, 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read or parse the JSON file:', error);
    return { type: 'all', isEnabled: false };
  }
};
const writeDB = (data) => fs.writeFileSync(store, JSON.stringify(data, null, 2));

6-7: 🧹 Nitpick (assertive)

Wrap single-statement 'if' blocks in curly braces for consistency

Even when an if block contains only a single statement, it's a good practice to enclose it in curly braces {}. This improves readability and helps prevent errors if additional statements are added later.

Apply this diff:

 if (!fs.existsSync(store))
-  fs.writeFileSync(store, JSON.stringify({ type: 'all', isEnabled: false }));
+{
+  fs.writeFileSync(store, JSON.stringify({ type: 'all', isEnabled: false }));
+}
📝 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.

if (!fs.existsSync(store))
{
  fs.writeFileSync(store, JSON.stringify({ type: 'all', isEnabled: false }));
}

1-2: 🛠️ Refactor suggestion

Use 'node:' protocol when importing Node.js built-in modules

According to best practices and the static analysis hints, it's recommended to use the node: protocol when importing Node.js built-in modules to make it explicit that they are core modules.

Apply this diff to fix the issue:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/afk.js (4)

7-8: 🧹 Nitpick (assertive)

Wrap single-statement 'if' blocks in curly braces for consistency

Including curly braces {} around single-statement if blocks enhances readability and helps prevent future bugs if more statements are added.

Apply this diff:

 if (!fs.existsSync(store))
-  fs.writeFileSync(store, JSON.stringify({ message: null, timestamp: null }));
+{
+  fs.writeFileSync(store, JSON.stringify({ message: null, timestamp: null }));
+}

Apply similar changes to other instances in the file.

Also applies to: 17-18, 25-26


9-12: 🧹 Nitpick (assertive)

Use asynchronous file operations within async functions

Using synchronous file operations like fs.readFileSync and fs.writeFileSync inside async functions can block the event loop. It's better to use asynchronous methods with await to improve performance.

Refactored code:

 export async function getAfkMessage() {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify({ message: null, timestamp: null }));
+    await fs.promises.writeFile(store, JSON.stringify({ message: null, timestamp: null }));
   }
-  const data = JSON.parse(fs.readFileSync(store, 'utf8'));
+  const data = JSON.parse(await fs.promises.readFile(store, 'utf8'));
   if (data.message && data.timestamp) {
     return { message: data.message, timestamp: data.timestamp };
   }
   return null;
 }

 export const setAfkMessage = async (afkMessage, timestamp) => {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify({ message: null, timestamp: null }));
+    await fs.promises.writeFile(store, JSON.stringify({ message: null, timestamp: null }));
   }
   const data = { message: afkMessage, timestamp };
-  fs.writeFileSync(store, JSON.stringify(data, null, 2));
+  await fs.promises.writeFile(store, JSON.stringify(data, null, 2));
   return data;
 };

 export const delAfkMessage = async () => {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify({ message: null, timestamp: null }));
+    await fs.promises.writeFile(store, JSON.stringify({ message: null, timestamp: null }));
   }
   const data = { message: null, timestamp: null };
-  fs.writeFileSync(store, JSON.stringify(data, null, 2));
+  await fs.promises.writeFile(store, JSON.stringify(data, null, 2));
 };

Also applies to: 19-21, 27-28


9-12: ⚠️ Potential issue

Handle JSON parsing errors to prevent crashes

Errors may occur when parsing the JSON file if it's corrupted or improperly formatted. Adding error handling will make the application more robust.

Apply this diff:

-  const data = JSON.parse(fs.readFileSync(store, 'utf8'));
+  let data;
+  try {
+    data = JSON.parse(await fs.promises.readFile(store, 'utf8'));
+  } catch (error) {
+    console.error('Failed to read or parse the JSON file:', error);
+    data = { message: null, timestamp: null };
+  }
📝 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.

  let data;
  try {
    data = JSON.parse(await fs.promises.readFile(store, 'utf8'));
  } catch (error) {
    console.error('Failed to read or parse the JSON file:', error);
    data = { message: null, timestamp: null };
  }
  if (data.message && data.timestamp) {
    return { message: data.message, timestamp: data.timestamp };
  }

1-2: 🛠️ Refactor suggestion

Use 'node:' protocol when importing Node.js built-in modules

As per Node.js best practices and the static analysis hints, you should import built-in modules using the node: protocol to make it explicit.

Apply this diff:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/akick.js (4)

10-10: 🧹 Nitpick (assertive)

Wrap single-statement 'if' blocks in curly braces for consistency

Using curly braces {} around single-statement if blocks improves readability and prevents potential issues if more statements are added later.

Apply this diff:

 if (!fs.existsSync(store))
-  fs.writeFileSync(store, JSON.stringify([]));
+{
+  fs.writeFileSync(store, JSON.stringify([]));
+}

Apply similar changes to lines 21 and 31.

Also applies to: 21-21, 31-31


6-7: 🧹 Nitpick (assertive)

Use asynchronous file operations within async functions

Synchronous file operations inside async functions can block the event loop. It's advisable to use asynchronous methods with await to enhance performance.

Refactored code:

-const readDB = () => JSON.parse(fs.readFileSync(store, 'utf8'));
+const readDB = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));

-const writeDB = (data) => fs.writeFileSync(store, JSON.stringify(data, null, 2));
+const writeDB = async (data) => await fs.promises.writeFile(store, JSON.stringify(data, null, 2));

 export const addAKick = async (groupJid, userJid) => {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify([]));
+    await fs.promises.writeFile(store, JSON.stringify([]));
   }
-  const data = readDB();
+  const data = await readDB();
   if (data.some((record) => record.groupJid === groupJid && record.userJid === userJid)) {
     return false;
   }
   data.push({ groupJid, userJid });
-  writeDB(data);
+  await writeDB(data);
   return true;
 };

 export const delKick = async (groupJid, userJid) => {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify([]));
+    await fs.promises.writeFile(store, JSON.stringify([]));
   }
-  const data = readDB();
+  const data = await readDB();
   const filteredData = data.filter(
     (record) => !(record.groupJid === groupJid && record.userJid === userJid)
   );
-  writeDB(filteredData);
+  await writeDB(filteredData);
   return data.length !== filteredData.length;
 };

 export const getKicks = async (groupJid, userJid = null) => {
   if (!fs.existsSync(store)) {
-    fs.writeFileSync(store, JSON.stringify([]));
+    await fs.promises.writeFile(store, JSON.stringify([]));
   }
-  const data = readDB();
+  const data = await readDB();
   return data.filter(
     (record) => record.groupJid === groupJid && (!userJid || record.userJid === userJid)
   );
 };

Also applies to: 11-17, 22-27, 32-36


6-7: ⚠️ Potential issue

Handle JSON parsing errors to prevent crashes

Parsing errors can occur if the JSON file is corrupted. Adding error handling makes the code more robust against such issues.

Apply this diff:

-const readDB = () => JSON.parse(fs.readFileSync(store, 'utf8'));
+const readDB = async () => {
+  try {
+    const data = await fs.promises.readFile(store, 'utf8');
+    return JSON.parse(data);
+  } catch (error) {
+    console.error('Failed to read or parse the JSON file:', error);
+    return [];
+  }
+};
📝 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.

const readDB = async () => {
  try {
    const data = await fs.promises.readFile(store, 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read or parse the JSON file:', error);
    return [];
  }
};
const writeDB = (data) => fs.writeFileSync(store, JSON.stringify(data, null, 2));

1-2: 🛠️ Refactor suggestion

Use 'node:' protocol when importing Node.js built-in modules

Following Node.js recommendations and the static analysis hints, import built-in modules using the node: protocol.

Apply this diff:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/antibot.js (3)

10-11: 🧹 Nitpick (assertive)

Refactor repeated file initialization checks

The checks to initialize the antibotStore file are repeated in multiple functions. Consider refactoring to initialize the file once or create a helper function to reduce code duplication.

Apply this diff to refactor the initialization:

+// Ensure the antibotStore file exists
+if (!fs.existsSync(antibotStore)) fs.writeFileSync(antibotStore, JSON.stringify([]));

+// Optionally, create a helper function
+const ensureStore = () => {
+  if (!fs.existsSync(antibotStore)) fs.writeFileSync(antibotStore, JSON.stringify([]));
+};

 async function setAntibot(jid, enabled) {
-  if (!fs.existsSync(antibotStore)) fs.writeFileSync(antibotStore, JSON.stringify([]));
+  ensureStore();
   const data = readDB();
   // ...
 }

 async function delAntibot(jid) {
-  if (!fs.existsSync(antibotStore)) fs.writeFileSync(antibotStore, JSON.stringify([]));
+  ensureStore();
   const data = readDB();
   // ...
 }

 async function getAntibot(jid) {
-  if (!fs.existsSync(antibotStore)) fs.writeFileSync(antibotStore, JSON.stringify([]));
+  ensureStore();
   const data = readDB();
   // ...
 }

Also applies to: 25-26, 33-34


6-7: 🧹 Nitpick (assertive)

Add error handling for file operations

Currently, file reads and writes do not handle possible errors, which could lead to unhandled exceptions if the file is inaccessible or corrupted. Implement error handling to make the code more robust.

Consider wrapping file operations in try-catch blocks or using asynchronous versions with error callbacks.

 const readDB = () => {
+  try {
     return JSON.parse(fs.readFileSync(antibotStore, 'utf8'));
+  } catch (error) {
+    console.error('Error reading antibotStore:', error);
+    return [];
+  }
 };

 const writeDB = (data) => {
+  try {
     fs.writeFileSync(antibotStore, JSON.stringify(data, null, 2));
+  } catch (error) {
+    console.error('Error writing to antibotStore:', error);
+  }
 };

Also applies to: 10-11, 25-26, 33-34


1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

For clarity and to signal that these modules are native to Node.js, it's recommended to use the 'node:' protocol in your import statements.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/ban.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

For clarity and to indicate that these are Node.js native modules, it's recommended to use the 'node:' protocol in import statements.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


43-43: 🛠️ Refactor suggestion

Avoid reassigning function parameters

Reassigning the jid parameter can lead to unintended side effects and confusion. Instead, use a local variable to handle default values.

Apply this diff to fix the issue:

 export const isBanned = async (jid) => {
-  if (!jid) jid = '';
+  const checkJid = jid || '';
   const bannedUsers = await getBanned();
-  return bannedUsers.includes(jid);
+  return bannedUsers.includes(checkJid);
 };
📝 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.

export const isBanned = async (jid) => {
  const checkJid = jid || '';
  const bannedUsers = await getBanned();
  return bannedUsers.includes(checkJid);
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 43-43: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)

sql/alive.js (3)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

To make it explicit that you're importing Node.js core modules, it's recommended to use the 'node:' protocol.

Apply this diff to update the imports:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


6-9: 🧹 Nitpick (assertive)

Add error handling for file operations

File operations like reading and writing to the JSON file might fail due to I/O errors. Adding error handling will make your code more robust.

Consider wrapping file operations in try-catch blocks:

 const readDB = () => {
+  try {
     return JSON.parse(fs.readFileSync(store, 'utf8'));
+  } catch (error) {
+    console.error('Error reading alive.json:', error);
+    return { message: null };
+  }
 };

 const writeDB = (data) => {
+  try {
     fs.writeFileSync(store, JSON.stringify(data, null, 2));
+  } catch (error) {
+    console.error('Error writing to alive.json:', error);
+  }
 };
📝 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.

const store = path.join('store', 'alive.json');

const readDB = () => {
  try {
    return JSON.parse(fs.readFileSync(store, 'utf8'));
  } catch (error) {
    console.error('Error reading alive.json:', error);
    return { message: null };
  }
};

const writeDB = (data) => {
  try {
    fs.writeFileSync(store, JSON.stringify(data, null, 2));
  } catch (error) {
    console.error('Error writing to alive.json:', error);
  }
};

35-37: ⚠️ Potential issue

Multiple replacements of '&facts' overwrite each other

You're replacing the '&facts' placeholder three times, which means only the last replacement (XSTRO.rizz()) will be used. To include all three pieces of information, consider using different placeholders or combining them.

Apply this diff to fix the issue:

Option 1: Use different placeholders

     .replace(/&facts/g, await XSTRO.facts())
-    .replace(/&facts/g, await XSTRO.quotes())
-    .replace(/&facts/g, await XSTRO.rizz());
+    .replace(/&quotes/g, await XSTRO.quotes())
+    .replace(/&rizz/g, await XSTRO.rizz());

Then update your message template to include &facts, &quotes, and &rizz.

Option 2: Combine the outputs

     .replace(/&facts/g, 
-      await XSTRO.facts())
-    .replace(/&facts/g, await XSTRO.quotes())
-    .replace(/&facts/g, await XSTRO.rizz());
+      `${await XSTRO.facts()}\n${await XSTRO.quotes()}\n${await XSTRO.rizz()}`
+    );
📝 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.

    .replace(/&facts/g, await XSTRO.facts())
    .replace(/&quotes/g, await XSTRO.quotes())
    .replace(/&rizz/g, await XSTRO.rizz());
    .replace(/&facts/g, 
      `${await XSTRO.facts()}\n${await XSTRO.quotes()}\n${await XSTRO.rizz()}`
    );
sql/bgm.js (2)

1-1: 🛠️ Refactor suggestion

Use the 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the imports:

-import fs from 'fs';
+import fs from 'node:fs';

-import path from 'path';
+import path from 'node:path';

Also applies to: 2-2

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


12-29: 🧹 Nitpick (assertive)

Remove unnecessary 'async' keywords from synchronous functions

The functions addBgm, getBgmResponse, deleteBgm, and getBgmList are declared as async but do not perform any asynchronous operations or contain await expressions. Removing the async keyword improves readability and avoids confusion.

Apply this diff to remove the async keyword:

-async function addBgm(word, response) {
+function addBgm(word, response) {
  // function body...
}

-async function getBgmResponse(word) {
+function getBgmResponse(word) {
  // function body...
}

-async function deleteBgm(word) {
+function deleteBgm(word) {
  // function body...
}

-async function getBgmList() {
+function getBgmList() {
  // function body...
}

Also applies to: 33-40, 44-55, 61-62

sql/group_event.js (2)

1-1: 🛠️ Refactor suggestion

Use the 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the imports:

-import fs from 'fs';
+import fs from 'node:fs';

-import path from 'path';
+import path from 'node:path';

Also applies to: 2-2

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


19-30: 🧹 Nitpick (assertive)

Remove unnecessary 'async' keywords from synchronous functions

The functions enableGroupEvents, disableGroupEvents, and isGroupEventEnabled are declared as async but do not perform any asynchronous operations or contain await expressions. Removing the async keyword improves readability and avoids confusion.

Apply this diff to remove the async keyword:

-export const enableGroupEvents = async (jid) => {
+export const enableGroupEvents = (jid) => {
  // function body...
};

-export const disableGroupEvents = async (jid) => {
+export const disableGroupEvents = (jid) => {
  // function body...
};

-export const isGroupEventEnabled = async (jid) => {
+export const isGroupEventEnabled = (jid) => {
  // function body...
};

Additionally, update the JSDoc comments to reflect that the functions return synchronous values:

- * @returns {Promise<boolean>} - Always returns true upon success.
+ * @returns {boolean} - Always returns true upon success.

Apply this change to all relevant JSDoc comments.

Also applies to: 38-49, 57-60

sql/plugins.js (2)

1-1: 🛠️ Refactor suggestion

Use the 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the imports:

-import fs from 'fs';
+import fs from 'node:fs';

-import path from 'path';
+import path from 'node:path';

Also applies to: 2-2

🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


18-29: 🧹 Nitpick (assertive)

Remove unnecessary 'async' keywords from synchronous functions

The functions addPlugin, updatePlugin, removePlugin, and getPlugins are declared as async but do not perform any asynchronous operations or contain await expressions. Removing the async keyword improves readability and avoids confusion.

Apply this diff to remove the async keyword:

-export async function addPlugin(name) {
+export function addPlugin(name) {
  // function body...
}

-export async function updatePlugin(name, newName) {
+export function updatePlugin(name, newName) {
  // function body...
}

-export async function removePlugin(name) {
+export function removePlugin(name) {
  // function body...
}

-export async function getPlugins() {
+export function getPlugins() {
  // function body...
}

Additionally, update the JSDoc comments to reflect that the functions return synchronous values.

Also applies to: 38-48, 57-66, 74-75

sql/stickercmd.js (3)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

To clearly indicate that the modules are Node.js built-ins and to enhance code readability, it's recommended to prefix the module names with the 'node:' protocol.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


65-83: 🧹 Nitpick (assertive)

Rename isStickerCmd to reflect its functionality

The function isStickerCmd returns an object containing exists and command properties rather than a boolean value. To improve clarity, consider renaming the function to getStickerCmd to better represent its purpose.

Apply this diff to rename the function:

-export async function isStickerCmd(id) {
+export async function getStickerCmd(id) {

Ensure that all references to this function are updated accordingly throughout the codebase.

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

export async function getStickerCmd(id) {
  const cmds = readStickerCmds();
  const stickerCmd = cmds.find((stickerCmd) => stickerCmd.id === id);

  if (stickerCmd) {
    return {
      exists: true,
      command: {
        cmd: stickerCmd.cmd,
        id: stickerCmd.id,
      },
    };
  }

  return {
    exists: false,
    command: null,
  };
}

10-11: 🧹 Nitpick (assertive)

Consider using asynchronous file operations to prevent blocking the event loop

Using synchronous file operations like fs.readFileSync and fs.writeFileSync can block the event loop, which may hinder performance, especially under heavy load or when scaling. Consider using asynchronous file operations to improve scalability and responsiveness.

Apply this diff to refactor the file operations:

-const readStickerCmds = () => JSON.parse(fs.readFileSync(store, 'utf8'));
-const writeStickerCmds = (cmds) => fs.writeFileSync(store, JSON.stringify(cmds, null, 2));
+const readStickerCmds = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
+const writeStickerCmds = async (cmds) => await fs.promises.writeFile(store, JSON.stringify(cmds, null, 2));

Update the functions that call readStickerCmds and writeStickerCmds to handle the promises appropriately:

-export async function setcmd(cmd, id) {
+export async function setcmd(cmd, id) {
+  const cmds = await readStickerCmds();
   // rest of the code
📝 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.

const readStickerCmds = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
const writeStickerCmds = async (cmds) => await fs.promises.writeFile(store, JSON.stringify(cmds, null, 2));
sql/mention.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

To enhance clarity and explicitly indicate Node.js built-in modules, it's advisable to prefix the module names with the 'node:' protocol.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


10-11: 🧹 Nitpick (assertive)

Refactor synchronous file operations to asynchronous to improve performance

Synchronous file operations can block the event loop, potentially impacting the application's performance. Refactoring to use asynchronous file operations will enhance scalability and responsiveness.

Apply this diff to modify the file operations:

-const readMentions = () => JSON.parse(fs.readFileSync(store, 'utf8'));
-const writeMentions = (mentions) => fs.writeFileSync(store, JSON.stringify(mentions, null, 2));
+const readMentions = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
+const writeMentions = async (mentions) => await fs.promises.writeFile(store, JSON.stringify(mentions, null, 2));

Update the functions that use readMentions and writeMentions to handle the promises:

-export async function setMention(jid, message) {
+export async function setMention(jid, message) {
+  const mentions = await readMentions();
   // rest of the code

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

sql/filters.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

By prefixing the module names with the 'node:' protocol, you make it explicit that these are Node.js built-in modules, which improves code readability and maintainability.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


10-11: 🧹 Nitpick (assertive)

Optimize file operations by switching to asynchronous methods

The use of synchronous methods like fs.readFileSync and fs.writeFileSync can block the event loop and degrade performance under load. Refactoring to asynchronous methods will enhance the application's efficiency.

Apply this diff to refactor the file operations:

-const readFilters = () => JSON.parse(fs.readFileSync(store, 'utf8'));
-const writeFilters = (filters) => fs.writeFileSync(store, JSON.stringify(filters, null, 2));
+const readFilters = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
+const writeFilters = async (filters) => await fs.promises.writeFile(store, JSON.stringify(filters, null, 2));

Adjust the functions that call readFilters and writeFilters to handle the asynchronous operations:

-export async function addFilter(type, text, response) {
+export async function addFilter(type, text, response) {
+  const filters = await readFilters();
   // rest of the code
📝 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.

const readFilters = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
const writeFilters = async (filters) => await fs.promises.writeFile(store, JSON.stringify(filters, null, 2));
plugins/misc.js (4)

65-72: ⚠️ Potential issue

Sanitize user input to prevent code injection attacks.

Evaluating user-provided expressions using evaluate(match) can lead to security vulnerabilities if the input is not properly sanitized, as it might execute arbitrary code.

Implement input sanitization or limit the scope of allowed expressions:

async (message, match) => {
  if (!match) return await message.send('*Example: `.math 2 + 2`*');
  const msg = await message.send('*Calculating...*');
  try {
+   // Restrict allowed characters to prevent malicious input
+   if (!/^[0-9+\-*/().\s^%]*$/.test(match))
+     throw new Error('Invalid characters in expression');

    const result = evaluate(match);
    return await msg.edit(`Result: ${result}`);
  } catch {
    return await msg.edit(`_Syntax Error_`);
  }
}

Alternatively, consider using a safer evaluation method that doesn't execute arbitrary code.

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

    if (!match) return await message.send('*Example: `.math 2 + 2`*');
    const msg = await message.send('*Calculating...*');
    try {
      // Restrict allowed characters to prevent malicious input
      if (!/^[0-9+\-*/().\s^%]*$/.test(match))
        throw new Error('Invalid characters in expression');

      const result = evaluate(match);
      return await msg.edit(`Result: ${result}`);
    } catch {
      return await msg.edit(`_Syntax Error_`);
    }

84-90: 🧹 Nitpick (assertive)

Handle cases where user status is not accessible and improve message clarity.

If the user's status or setAt date is not available, the bot should inform the user more clearly.

Apply this diff to enhance the response:

async (message, match) => {
  const jid = await message.getUserJid(match);
  const { status, setAt } = await message.client.fetchStatus(jid);
  if (status && setAt) {
-   await message.send(`\`\`\`Bio: ${status}\nSetAt: ${setAt}\`\`\``);
+   const date = new Date(setAt).toLocaleString();
+   await message.send(`*Bio:* ${status}\n*Set At:* ${date}`);
  } else {
-   message.send(`_User's settings doesn't allow me to_`);
+   await message.send(`*Unable to retrieve bio for this user.*`);
  }
}
📝 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.

    const jid = await message.getUserJid(match);
    const { status, setAt } = await message.client.fetchStatus(jid);
    if (status && setAt) {
      const date = new Date(setAt).toLocaleString();
      await message.send(`*Bio:* ${status}\n*Set At:* ${date}`);
    } else {
      await message.send(`*Unable to retrieve bio for this user.*`);
    }

29-35: 🛠️ Refactor suggestion

Validate URLs more robustly and handle errors gracefully.

The regular expression used for URL validation is too permissive and might accept invalid URLs. Additionally, if the URL is invalid or the media cannot be sent, the user won't receive feedback.

Consider using a more precise URL validation method and add error handling:

async (message, match) => {
-  if (!match || !/^https?:\/\/[^\s$.?#].[^\s]*$/.test(match))
+  try {
+    new URL(match);
+  } catch {
     return message.send('*Please provide a valid URL.*');
   }
   const url = extractUrlFromString(match);
-  return await message.client.sendMessage(message.jid, {
+  await message.client.sendMessage(message.jid, {
     video: { url: url },
     caption: '*HERE WE GO*',
   });
+  return;
+} catch (error) {
+  await message.send('*Failed to send video. Please check the URL and try again.*');
+}
 }

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


13-18: 🧹 Nitpick (assertive)

Ensure consistent error messages and consider edge cases.

The command checks for empty input but does not handle inputs without the '|' separator, which is required by the readmore function. Additionally, the error messages use different styles ('*Give me text!*' vs. '*Format: text1|text2*').

Apply this diff to enhance input validation and unify error messages:

async (message, match) => {
-  if (!match) return await message.send('*Give me text!*');
+  if (!match || !match.includes('|'))
+    return await message.send('*Please provide text in the format: text1|text2*');
   const result = readmore(match);
-  if (!result) return await message.send('*Format: text1|text2*');
   return await message.send(result);
 }
📝 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.

  async (message, match) => {
    if (!match || !match.includes('|'))
      return await message.send('*Please provide text in the format: text1|text2*');
    const result = readmore(match);
    return await message.send(result);
  }
sql/notes.js (3)

1-2: 🧹 Nitpick (assertive)

Import Node.js built-in modules using the node: protocol.

According to static analysis hints, using the node: protocol is more explicit and signals that the imported module belongs to Node.js.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


85-87: 🧹 Nitpick (assertive)

Performance optimization: Use early return.

In getNote, the || null is unnecessary since find returns undefined if no match is found.

Simplify the return statement:

export async function getNote(id) {
  const notes = readNotes();
- return notes.find((note) => note.id === id) || null;
+ return notes.find((note) => note.id === id);
}
📝 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.

  const notes = readNotes();
  return notes.find((note) => note.id === id);
}

22-26: 🛠️ Refactor suggestion

Ensure unique and incremental note IDs in concurrent environments.

Using notes.length + 1 for the id may result in duplicate IDs if notes are deleted or in a concurrent environment.

Consider generating unique IDs using a UUID library or tracking the last used ID:

const newNote = {
-  id: notes.length + 1, // Auto-increment id based on the current notes length
+  id: Date.now(), // Use timestamp as a simple unique ID
   title,
   content,
   createdAt: new Date(),
 };

Alternatively, maintain a separate file to track the last used ID.

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

    id: Date.now(), // Use timestamp as a simple unique ID
    title,
    content,
    createdAt: new Date(),
  };
sql/antiword.js (4)

96-99: 🧹 Nitpick (assertive)

Handle undefined return in isAntiWordEnabled.

If jid is not provided, the function currently returns undefined. For consistency, it should return false or throw an error.

Adjust the function to return false when jid is missing:

async function isAntiWordEnabled(jid) {
- if (!jid) return;
+ if (!jid) return false;
  const db = readDB();
  const record = db.find((item) => item.jid === jid);
  return record ? record.status : false;
}
📝 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.

  if (!jid) return false;
  const db = readDB();
  const record = db.find((item) => item.jid === jid);
  return record ? record.status : false;

14-21: 🛠️ Refactor suggestion

Prevent direct mutation of objects within arrays.

Modifying record directly can lead to unintended side effects if other references to record exist.

Create a new object when updating record:

if (!record) {
  record = { jid, status: action, words: [] };
  db.push(record);
} else {
- record.status = action;
+ const updatedRecord = { ...record, status: action };
+ const index = db.findIndex((item) => item.jid === jid);
+ db[index] = updatedRecord;
}
📝 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.

  let record = db.find((item) => item.jid === jid);

  if (!record) {
    record = { jid, status: action, words: [] };
    db.push(record);
  } else {
    const updatedRecord = { ...record, status: action };
    const index = db.findIndex((item) => item.jid === jid);
    db[index] = updatedRecord;
  }

1-2: 🧹 Nitpick (assertive)

Import Node.js built-in modules using the node: protocol.

As indicated by static analysis, updating the import statements enhances clarity.

Apply this diff:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


40-42: 🧹 Nitpick (assertive)

Ensure uniqueness when adding antiwords and handle case sensitivity.

When combining word lists, consider normalizing words to handle case differences and prevent duplicates.

Normalize words before merging:

const normalize = (word) => word.toLowerCase();
const uniqueWords = [
  ...new Set([...record.words.map(normalize), ...words.map(normalize)]),
];
record.words = uniqueWords;

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

bot/schedule.js (2)

32-69: 🧹 Nitpick (assertive)

Refactor duplicated muting and unmuting logic into a single function

The muting and unmuting code blocks are almost identical, leading to code duplication. Refactoring them into a single function improves maintainability and reduces potential errors.

Consider applying the following refactor:

+const handleGroupSetting = async (schedule, isMuting) => {
+  try {
+    const setting = isMuting ? 'announcement' : 'not_announcement';
+    await client.groupSettingUpdate(schedule.groupId, setting);
+    await addOrUpdateSchedule(
+      schedule.groupId,
+      schedule.muteTime,
+      schedule.unmuteTime,
+      !isMuting,
+      schedule.isScheduled
+    );
+    const message = isMuting
+      ? '```Group has been muted, due to AutoMute```'
+      : '```Group is now unmuted, due to AutoUnMute```';
+    await client.sendMessage(schedule.groupId, { text: message });
+  } catch (error) {
+    const action = isMuting ? 'mute' : 'unmute';
+    console.error(`Failed to ${action} group ${schedule.groupId}:`, error);
+  }
+};

 for (const schedule of schedules) {
   if (!schedule.isScheduled) continue;

   if (schedule.muteTime === currentTime && schedule.isMuted) {
-    try {
-      await client.groupSettingUpdate(schedule.groupId, 'announcement');
-      await addOrUpdateSchedule(
-        schedule.groupId,
-        schedule.muteTime,
-        schedule.unmuteTime,
-        false,
-        schedule.isScheduled
-      );
-      await client.sendMessage(schedule.groupId, {
-        text: '```Group has been muted, due to AutoMute```',
-      });
-    } catch (error) {
-      console.error(`Failed to mute group ${schedule.groupId}:`, error);
-    }
+    await handleGroupSetting(schedule, true);
   }

   if (schedule.unmuteTime === currentTime && !schedule.isMuted) {
-    try {
-      await client.groupSettingUpdate(schedule.groupId, 'not_announcement');
-      await addOrUpdateSchedule(
-        schedule.groupId,
-        schedule.muteTime,
-        schedule.unmuteTime,
-        true,
-        schedule.isScheduled
-      );
-      await client.sendMessage(schedule.groupId, {
-        text: '```Group is now unmuted, due to AutoUnMute```',
-      });
-    } catch (error) {
-      console.error(`Failed to unmute group ${schedule.groupId}:`, error);
-    }
+    await handleGroupSetting(schedule, false);
   }
 }

24-74: ⚠️ Potential issue

Prevent overlapping executions by avoiding async functions inside setInterval

Using an asynchronous function inside setInterval can lead to overlapping executions if the asynchronous tasks take longer than the interval duration. This can cause unexpected behavior and resource exhaustion.

Consider refactoring to use setTimeout to schedule the next execution after the asynchronous task completes.

Apply this refactor:

-export const schedules = async (msg) => {
+export const schedules = (msg) => {
   const client = msg.client;
-  setInterval(async () => {
+  const scheduleHandler = async () => {
     try {
       const currentTime = getCurrentTime();
       const schedules = await getAllSchedules();
       
       for (const schedule of schedules) {
         if (!schedule.isScheduled) continue;

         if (schedule.muteTime === currentTime && schedule.isMuted) {
           // Muting logic
           // ...
         }

         if (schedule.unmuteTime === currentTime && !schedule.isMuted) {
           // Unmuting logic
           // ...
         }
       }
     } catch (error) {
       console.error('Error in schedule handler:', error);
     }
+    setTimeout(scheduleHandler, 10000);
   };
+  scheduleHandler();
 }

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

sql/scheduler.js (2)

10-11: 🛠️ Refactor suggestion

Prevent potential race conditions with concurrent file access

Using synchronous file operations without proper concurrency control can lead to race conditions if multiple operations access the schedules.json file simultaneously. This may cause data corruption or loss.

Consider using asynchronous file operations and implementing a locking mechanism to handle concurrent access safely.

Refactor the code as follows:

-const readSchedules = () => JSON.parse(fs.readFileSync(store, 'utf8'));
-const writeSchedules = (schedules) => fs.writeFileSync(store, JSON.stringify(schedules, null, 2));
+const readSchedules = async () => JSON.parse(await fs.promises.readFile(store, 'utf8'));
+const writeSchedules = async (schedules) => await fs.promises.writeFile(store, JSON.stringify(schedules, null, 2));

 export async function addOrUpdateSchedule(
   groupId,
   muteTime,
   unmuteTime,
   isMuted = false,
   isScheduled = false
 ) {
-  const schedules = readSchedules();
+  const schedules = await readSchedules();
   let schedule = schedules.find((schedule) => schedule.groupId === groupId);

   if (schedule) {
     // Update existing schedule
     schedule.muteTime = muteTime;
     schedule.unmuteTime = unmuteTime;
     schedule.isMuted = isMuted;
     schedule.isScheduled = isScheduled;
   } else {
     // Add new schedule
     schedule = { groupId, muteTime, unmuteTime, isMuted, isScheduled };
     schedules.push(schedule);
   }

-  writeSchedules(schedules);
+  await writeSchedules(schedules);
   return schedule;
 }

Note: Implementing proper concurrency handling, like file locking or queuing write operations, is crucial to ensure data integrity.

Also applies to: 29-45


1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

Using the 'node:' protocol when importing Node.js built-in modules clarifies that these modules are core Node.js modules and not third-party packages.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

sql/config.js (6)

28-29: 🛠️ Refactor suggestion

Prevent potential race conditions in config file operations

Concurrent access to the config.json file without proper handling can lead to race conditions and data corruption. This is especially important if multiple parts of the application might read or write to the config simultaneously.

Consider using asynchronous file operations and implementing locking mechanisms to ensure safe concurrent access.

Refactor the file operations:

-const readConfig = () => JSON.parse(fs.readFileSync(store, 'utf8'));
-const writeConfig = (config) => fs.writeFileSync(store, JSON.stringify(config, null, 2));
+const readConfig = async () => {
+  try {
+    const data = await fs.promises.readFile(store, 'utf8');
+    return JSON.parse(data);
+  } catch (error) {
+    // Handle error
+  }
+};
+const writeConfig = async (config) => {
+  await fs.promises.writeFile(store, JSON.stringify(config, null, 2));
+};

 // Update functions to use async/await
 async function updateConfig(field, value) {
-  let config = await ensureConfigExists();
+  const config = await ensureConfigExists();
   // ...
 }

 // Similarly update other functions that read/write config

Note: Ensuring atomic write operations and possibly using a library for managing configuration files can help prevent such issues.

Also applies to: 52-109


28-29: ⚠️ Potential issue

Handle potential JSON parsing errors in readConfig

If config.json becomes corrupted or contains invalid JSON, JSON.parse will throw an error, which can crash the application. It's important to handle this exception gracefully.

Consider updating readConfig to handle parsing errors:

-const readConfig = () => JSON.parse(fs.readFileSync(store, 'utf8'));
+const readConfig = () => {
+  try {
+    return JSON.parse(fs.readFileSync(store, 'utf8'));
+  } catch (error) {
+    console.error('Failed to read or parse config.json:', error);
+    // Optionally reinitialize the config file with default values
+    const defaultConfig = {
+      autoRead: false,
+      autoStatusRead: false,
+      cmdReact: true,
+      cmdRead: false,
+      mode: false,
+      PREFIX: '.',
+      disabledCmds: [],
+      autolikestatus: false,
+      disablegc: false,
+      disabledm: false,
+    };
+    writeConfig(defaultConfig);
+    return defaultConfig;
+  }
+};
📝 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.

const readConfig = () => {
  try {
    return JSON.parse(fs.readFileSync(store, 'utf8'));
  } catch (error) {
    console.error('Failed to read or parse config.json:', error);
    // Optionally reinitialize the config file with default values
    const defaultConfig = {
      autoRead: false,
      autoStatusRead: false,
      cmdReact: true,
      cmdRead: false,
      mode: false,
      PREFIX: '.',
      disabledCmds: [],
      autolikestatus: false,
      disablegc: false,
      disabledm: false,
    };
    writeConfig(defaultConfig);
    return defaultConfig;
  }
};
const writeConfig = (config) => fs.writeFileSync(store, JSON.stringify(config, null, 2));

99-99: 🧹 Nitpick (assertive)

Use 'const' instead of 'let' for config variable

The config variable is not mutated after declaration. Using const is more appropriate here.

Apply this change:

-  let config = await ensureConfigExists();
+  const config = await ensureConfigExists();
📝 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.

  const config = await ensureConfigExists();
🧰 Tools
🪛 Biome (1.9.4)

[error] 99-99: This let declares a variable that is only assigned once.

'config' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


52-52: 🧹 Nitpick (assertive)

Use 'const' instead of 'let' for variables not reassigned

The variable config is declared with let but is not reassigned in the scope. Using const emphasizes that the variable is not intended to be reassigned.

Apply this change:

-  let config = await ensureConfigExists();
+  const config = await ensureConfigExists();
📝 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.

  const config = await ensureConfigExists();
🧰 Tools
🪛 Biome (1.9.4)

[error] 52-52: This let declares a variable that is only assigned once.

'config' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing Node.js built-in modules

Consistently using the 'node:' protocol when importing built-in modules enhances code clarity and prevents confusion with similarly named third-party modules.

Apply this diff:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


85-85: 🧹 Nitpick (assertive)

Use 'const' instead of 'let' for config variable

Since config is not reassigned after its initial assignment, declaring it with const improves code readability and prevents accidental reassignment.

Apply this change:

-  let config = await ensureConfigExists();
+  const config = await ensureConfigExists();
📝 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.

  const config = await ensureConfigExists();
🧰 Tools
🪛 Biome (1.9.4)

[error] 85-85: This let declares a variable that is only assigned once.

'config' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

sql/antilink.js (2)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


93-94: 🧹 Nitpick (assertive)

Simplify null checks using optional chaining

You can simplify the code by utilizing optional chaining to handle undefined properties more elegantly.

Apply this diff to improve the code:

-const groupConfig = (readDB()[jid] || {})[type];
+const groupConfig = readDB()[jid]?.[type];
📝 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.

  const groupConfig = readDB()[jid]?.[type];
  const newCount = (groupConfig?.warningCount || 0) + 1;
🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

sql/greetings.js (1)

1-2: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the import statements:

-import fs from 'fs';
-import path from 'path';
+import fs from 'node:fs';
+import path from 'node:path';
📝 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.

import fs from 'node:fs';
import path from 'node:path';
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

lib/client.js (3)

11-11: 🧹 Nitpick (assertive)

Use 'node:' protocol when importing built-in modules

It's recommended to use the 'node:' protocol when importing Node.js built-in modules for clarity and explicitness.

Apply this diff to update the import statement:

-import { EventEmitter } from 'events';
+import { EventEmitter } from 'node:events';
📝 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.

import { EventEmitter } from 'node:events';
🧰 Tools
🪛 Biome (1.9.4)

[error] 11-11: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


99-105: ⚠️ Potential issue

Wrap variable declaration in switch case with a block

Declaring variables inside a switch case without wrapping them in a block can cause scope leakage, leading to unexpected behavior. To ensure proper scoping, wrap the case in braces.

Apply this diff to fix the scoping issue:

         case 'open':
+          {
             const web = version.join('.');
             await conn.sendMessage(conn.user.id, {
               text: `\`\`\`Bot Connected\n${web}\`\`\``,
             });
             console.log(`Connected`);
+          }
           break;
📝 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.

          {
            const web = version.join('.');
            await conn.sendMessage(conn.user.id, {
              text: `\`\`\`Bot Connected\n${web}\`\`\``,
            });
            console.log(`Connected`);
          }
          break;
      }
🧰 Tools
🪛 Biome (1.9.4)

[error] 99-99: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


58-71: 🧹 Nitpick (assertive)

Avoid reassigning function parameters

Reassigning function parameters can lead to confusion and unexpected bugs. It's better to assign the new value to a local variable.

Apply this diff to avoid reassigning the message parameter:

-patchMessageBeforeSending: (message) => {
+patchMessageBeforeSending: (originalMessage) => {
   const requiresPatch = !!(
-    message.buttonsMessage ||
-    message.templateMessage ||
-    message.listMessage ||
-    message.scheduledCallCreationMessage ||
-    message.callLogMesssage
+    originalMessage.buttonsMessage ||
+    originalMessage.templateMessage ||
+    originalMessage.listMessage ||
+    originalMessage.scheduledCallCreationMessage ||
+    originalMessage.callLogMesssage
   );
   if (requiresPatch) {
-    message = {
+    const patchedMessage = {
       viewOnceMessage: {
         message: {
           messageContextInfo: {
             deviceListMetadataVersion: 2,
             deviceListMetadata: {},
           },
-          ...message,
+          ...originalMessage,
         },
       },
     };
-    return message;
+    return patchedMessage;
   }
-  return message;
+  return originalMessage;
 },
📝 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.

        const patchedMessage = {
          viewOnceMessage: {
            message: {
              messageContextInfo: {
                deviceListMetadataVersion: 2,
                deviceListMetadata: {},
              },
              ...originalMessage,
            },
          },
        };
      }

      return originalMessage;
🧰 Tools
🪛 Biome (1.9.4)

[error] 58-58: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)

plugins/tools.js (6)

41-46: ⚠️ Potential issue

Add error handling for the 'remini' function in 'recolor' command

The recolor command lacks error handling for the remini function call. If an error occurs during the recoloring process, it may result in an unhandled exception.

Apply this diff to handle errors:

async (message) => {
  if (!message.reply_message?.image) return message.send('_Reply An Image_');
  const img = await message.download();
- const recoloredImg = await remini(img, 'recolor');
- await message.send(recoloredImg);
+ try {
+   const recoloredImg = await remini(img, 'recolor');
+   await message.send(recoloredImg);
+ } catch (error) {
+   await message.send('_Failed to recolor the image._');
+ }
}
📝 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.

async (message) => {
    if (!message.reply_message?.image) return message.send('_Reply An Image_');
    const img = await message.download();
    try {
        const recoloredImg = await remini(img, 'recolor');
        await message.send(recoloredImg);
    } catch (error) {
        await message.send('_Failed to recolor the image._');
    }
}

71-84: ⚠️ Potential issue

Add error handling for file operations in 'upload' command

The upload command performs file download and upload without error handling. If either operation fails, it could lead to unhandled exceptions.

Apply this diff to handle errors:

async (message) => {
  if (
    !message.reply_message.image &&
    !message.reply_message.video &&
    !message.reply_message.audio &&
    !message.reply_message.sticker &&
    !message.reply_message.document
  ) {
    return message.send('_Reply A File_');
  }
- const data = await message.download();
- const url = await uploadFile(data);
- await message.send(`*${url}*`);
+ try {
+   const data = await message.download();
+   const url = await uploadFile(data);
+   await message.send(`*${url}*`);
+ } catch (error) {
+   await message.send('_Failed to upload the file._');
+ }
}
📝 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.

  async (message) => {
    if (
      !message.reply_message.image &&
      !message.reply_message.video &&
      !message.reply_message.audio &&
      !message.reply_message.sticker &&
      !message.reply_message.document
    ) {
      return message.send('_Reply A File_');
    }
    try {
      const data = await message.download();
      const url = await uploadFile(data);
      await message.send(`*${url}*`);
    } catch (error) {
      await message.send('_Failed to upload the file._');
    }
  }

56-61: ⚠️ Potential issue

Add error handling for the 'remini' function in 'dehaze' command

Similarly, the dehaze command should handle potential errors from the remini function to prevent unhandled exceptions.

Apply this diff to handle errors:

async (message) => {
  if (!message.reply_message?.image) return message.send('_Reply An Image_');
  const img = await message.download();
- const dehazedImg = await remini(img, 'dehaze');
- await message.send(dehazedImg);
+ try {
+   const dehazedImg = await remini(img, 'dehaze');
+   await message.send(dehazedImg);
+ } catch (error) {
+   await message.send('_Failed to dehaze the image._');
+ }
}
📝 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.

  async (message) => {
    if (!message.reply_message?.image) return message.send('_Reply An Image_');
    const img = await message.download();
    try {
      const dehazedImg = await remini(img, 'dehaze');
      await message.send(dehazedImg);
    } catch (error) {
      await message.send('_Failed to dehaze the image._');
    }
  }

95-102: ⚠️ Potential issue

Add error handling for network operations in 'getsticker' command

The getsticker command does not handle errors from network requests like XSTRO.searchSticker, getBuffer, and createSticker. Unhandled errors may cause the bot to crash or behave unexpectedly.

Apply this diff to handle errors:

async (message, match) => {
  if (!match) return message.send('_Provide A Query_');
+ try {
    const stickers = await XSTRO.searchSticker(match);
    for (const sticker of stickers) {
      const buffer = await getBuffer(sticker);
      const stickerUrl = await createSticker(buffer);
      await message.send(stickerUrl, { type: 'sticker' });
    }
+ } catch (error) {
+   await message.send('_Failed to fetch stickers._');
+ }
}
📝 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.

    if (!match) return message.send('_Provide A Query_');
    try {
      const stickers = await XSTRO.searchSticker(match);
      for (const sticker of stickers) {
        const buffer = await getBuffer(sticker);
        const stickerUrl = await createSticker(buffer);
        await message.send(stickerUrl, { type: 'sticker' });
      }
    } catch (error) {
      await message.send('_Failed to fetch stickers._');
    }
  }

26-31: ⚠️ Potential issue

Add error handling for the 'remini' function in 'enhance' command

Currently, if the remini function fails, the error is not handled, which could lead to unhandled promise rejections and a poor user experience. It's important to catch any errors and inform the user appropriately.

Apply this diff to handle errors:

async (message) => {
  if (!message.reply_message?.image) return message.send('_Reply An Image_');
  const img = await message.download();
- const enhancedImg = await remini(img, 'enhance');
- await message.send(enhancedImg);
+ try {
+   const enhancedImg = await remini(img, 'enhance');
+   await message.send(enhancedImg);
+ } catch (error) {
+   await message.send('_Failed to enhance the image._');
+ }
}
📝 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.

async (message) => {
    if (!message.reply_message?.image) return message.send('_Reply An Image_');
    const img = await message.download();
    try {
        const enhancedImg = await remini(img, 'enhance');
        await message.send(enhancedImg);
    } catch (error) {
        await message.send('_Failed to enhance the image._');
    }
}

179-179: 🧹 Nitpick (assertive)

Use 'const' instead of 'let' for 'repoUrl'

The variable repoUrl is declared with let but is not reassigned after initialization. Using const is preferable for variables that do not change, improving code readability and preventing accidental reassignments.

Apply this diff to fix the issue:

-       let repoUrl = match.endsWith('.git') ? match.replace('.git', '') : match;
+       const repoUrl = match.endsWith('.git') ? match.replace('.git', '') : match;
📝 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.

    const repoUrl = match.endsWith('.git') ? match.replace('.git', '') : match;
🧰 Tools
🪛 Biome (1.9.4)

[error] 179-179: This let declares a variable that is only assigned once.

'repoUrl' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

plugins/add.js (2)

69-71: 🧹 Nitpick (assertive)

Consider simplifying the error message.

The current error message is verbose and could be more concise while maintaining clarity.

-        '```Unable to send an Invite, this is because this person has not saved your contact, please do not misue this command, It Will Of Course Ban Your ACCOUNT!!!\n\nIf you are sure that indeed that this person has saved your number, then please do not use it yet```'
+        '```❌ Invite failed: Contact not saved\n\n⚠️ WARNING: Using this command with unsaved contacts can result in account ban!\n\n📝 Note: Even if you believe the contact is saved, please wait before retrying.```'

14-16: 🧹 Nitpick (assertive)

Consider enhancing the warning message visibility.

The warning about potential account bans is crucial. Consider making it more prominent by:

  1. Using a more attention-grabbing prefix (e.g., "🚨 CRITICAL WARNING")
  2. Adding line breaks for better readability
-    await message.send(
-      `\`\`\`⚠️ Warning: Using this command improperly can lead to your account being banned! Ensure the recipient has saved your contact before proceeding. Misuse of this feature is strictly prohibited by whatsapp\`\`\``
-    );
+    await message.send(
+      `\`\`\`🚨 CRITICAL WARNING 🚨\n\nUsing this command improperly can lead to your account being banned!\n\n- Ensure the recipient has saved your contact\n- Misuse is strictly prohibited by WhatsApp\`\`\``
+    );
📝 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.

    await message.send(
      `\`\`\`🚨 CRITICAL WARNING 🚨\n\nUsing this command improperly can lead to your account being banned!\n\n- Ensure the recipient has saved your contact\n- Misuse is strictly prohibited by WhatsApp\`\`\``
    );
plugins/menu.js (1)

77-79: 🧹 Nitpick (assertive)

Improve variable declarations.

Declare variables separately and use const for variables that aren't reassigned.

-      if (command.pattern) cmd = command.pattern.toString().split(/\W+/)[1];
-      desc = command.desc || false;
+      const cmd = command.pattern ? command.pattern.toString().split(/\W+/)[1] : undefined;
+      const desc = command.desc || false;
📝 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.

      const cmd = command.pattern ? command.pattern.toString().split(/\W+/)[1] : undefined;
      const desc = command.desc || false;
      if (!command.dontAddCommandList && cmd !== undefined) cmdList.push({ cmd, desc });
🧰 Tools
🪛 Biome (1.9.4)

[error] 77-78: Declare variables separately

Unsafe fix: Break out into multiple declarations

(lint/style/useSingleVarDeclarator)


[error] 77-77: This let declares a variable that is only assigned once.

'cmdList' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

plugins/help.js (1)

84-86: ⚠️ Potential issue

Enhance error handling for external API call.

The external API call needs better error handling and timeout management.

-    const res = await getJson(`https://xstrosession.koyeb.app/pair?phone=${id}`);
-    if (!res.code) return message.send('*unable to get a pairing code, try again!*');
-    return await msg.edit(`*${res.code}*`);
+    try {
+      const controller = new AbortController();
+      const timeoutId = setTimeout(() => controller.abort(), 5000);
+      
+      const res = await getJson(
+        `https://xstrosession.koyeb.app/pair?phone=${id}`,
+        { signal: controller.signal }
+      );
+      clearTimeout(timeoutId);
+      
+      if (!res.code) {
+        return message.send('*Unable to get a pairing code. Please try again later.*');
+      }
+      return await msg.edit(`*Your pairing code: ${res.code}*`);
+    } catch (error) {
+      if (error.name === 'AbortError') {
+        return message.send('*Request timed out. Please try again.*');
+      }
+      return message.send('*An error occurred while getting the pairing code.*');
+    }
📝 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.

    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);
      
      const res = await getJson(
        `https://xstrosession.koyeb.app/pair?phone=${id}`,
        { signal: controller.signal }
      );
      clearTimeout(timeoutId);
      
      if (!res.code) {
        return message.send('*Unable to get a pairing code. Please try again later.*');
      }
      return await msg.edit(`*Your pairing code: ${res.code}*`);
    } catch (error) {
      if (error.name === 'AbortError') {
        return message.send('*Request timed out. Please try again.*');
      }
      return message.send('*An error occurred while getting the pairing code.*');
    }
bot/chatbot.js (1)

1-1: 🧹 Nitpick (assertive)

Remove or update the placeholder comment.

The current comment doesn't provide any value. Consider either removing it or replacing it with proper documentation about the chatbot's functionality.

lib/devs.js (1)

2-6: 💡 Codebase verification

🛠️ Refactor suggestion

Move developer phone numbers to the SUDO environment variable

The codebase already supports storing admin phone numbers via the SUDO environment variable. Instead of hardcoding these numbers in lib/devs.js, move them to this environment variable to improve security and maintainability.

  • In lib/devs.js: Replace the hardcoded array with numbers from process.env.SUDO
  • In deployment: Set the SUDO environment variable with comma-separated phone numbers
🔗 Analysis chain

Consider moving sensitive information to environment variables.

While the formatting changes improve readability, storing phone numbers directly in the source code poses a security risk. Consider moving these to environment variables or a secure configuration management system.

Let's check if these numbers are referenced elsewhere in the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for hardcoded phone numbers
rg -l "['\"](2348|2347|9230)" --type js

Length of output: 67


Script:

#!/bin/bash
# Check content of both files
echo "=== lib/devs.js ==="
cat lib/devs.js
echo -e "\n=== sql/sudo.js ==="
cat sql/sudo.js

# Look for potential config files
echo -e "\n=== Config Files ==="
fd -e json -e env -e yaml -e yml -e config

Length of output: 2793


Script:

#!/bin/bash
# Check config files and documentation
echo "=== app.json ==="
cat app.json
echo -e "\n=== render.yaml ==="
cat render.yaml
echo -e "\n=== Documentation ==="
fd README.md

Length of output: 1903

.github/js/test.js (1)

3-5: 🧹 Nitpick (assertive)

Improve test coverage and remove hardcoded values.

Consider the following improvements:

  1. Add more test cases to verify the JSON storage functionality
  2. Remove hardcoded WhatsApp number from comments
  3. Add error handling test cases
.github/workflows/docker-image.yml (1)

16-16: ⚠️ Potential issue

Fix shell command quoting in Docker tag.

The current command is vulnerable to word splitting. Quote the date command substitution.

-        run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)
+        run: docker build . --file Dockerfile --tag "my-image-name:$(date +%s)"
📝 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.

        run: docker build . --file Dockerfile --tag "my-image-name:$(date +%s)"
🧰 Tools
🪛 actionlint (1.7.4)

16-16: shellcheck reported issue in this script: SC2046:warning:1:54: Quote this to prevent word splitting

(shellcheck)

bot/antidelete.js (2)

11-15: 🧹 Nitpick (assertive)

⚠️ Potential issue

Implementation missing for both chat types.

The handlers for both group and personal chats are missing. This could break the anti-delete functionality.

Would you like me to help implement these handlers based on the new JSON storage approach?


5-8: ⚠️ Potential issue

Add error handling for JSON operations.

The function lacks error handling for:

  1. JSON read operations in getAntiDelete()
  2. Protocol message processing
 export async function AntiDelete(msg) {
-  if (!(await getAntiDelete())) return;
+  try {
+    const antiDelete = await getAntiDelete();
+    if (!antiDelete) return;
+  } catch (error) {
+    console.error('Failed to read anti-delete settings:', error);
+    return;
+  }
   if (!msg.message?.protocolMessage) return;
📝 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.

export async function AntiDelete(msg) {
  try {
    const antiDelete = await getAntiDelete();
    if (!antiDelete) return;
  } catch (error) {
    console.error('Failed to read anti-delete settings:', error);
    return;
  }
  if (!msg.message?.protocolMessage) return;

.github/workflows/label.yml (1)

14-16: ⚠️ Potential issue

Update the labeler action version.

The current version of actions/labeler@v4 is outdated. Consider updating to the latest version to ensure compatibility with GitHub Actions runners.

-      - uses: actions/labeler@v4 # Use the labeler action
+      - uses: actions/labeler@v5 # Use the labeler action
📝 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.

      - uses: actions/labeler@v5 # Use the labeler action
        with:
          repo-token: '${{ secrets.GITHUB_TOKEN }}' # Access token for authentication
🧰 Tools
🪛 actionlint (1.7.4)

14-14: the runner of "actions/labeler@v4" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

bot/stickercmd.js (1)

13-19: 🧹 Nitpick (assertive)

Consider optimizing command lookup and adding error handling.

The current implementation has two potential improvements:

  1. Command name extraction could be cached to avoid repeated regex operations
  2. Command execution should include error handling
 for (const command of commands) {
-      const commandName = command.pattern.toString().split(/\W+/)[2];
+      const commandName = command.name || command.pattern.toString().split(/\W+/)[2];
       if (commandName === data.command.cmd) {
+        try {
           await command.function(inst, msg.body);
+        } catch (error) {
+          console.error(`Error executing command ${commandName}:`, error);
+        }
         break;
       }
📝 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.

    for (const command of commands) {
      const commandName = command.name || command.pattern.toString().split(/\W+/)[2];
      if (commandName === data.command.cmd) {
        try {
          await command.function(inst, msg.body);
        } catch (error) {
          console.error(`Error executing command ${commandName}:`, error);
        }
        break;
      }
    }
lib/files.js (1)

8-21: 🧹 Nitpick (assertive)

Enhance error handling and logging for plugin loading.

Consider the following improvements:

  1. Add directory existence check
  2. Provide more detailed error logging
  3. Track successful plugin loads
+  try {
+    await readdir(pluginsDir);
+  } catch (error) {
+    console.error(`Plugin directory not found: ${pluginsDir}`);
+    return;
+  }
+
+  let loadedCount = 0;
   const files = await readdir(pluginsDir, { withFileTypes: true });
   await Promise.all(
     files.map(async (file) => {
       const fullPath = join(pluginsDir, file.name);
       if (extname(file.name) === '.js') {
         try {
           const fileUrl = pathToFileURL(fullPath).href;
           await import(fileUrl);
+          loadedCount++;
+          console.log(`Loaded plugin: ${file.name}`);
         } catch (err) {
-          console.log('ERROR', `${file.name}: ${err.message}`);
+          console.error(`Failed to load plugin ${file.name}:`, err);
         }
       }
     })
   );
-  return console.log('Plugins Synced');
+  return console.log(`Plugins Synced: ${loadedCount} plugins loaded successfully`);
📝 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.

  try {
    await readdir(pluginsDir);
  } catch (error) {
    console.error(`Plugin directory not found: ${pluginsDir}`);
    return;
  }

  let loadedCount = 0;
  const files = await readdir(pluginsDir, { withFileTypes: true });
  await Promise.all(
    files.map(async (file) => {
      const fullPath = join(pluginsDir, file.name);
      if (extname(file.name) === '.js') {
        try {
          const fileUrl = pathToFileURL(fullPath).href;
          await import(fileUrl);
          loadedCount++;
          console.log(`Loaded plugin: ${file.name}`);
        } catch (err) {
          console.error(`Failed to load plugin ${file.name}:`, err);
        }
      }
    })
  );
  return console.log(`Plugins Synced: ${loadedCount} plugins loaded successfully`);
eslint.config.mjs (1)

1-1: 🧹 Nitpick (assertive)

Fix file extension mismatch.

The comment indicates eslint.config.js but the file is named eslint.config.mjs. Update the comment to match the actual filename.

-// eslint.config.js
+// eslint.config.mjs
📝 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.

// eslint.config.mjs
lib/events.js (1)

15-17: 🧹 Nitpick (assertive)

Use const for non-reassigned variables and combine task assignments.

  1. Use const instead of let for tasks as it's never reassigned.
  2. Consider combining the task assignments for better maintainability.
-  let tasks = [];
-  const config = await getConfig();
-  tasks.push(StickerCMD(msg), AntiViewOnce(msg), AntiSpammer(msg), updateGroupMetadata(msg.client));
+  const config = await getConfig();
+  const tasks = [
+    StickerCMD(msg),
+    AntiViewOnce(msg),
+    AntiSpammer(msg),
+    updateGroupMetadata(msg.client),
+  ];
📝 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.

  const config = await getConfig();
  const tasks = [
    StickerCMD(msg),
    AntiViewOnce(msg),
    AntiSpammer(msg),
    updateGroupMetadata(msg.client),
  ];
🧰 Tools
🪛 Biome (1.9.4)

[error] 15-15: This let declares a variable that is only assigned once.

'tasks' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

lib/logger.js (1)

8-19: 🧹 Nitpick (assertive)

Improve error handling and use optional chaining.

  1. Consider logging errors in the catch block instead of silently ignoring them.
  2. Use optional chaining for better readability.
     try {
       const logger = require(lib);
-      if (logger && logger.createLogger) {
+      if (logger?.createLogger) {
         logger.createLogger = () => ({
           info: () => {},
           warn: () => {},
           error: () => {},
           debug: () => {},
         });
       }
-    } catch {}
+    } catch (error) {
+      console.debug(`Logger ${lib} not available:`, error.message);
+    }
📝 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.

    try {
      const logger = require(lib);
      if (logger?.createLogger) {
        logger.createLogger = () => ({
          info: () => {},
          warn: () => {},
          error: () => {},
          debug: () => {},
        });
      }
    } catch (error) {
      console.debug(`Logger ${lib} not available:`, error.message);
    }
  });
🧰 Tools
🪛 Biome (1.9.4)

[error] 10-10: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

plugins/files.js (1)

15-20: ⚠️ Potential issue

Critical: Add security measures for file access.

The current implementation has several security vulnerabilities:

  1. Path traversal: Users can access files outside the intended directory.
  2. No file size limits: Large files could cause memory issues.
  3. No file type restrictions: Sensitive files could be exposed.
     const fileName = match?.trim();
     if (!fileName) return message.send('_Please specify the file name. Example: file `config.js`_');
+    // Prevent path traversal
+    if (fileName.includes('..') || !fileName.match(/^[\w.-]+$/)) {
+      return message.send('_Invalid file name. Only alphanumeric characters, dots, and hyphens are allowed._');
+    }
+    // Restrict to specific directory
+    const allowedDir = path.join(process.cwd(), 'public');
     const filePath = path.resolve(process.cwd(), fileName);
+    if (!filePath.startsWith(allowedDir)) {
+      return message.send('_Access denied: File must be in the public directory._');
+    }
     if (!fs.existsSync(filePath)) {
       return message.send(`_The file "${fileName}" does not exist._`);
     }
+    // Add file size check
+    const stats = fs.statSync(filePath);
+    if (stats.size > 1024 * 1024) { // 1MB limit
+      return message.send('_File too large. Maximum size is 1MB._');
+    }

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

bot/antiviewonce.js (2)

14-15: 🧹 Nitpick (assertive)

Consider optimizing message cloning.

Using JSON.parse(JSON.stringify()) for deep cloning can be inefficient for large message objects. Consider using a more efficient cloning method like structuredClone() for better performance.

-  const modifiedMessage = JSON.parse(JSON.stringify(msg.message));
+  const modifiedMessage = structuredClone(msg.message);
📝 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.

  const modifiedMessage = structuredClone(msg.message);
  const messageType = Object.keys(modifiedMessage)[0];

18-18: 🧹 Nitpick (assertive)

Optimize property deletion for better performance.

The delete operator can impact performance. Consider setting the property to undefined instead.

-    delete modifiedMessage[messageType].viewOnce;
+    modifiedMessage[messageType].viewOnce = undefined;
📝 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.

    modifiedMessage[messageType].viewOnce = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 18-18: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

bot/autokick.js (1)

13-27: ⚠️ Potential issue

Address potential memory leaks and performance issues.

Several concerns need attention:

  1. The setInterval is never cleared, potentially causing memory leaks
  2. Frequent group metadata fetches every 10 seconds could impact performance
  3. The monitoredGroups Set grows indefinitely

Consider implementing:

  1. Cleanup mechanism for intervals
  2. Caching for group metadata
  3. Mechanism to remove inactive groups

Here's a suggested implementation:

+ const intervals = new Map();
+ 
  export async function AutoKick(msg) {
    const groupId = msg.from;
  
-   if (!isJidGroup(groupId) || monitoredGroups.has(groupId)) return;
+   if (!isJidGroup(groupId) || intervals.has(groupId)) return;
  
-   monitoredGroups.add(groupId);
-   setInterval(async () => {
+   const interval = setInterval(async () => {
      const groupMeta = await msg.client.groupMetadata(groupId);
+     if (!groupMeta) {
+       clearInterval(interval);
+       intervals.delete(groupId);
+       return;
+     }
      // ... rest of the code
    }, 10000);
+   intervals.set(groupId, interval);
  }

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

bot/antiword.js (2)

7-7: 🧹 Nitpick (assertive)

Optimize permission checks.

Multiple async calls in the permission check could be combined for better performance.

-  if (msg.sender === msg.user || (await isSudo(msg.sender)) || msg.isAdmin) return;
+  const [isUserSudo] = await Promise.all([isSudo(msg.sender)]);
+  if (msg.sender === msg.user || isUserSudo || msg.isAdmin) return;

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


12-14: 🧹 Nitpick (assertive)

Optimize word matching performance.

The current implementation checks each word individually, which could be inefficient for large lists. Consider using a RegExp for better performance.

-    const un_allowed_words = badwords.words;
-    if (un_allowed_words.some((word) => msg.body.toLowerCase().includes(word.toLowerCase()))) {
+    const pattern = new RegExp(badwords.words.join('|'), 'i');
+    if (pattern.test(msg.body)) {
📝 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.

    const pattern = new RegExp(badwords.words.join('|'), 'i');
    if (pattern.test(msg.body)) {
      if (!msg.isBotAdmin) return;
lib/session.js (2)

14-18: 🧹 Nitpick (assertive)

Consider using async file operations

Synchronous file operations can block the event loop. Consider using async versions for better performance.

-  mkdirSync('session', { recursive: true });
-  writeFileSync(join('session', 'creds.json'), JSON.stringify(data.creds, null, 2));
+  await mkdir('session', { recursive: true });
+  await writeFile(join('session', 'creds.json'), JSON.stringify(data.creds, null, 2));

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


14-18: ⚠️ Potential issue

Add error handling for file operations

The file operations (mkdirSync, writeFileSync) lack try-catch blocks. Failed writes could crash the application.

Add error handling:

-  mkdirSync('session', { recursive: true });
-  writeFileSync(join('session', 'creds.json'), JSON.stringify(data.creds, null, 2));
-  for (const [filename, syncKeyData] of Object.entries(data.syncKeys)) {
-    writeFileSync(join('session', filename), JSON.stringify(syncKeyData, null, 2));
-  }
+  try {
+    mkdirSync('session', { recursive: true });
+    writeFileSync(join('session', 'creds.json'), JSON.stringify(data.creds, null, 2));
+    for (const [filename, syncKeyData] of Object.entries(data.syncKeys)) {
+      writeFileSync(join('session', filename), JSON.stringify(syncKeyData, null, 2));
+    }
+  } catch (error) {
+    console.error('Failed to write session files:', error);
+    throw error;
+  }
📝 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.

  try {
    mkdirSync('session', { recursive: true });
    writeFileSync(join('session', 'creds.json'), JSON.stringify(data.creds, null, 2));
    for (const [filename, syncKeyData] of Object.entries(data.syncKeys)) {
      writeFileSync(join('session', filename), JSON.stringify(syncKeyData, null, 2));
    }
  } catch (error) {
    console.error('Failed to write session files:', error);
    throw error;
  }
.github/workflows/node.js.yml (2)

31-43: 🛠️ Refactor suggestion

Improve script execution security

The script execution lacks proper sandboxing and runs with full permissions.

Consider:

  1. Running in a container with limited permissions
  2. Adding timeout handling for the background process
  3. Implementing proper error handling for the kill command

27-29: ⚠️ Potential issue

Add checksum verification for downloaded script

Directly executing a downloaded script without verification is a security risk. Consider adding SHA256 checksum verification.

  - name: Download panel.js
    run: |
      curl -L -o panel.js https://raw.githubusercontent.com/AstroX11/Xstro/master/.github/js/panel.js
+     echo "expected-sha256-hash panel.js" | sha256sum --check
      cat panel.js

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

plugins/ads.js (2)

37-37: 🧹 Nitpick (assertive)

Use template literal for string concatenation

Replace string concatenation with template literal for better readability.

- return await message.send('```Shared to ' + groupIds.length + ' Groups.```');
+ return await message.send(`\`\`\`Shared to ${groupIds.length} Groups.\`\`\``);
🧰 Tools
🪛 Biome (1.9.4)

[error] 37-37: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


29-35: 🛠️ Refactor suggestion

Add rate limiting and batch processing

Current implementation might trigger spam detection or hit API limits. Consider implementing rate limiting and batch processing.

+ const BATCH_SIZE = 10;
+ const MAX_GROUPS_PER_HOUR = 50;
+ let processedCount = 0;

  for (const groupId of groupIds) {
+   if (processedCount >= MAX_GROUPS_PER_HOUR) {
+     await delay(3600000); // Wait 1 hour
+     processedCount = 0;
+   }
+   if (processedCount % BATCH_SIZE === 0) {
+     await delay(5000); // Longer delay between batches
+   }
    await delay(1500);
    await message.send(broadcastMessage, {
      jid: groupId,
      contextInfo: messageOptions,
    });
+   processedCount++;
  }
📝 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.

    const BATCH_SIZE = 10;
    const MAX_GROUPS_PER_HOUR = 50;
    let processedCount = 0;

    for (const groupId of groupIds) {
      if (processedCount >= MAX_GROUPS_PER_HOUR) {
        await delay(3600000); // Wait 1 hour
        processedCount = 0;
      }
      if (processedCount % BATCH_SIZE === 0) {
        await delay(5000); // Longer delay between batches
      }
      await delay(1500);
      await message.send(broadcastMessage, {
        jid: groupId,
        contextInfo: messageOptions,
      });
      processedCount++;
    }
plugins/vars.js (1)

15-16: ⚠️ Potential issue

Add input validation for system variables

Current implementation lacks input validation, potentially allowing injection of malicious values.

  const [key, value] = input.map((item) => item.trim());
+ if (!/^[a-zA-Z0-9_]+$/.test(key)) {
+   return message.send('Invalid key format. Use only alphanumeric characters and underscore.');
+ }
+ if (key.toLowerCase().includes('password') || key.toLowerCase().includes('token')) {
+   return message.send('Cannot set sensitive variables through this command.');
+ }
  await manageVar({ command: 'set', key, value });

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

plugins/structure.js (2)

6-30: 🛠️ Refactor suggestion

Consider async implementation for large directories

Synchronous file operations can block the event loop when processing large directories.

Consider implementing an async version of the function:

async function getDirectoryStructureAsync(dir, prefix = '', isLast = true) {
  const files = await fs.promises.readdir(dir);
  let structure = '';

  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    const isLastItem = i === files.length - 1;
    const filePath = path.join(dir, file);
    const stats = await fs.promises.stat(filePath);
    // ... rest of the logic ...
  }
  return structure;
}

15-22: 🧹 Nitpick (assertive)

Move exclusion list to configuration

Hard-coded exclusion list makes it difficult to maintain and update.

+ const DEFAULT_EXCLUSIONS = [
+   'node_modules',
+   '.git',
+   '.env',
+   '.npm',
+   'session'
+ ];

  if (
-   file === 'node_modules' ||
-   file.startsWith('.git') ||
-   file === '.env' ||
-   file === '.npm' ||
-   file === 'session'
+   DEFAULT_EXCLUSIONS.some(excluded => 
+     excluded === file || (excluded.endsWith('*') && file.startsWith(excluded.slice(0, -1)))
+   )
  )
📝 Committable suggestion

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

    const DEFAULT_EXCLUSIONS = [
      'node_modules',
      '.git',
      '.env',
      '.npm',
      'session'
    ];

    if (
      DEFAULT_EXCLUSIONS.some(excluded => 
        excluded === file || (excluded.endsWith('*') && file.startsWith(excluded.slice(0, -1)))
      )
    )
      return;
app.json (2)

14-17: 🧹 Nitpick (assertive)

Consider enhancing SESSION_ID security guidance.

Add a comment in the description explaining the secure way to generate and handle the session ID to prevent unauthorized access.

     "SESSION_ID": {
-      "description": "Session ID to Run Bot",
+      "description": "Session ID to Run Bot. Generate this securely and never share it.",
       "required": true
     },
📝 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.

    "SESSION_ID": {
      "description": "Session ID to Run Bot. Generate this securely and never share it.",
      "required": true
    },

18-22: 🧹 Nitpick (assertive)

Add validation pattern for SUDO phone numbers.

Consider adding a pattern field to validate phone number format.

     "SUDO": {
       "description": "Phone Number for Admin Users",
+      "pattern": "^[0-9]{10,15}$",
       "value": "",
       "required": false
     },
📝 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.

    "SUDO": {
      "description": "Phone Number for Admin Users",
      "pattern": "^[0-9]{10,15}$",
      "value": "",
      "required": false
    },
plugins/ban.js (1)

44-46: 🧹 Nitpick (assertive)

Use template literal for better readability.

Replace string concatenation with template literal as suggested by static analysis.

-      '*_Banned Users:_*\n' + bannedUsers.map((jid, index) => `${index + 1}. @${jid}`).join('\n'),
+      `*_Banned Users:_*\n${bannedUsers.map((jid, index) => `${index + 1}. @${jid}`).join('\n')}`,
📝 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.

    return message.send(
      `*_Banned Users:_*\n${bannedUsers.map((jid, index) => `${index + 1}. @${jid}`).join('\n')}`,
      { mentions }
🧰 Tools
🪛 Biome (1.9.4)

[error] 45-45: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

plugins/sudo.js (2)

42-43: 🛠️ Refactor suggestion

Improve error handling for getSudo response.

The string comparison for empty sudo list is fragile. Consider using a more robust check.

-    if (sudoList === '_No Sudo Numbers_') return message.send('*_No Sudo Users_*');
+    if (!sudoList || !sudoList.trim() || sudoList === '_No Sudo Numbers_') return message.send('*_No Sudo Users_*');
📝 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.

    if (!sudoList || !sudoList.trim() || sudoList === '_No Sudo Numbers_') return message.send('*_No Sudo Users_*');
    const sudoNumbers = sudoList.split('\n').map((number) => number.split('@')[0]);

44-48: 🧹 Nitpick (assertive)

Use template literals and simplify the code.

Improve readability and reduce complexity.

-    const formattedSudoList =
-      '*_Sudo Users_*\n\n' +
-      sudoNumbers.map((number, index) => `${index + 1}. @${number}`).join('\n');
-    const mentions = sudoNumbers.map((number) => `${number}@s.whatsapp.net`);
-    return message.send(formattedSudoList, { mentions: mentions });
+    const mentions = sudoNumbers.map(number => `${number}@s.whatsapp.net`);
+    return message.send(
+      `*_Sudo Users_*\n\n${sudoNumbers.map((number, index) => `${index + 1}. @${number}`).join('\n')}`,
+      { mentions }
+    );
📝 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.

    const mentions = sudoNumbers.map(number => `${number}@s.whatsapp.net`);
    return message.send(
      `*_Sudo Users_*\n\n${sudoNumbers.map((number, index) => `${index + 1}. @${number}`).join('\n')}`,
      { mentions }
    );
🧰 Tools
🪛 Biome (1.9.4)

[error] 45-46: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

plugins/call.js (2)

14-15: ⚠️ Potential issue

Avoid parameter reassignment and add error handling.

The parameter reassignment and lack of validation could lead to runtime errors.

-    match = match.split(';');
-    console.log(timeToTimestamp(match[1]));
+    const [title, time] = match.split(';');
+    if (!title || !time) {
+      return message.send(`_Invalid format. Use: ${prefix}call <title>;<time>_`);
+    }
+    const timestamp = timeToTimestamp(time);

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 14-14: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)


39-52: 🛠️ Refactor suggestion

Improve time parsing robustness and timezone handling.

The current implementation has several potential issues:

  1. No timezone consideration
  2. Primitive parseInt usage
  3. Limited error handling
 function timeToTimestamp(timeStr) {
-  const match = timeStr.match(/^(\d{1,2}):(\d{2})(am|pm)$/i);
+  const match = timeStr.trim().match(/^(\d{1,2}):(\d{2})\s*(am|pm)$/i);
   if (!match) throw new Error("Invalid time format. Use 'hh:mmam' or 'hh:mmpm'.");

-  let [_, hours, minutes, period] = match;
-  hours = parseInt(hours, 10);
-  minutes = parseInt(minutes, 10);
+  const [_, hoursStr, minutesStr, period] = match;
+  const hours = Number.parseInt(hoursStr, 10);
+  const minutes = Number.parseInt(minutesStr, 10);
+
+  if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) {
+    throw new Error('Invalid hours or minutes.');
+  }

   if (period.toLowerCase() === 'pm' && hours !== 12) {
     hours += 12;
   } else if (period.toLowerCase() === 'am' && hours === 12) {
     hours = 0;
   }
   const now = new Date();
   now.setHours(hours, minutes, 0, 0);
+  if (now < Date.now()) {
+    now.setDate(now.getDate() + 1); // Schedule for next day if time has passed
+  }
   return now.getTime();
 }
📝 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.

  const match = timeStr.trim().match(/^(\d{1,2}):(\d{2})\s*(am|pm)$/i);
  if (!match) throw new Error("Invalid time format. Use 'hh:mmam' or 'hh:mmpm'.");

  const [_, hoursStr, minutesStr, period] = match;
  const hours = Number.parseInt(hoursStr, 10);
  const minutes = Number.parseInt(minutesStr, 10);

  if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) {
    throw new Error('Invalid hours or minutes.');
  }

  if (period.toLowerCase() === 'pm' && hours !== 12) {
    hours += 12;
  } else if (period.toLowerCase() === 'am' && hours === 12) {
    hours = 0;
  }
  const now = new Date();
  now.setHours(hours, minutes, 0, 0);
  if (now < Date.now()) {
    now.setDate(now.getDate() + 1); // Schedule for next day if time has passed
  }
  return now.getTime();
🧰 Tools
🪛 Biome (1.9.4)

[error] 43-43: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 44-44: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

plugins/antiviewonce.js (2)

45-46: ⚠️ Potential issue

Fix inconsistent success message.

The success message doesn't reflect the actual command state.

     await setViewOnce(cmd === 'on');
-    return await message.send(`_AntiViewOnce turned On_`);
+    return await message.send(`_AntiViewOnce turned ${cmd.toUpperCase()}_`);
📝 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.

    await setViewOnce(cmd === 'on');
    return await message.send(`_AntiViewOnce turned ${cmd.toUpperCase()}_`);

17-23: 🧹 Nitpick (assertive)

Use template literals for help message.

Improve readability and maintainability of the help message.

-      return await message.send(
-        `\`\`\`Anti ViewOnce Settings\n\n` +
-          `${message.prefix}antivv on - Enable\n` +
-          `${message.prefix}antivv off - Disable\n` +
-          `${message.prefix}antivv set _[gc/dm/all]_ - Set chat type\n` +
-          `${message.prefix}antivv get - Check status\`\`\``
-      );
+      return await message.send(
+        `\`\`\`Anti ViewOnce Settings\n\n\
+${message.prefix}antivv on - Enable\n\
+${message.prefix}antivv off - Disable\n\
+${message.prefix}antivv set _[gc/dm/all]_ - Set chat type\n\
+${message.prefix}antivv get - Check status\`\`\``
+      );
📝 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.

      return await message.send(
        `\`\`\`Anti ViewOnce Settings\n\n\
${message.prefix}antivv on - Enable\n\
${message.prefix}antivv off - Disable\n\
${message.prefix}antivv set _[gc/dm/all]_ - Set chat type\n\
${message.prefix}antivv get - Check status\`\`\``
      );
🧰 Tools
🪛 Biome (1.9.4)

[error] 18-22: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

.github/workflows/stale.yml (1)

15-15: 🛠️ Refactor suggestion

Update actions/stale action to the latest version.

The current version of the stale action may be outdated. Consider updating to the latest version to ensure compatibility with GitHub Actions runners.

-      - uses: actions/stale@v5
+      - uses: actions/stale@v8
📝 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.

      - uses: actions/stale@v8
🧰 Tools
🪛 actionlint (1.7.4)

15-15: the runner of "actions/stale@v5" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

SECURITY.md (1)

9-9: ⚠️ Potential issue

Update version information in security policy.

The version information in the security policy (1.2.2) is outdated compared to package.json (1.2.3).

-| Latest (Main)  | ✔ 1.2.2  |
+| Latest (Main)  | ✔ 1.2.3  |
📝 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.

| Latest (Main)  | ✔ 1.2.3  |
package.json (1)

42-45: ⚠️ Potential issue

Fix invalid package versions in devDependencies.

Several package versions specified don't exist:

-    "eslint": "^9.18.0",
-    "eslint-config-prettier": "^10.0.1",
-    "eslint-plugin-prettier": "^5.2.2",
-    "prettier": "^3.4.2"
+    "eslint": "^8.56.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-prettier": "^5.1.3",
+    "prettier": "^3.1.1"
📝 Committable suggestion

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

    "eslint": "^8.56.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.3",
    "prettier": "^3.1.1"
index.js (3)

48-48: 🛠️ Refactor suggestion

Add error handling for directory creation.

The mkdir operation could fail due to permissions or other I/O issues. Consider adding proper error handling:

-    await mkdir('store', { recursive: true });
+    try {
+      await mkdir('store', { recursive: true });
+    } catch (error) {
+      console.error('Failed to create store directory:', error);
+      process.exit(1);
+    }
📝 Committable suggestion

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

    try {
      await mkdir('store', { recursive: true });
    } catch (error) {
      console.error('Failed to create store directory:', error);
      process.exit(1);
    }

6-6: 🧹 Nitpick (assertive)

Use the node: protocol for Node.js built-in modules.

For better clarity and to explicitly indicate this is a Node.js built-in module:

-import { mkdir } from 'fs/promises';
+import { mkdir } from 'node:fs/promises';
📝 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.

import { mkdir } from 'node:fs/promises';
🧰 Tools
🪛 Biome (1.9.4)

[error] 6-6: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


46-57: 🧹 Nitpick (assertive)

Consider potential race conditions in worker processes.

Multiple worker processes might attempt to create the 'store' directory simultaneously. While mkdir with recursive: true is idempotent, consider moving the directory creation to the master process.

// In the master process section
if (cluster.isMaster) {
+  try {
+    await mkdir('store', { recursive: true });
+  } catch (error) {
+    console.error('Failed to create store directory:', error);
+    process.exit(1);
+  }
   let isRestarting = false;
   // ... rest of the code

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

bot/antispam.js (2)

18-19: 🧹 Nitpick (assertive)

Use atomic operations for Map updates.

The current implementation could lead to race conditions if multiple messages are processed simultaneously:

-  const recentMessages = userMessages.filter((msgInfo) => now - msgInfo.timestamp <= 10000);
-  messageStore.set(senderKey, recentMessages);
+  const recentMessages = userMessages.filter((msgInfo) => now - msgInfo.timestamp <= 10000);
+  if (recentMessages.length > 0) {
+    messageStore.set(senderKey, recentMessages);
+  } else {
+    messageStore.delete(senderKey);
+  }
📝 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.

  const recentMessages = userMessages.filter((msgInfo) => now - msgInfo.timestamp <= 10000);
  if (recentMessages.length > 0) {
    messageStore.set(senderKey, recentMessages);
  } else {
    messageStore.delete(senderKey);
  }

15-16: 🛠️ Refactor suggestion

Implement message store cleanup to prevent memory leaks.

The messageStore Map could grow indefinitely as new messages are added. Consider implementing a cleanup mechanism:

+  // Cleanup old messages (older than 1 hour)
+  const cleanupTime = now - 3600000;
+  for (const [key, messages] of messageStore.entries()) {
+    const validMessages = messages.filter(msg => msg.timestamp > cleanupTime);
+    if (validMessages.length === 0) {
+      messageStore.delete(key);
+    } else {
+      messageStore.set(key, validMessages);
+    }
+  }
   userMessages.push({ timestamp: now, key: msg.key });

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

plugins/stickercmd.js (1)

28-31: 🛠️ Refactor suggestion

Add error handling for Buffer operations.

The Buffer creation from fileSha256 could fail. Add proper error handling:

-    const success = await setcmd(
-      match,
-      Buffer.from(message.data.quoted.message.stickerMessage.fileSha256).toString('hex')
-    );
+    try {
+      const fileSha256 = message.data.quoted.message.stickerMessage.fileSha256;
+      if (!fileSha256) {
+        return await message.send('_Invalid sticker format_');
+      }
+      const success = await setcmd(
+        match,
+        Buffer.from(fileSha256).toString('hex')
+      );
+      if (success) {
+        return await message.send(`_Command "${match}" successfully set to the sticker._`);
+      }
+      await message.send('_Failed to set the command._');
+    } catch (error) {
+      console.error('Failed to process sticker command:', error);
+      await message.send('_Failed to process sticker command_');
+    }
📝 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.

    try {
      const fileSha256 = message.data.quoted.message.stickerMessage.fileSha256;
      if (!fileSha256) {
        return await message.send('_Invalid sticker format_');
      }
      const success = await setcmd(
        match,
        Buffer.from(fileSha256).toString('hex')
      );
      if (success) {
        return await message.send(`_Command "${match}" successfully set to the sticker._`);
      }
      await message.send('_Failed to set the command._');
    } catch (error) {
      console.error('Failed to process sticker command:', error);
      await message.send('_Failed to process sticker command_');
    }
plugins/mention.js (2)

70-70: 🧹 Nitpick (assertive)

Use const instead of let for variables that aren't reassigned.

The reply variable is never reassigned, so it should use const:

-      let reply = await getMention(message.jid);
+      const reply = await getMention(message.jid);
📝 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.

      const reply = await getMention(message.jid);
🧰 Tools
🪛 Biome (1.9.4)

[error] 70-70: This let declares a variable that is only assigned once.

'reply' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


73-75: 🛠️ Refactor suggestion

Improve error handling in try-catch block.

The current implementation silently ignores errors. Consider logging them or handling them appropriately:

       try {
         if (!JSON.parse(reply)) return message.send(reply);
-      } catch {}
+      } catch (error) {
+        console.error('Failed to parse mention reply:', error);
+        return message.send('_Invalid mention reply format_');
+      }
📝 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.

      try {
        if (!JSON.parse(reply)) return message.send(reply);
      } catch (error) {
        console.error('Failed to parse mention reply:', error);
        return message.send('_Invalid mention reply format_');
      }
plugins/updater.js (3)

46-51: ⚠️ Potential issue

Critical: Add proper cleanup before process exit

The process is terminated without proper cleanup of resources or graceful shutdown of connections.

Add cleanup logic before process exit:

+            // Cleanup resources before exit
+            await message.client.end();
+            // Allow time for connections to close
+            setTimeout(() => {
               process.exit(0);
+            }, 1000);
-            process.exit(0);
📝 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.

          exec(`npm install`, async (err, stdout, stderr) => {
            if (err) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 48-48: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


61-67: 🧹 Nitpick (assertive)

Add retry mechanism for git operations

The git diff operation could fail due to temporary issues. Consider adding a retry mechanism.

   try {
-    const diff = await git.diff([`master..origin/master`]);
+    const maxRetries = 3;
+    let retries = 0;
+    while (retries < maxRetries) {
+      try {
+        const diff = await git.diff([`master..origin/master`]);
+        return diff.includes('"dependencies":');
+      } catch (error) {
+        retries++;
+        if (retries === maxRetries) throw error;
+        await new Promise(resolve => setTimeout(resolve, 1000 * retries));
+      }
+    }
-    return diff.includes('"dependencies":');
   } catch (error) {
     console.error('Error occurred while checking package.json:', error);
     return false;
   }
📝 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.

  try {
    const maxRetries = 3;
    let retries = 0;
    while (retries < maxRetries) {
      try {
        const diff = await git.diff([`master..origin/master`]);
        return diff.includes('"dependencies":');
      } catch (error) {
        retries++;
        if (retries === maxRetries) throw error;
        await new Promise(resolve => setTimeout(resolve, 1000 * retries));
      }
    }
  } catch (error) {
    console.error('Error occurred while checking package.json:', error);
    return false;
  }

38-41: ⚠️ Potential issue

Critical: Sanitize user input before executing shell commands

The direct execution of shell commands with user-provided input poses a significant security risk. The stderr is properly handled, but the command itself needs sanitization.

Consider using the following safer approach:

-      exec(`git stash && git pull origin master`, async (err, stdout, stderr) => {
+      const gitCommands = ['git stash', 'git pull origin master'];
+      for (const cmd of gitCommands) {
+        try {
+          await new Promise((resolve, reject) => {
+            exec(cmd, (err, stdout, stderr) => {
+              if (err) reject(new Error(stderr));
+              resolve(stdout);
+            });
+          });
+        } catch (error) {
+          return await message.send('```' + error.message + '```');
+        }
+      }
📝 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.

      const gitCommands = ['git stash', 'git pull origin master'];
      for (const cmd of gitCommands) {
        try {
          await new Promise((resolve, reject) => {
            exec(cmd, (err, stdout, stderr) => {
              if (err) reject(new Error(stderr));
              resolve(stdout);
            });
          });
        } catch (error) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 40-40: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

plugins/antispam.js (2)

34-35: ⚠️ Potential issue

Add error handling for storage operations

The calls to setAntiSpam and getAntiSpamMode need proper error handling as they now interact with the file system.

-      const currentMode = await getAntiSpamMode(jid);
+      try {
+        const currentMode = await getAntiSpamMode(jid);
+      } catch (error) {
+        console.error('Failed to get antispam mode:', error);
+        return message.send('```Failed to get antispam configuration```');
+      }

Also applies to: 26-27


40-47: 🧹 Nitpick (assertive)

Implement atomic operations for file updates

The setAntiSpam operation could lead to race conditions when multiple users modify settings simultaneously.

Consider implementing a file locking mechanism or using atomic operations for the JSON file updates. Would you like me to provide an implementation example?

plugins/warn.js (2)

15-17: ⚠️ Potential issue

Add validation for warning operations

The warning operations need proper validation and error handling for the JSON storage system.

-    const { success, warnings } = await addWarn(jid);
+    try {
+      const { success, warnings } = await addWarn(jid);
+      if (typeof warnings !== 'number' || warnings < 0) {
+        throw new Error('Invalid warning count received');
+      }
+    } catch (error) {
+      console.error('Failed to add warning:', error);
+      return await message.send('```Failed to add warning: Invalid data```');
+    }

19-19: 🧹 Nitpick (assertive)

Use Number.parseInt with radix parameter

The parseInt function should include a radix parameter and use the Number namespace.

-    const warningCount = parseInt(warnings);
+    const warningCount = Number.parseInt(warnings, 10);
📝 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.

    const warningCount = Number.parseInt(warnings, 10);
🧰 Tools
🪛 Biome (1.9.4)

[error] 19-19: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

plugins/autokick.js (2)

19-25: ⚠️ Potential issue

Add comprehensive error handling for storage operations

The auto-kick list modifications need proper error handling for file operations.

-    const added = await addAKick(groupId, jid);
+    try {
+      const added = await addAKick(groupId, jid);
+      if (typeof added !== 'boolean') {
+        throw new Error('Invalid response from storage operation');
+      }
+    } catch (error) {
+      console.error('Failed to modify auto-kick list:', error);
+      return message.send('```Failed to update auto-kick list```');
+    }

69-74: 🛠️ Refactor suggestion

Validate data integrity before processing

The kicks array needs validation before processing to ensure data integrity.

     if (kicks.length > 0) {
+      // Validate kick entries
+      const validKicks = kicks.filter(k => k && k.userJid && typeof k.userJid === 'string');
+      if (validKicks.length !== kicks.length) {
+        console.warn('Some kick entries were invalid and filtered out');
+      }
       return message.send(
-        `_Users in auto-kick list:_\n${kicks.map((k) => `• @${k.userJid.split('@')[0]}`).join('\n')}`,
+        `_Users in auto-kick list:_\n${validKicks.map((k) => `• @${k.userJid.split('@')[0]}`).join('\n')}`,
-        { mentions: [kicks] }
+        { mentions: validKicks.map(k => k.userJid) }
       );
     }
📝 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.

    if (kicks.length > 0) {
      // Validate kick entries
      const validKicks = kicks.filter(k => k && k.userJid && typeof k.userJid === 'string');
      if (validKicks.length !== kicks.length) {
        console.warn('Some kick entries were invalid and filtered out');
      }
      return message.send(
        `_Users in auto-kick list:_\n${validKicks.map((k) => `• @${k.userJid.split('@')[0]}`).join('\n')}`,
        { mentions: validKicks.map(k => k.userJid) }
      );
    }
plugins/tag.js (2)

47-61: ⚠️ Potential issue

Add validation for message content and type

The message handling logic needs proper validation to prevent potential security issues.

       if (objectAction) {
+        // Validate message type
+        const allowedTypes = ['conversation', 'extendedText', 'image', 'video'];
+        if (!allowedTypes.includes(typeOfMessage)) {
+          return message.send('```Unsupported message type```');
+        }
+        
         let taggedMessage = {
           [typeOfMessage]: {
-            ...objectAction,
+            // Only spread known safe properties
+            ...(typeof objectAction === 'object' ? {
+              caption: objectAction.caption,
+              mimetype: objectAction.mimetype,
+              url: objectAction.url
+            } : {}),
             contextInfo: {
               ...objectAction.contextInfo,
               mentionedJid: objectAction.contextInfo?.mentionedJid || participantJids,
             },
           },
         };
🧰 Tools
🪛 Biome (1.9.4)

[error] 48-48: This let declares a variable that is only assigned once.

'taggedMessage' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


12-13: ⚠️ Potential issue

Sanitize user input before processing

The message content needs to be sanitized to prevent potential XSS attacks.

-    const msg = match || message.reply_message?.text;
+    const sanitizeMessage = (text) => {
+      if (typeof text !== 'string') return '';
+      return text.replace(/[<>]/g, ''); // Basic XSS prevention
+    };
+    const msg = sanitizeMessage(match || message.reply_message?.text);
     if (!msg) return message.send('_You must provide a reason for tagging everyone._');
📝 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.

    const sanitizeMessage = (text) => {
      if (typeof text !== 'string') return '';
      return text.replace(/[<>]/g, ''); // Basic XSS prevention
    };
    const msg = sanitizeMessage(match || message.reply_message?.text);
    if (!msg) return message.send('_You must provide a reason for tagging everyone._');
lib/plugins.js (2)

18-18: ⚠️ Potential issue

Add error handling for getConfig call.

The database call could fail during the migration to JSON storage. Consider adding try-catch block to handle potential errors gracefully.

-  const db = await getConfig();
+  let db;
+  try {
+    db = await getConfig();
+  } catch (error) {
+    console.error('Failed to load configuration:', error);
+    return;
+  }
📝 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.

  let db;
  try {
    db = await getConfig();
  } catch (error) {
    console.error('Failed to load configuration:', error);
    return;
  }

41-41: 🧹 Nitpick (assertive)

Remove redundant prefix check.

This check is redundant as we already verify the prefix in line 23.

-        if (!prefixes.includes(prefix)) continue;
.github/js/panel.js (2)

20-23: ⚠️ Potential issue

Security: Remove shell: true option.

Using shell: true is a security risk as it can lead to command injection vulnerabilities. Consider using array syntax for commands instead.

-  const cloneResult = spawnSync('git', ['clone', CONFIG.REPO_URL, CONFIG.PROJECT_DIR], {
-    stdio: 'inherit',
-    shell: true, // For Windows compatibility
-  });
+  const cloneResult = spawnSync(process.platform === 'win32' ? 'git.exe' : 'git', 
+    ['clone', CONFIG.REPO_URL, CONFIG.PROJECT_DIR], 
+    { stdio: 'inherit' }
+  );
📝 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.

  const cloneResult = spawnSync(process.platform === 'win32' ? 'git.exe' : 'git', 
    ['clone', CONFIG.REPO_URL, CONFIG.PROJECT_DIR], 
    { stdio: 'inherit' }
  );

30-34: ⚠️ Potential issue

Add input validation for SESSION_ID.

The SESSION_ID is written to .env file without validation, which could lead to injection vulnerabilities.

+  if (!/^[A-Za-z0-9+/=_-]+$/.test(CONFIG.SESSION_ID)) {
+    handleError('Invalid SESSION_ID format', new Error('SESSION_ID contains invalid characters'));
+  }
   try {
     writeFileSync(join(CONFIG.PROJECT_DIR, '.env'), `SESSION_ID=${CONFIG.SESSION_ID}`);
   } catch (error) {
📝 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.

  if (!/^[A-Za-z0-9+/=_-]+$/.test(CONFIG.SESSION_ID)) {
    handleError('Invalid SESSION_ID format', new Error('SESSION_ID contains invalid characters'));
  }
  try {
    writeFileSync(join(CONFIG.PROJECT_DIR, '.env'), `SESSION_ID=${CONFIG.SESSION_ID}`);
  } catch (error) {
    handleError('Failed to write .env file', error);
  }
plugins/antilink.js (1)

54-55: ⚠️ Potential issue

Remove duplicate database call.

The getAntilink function is called twice with the same parameters.

-      const status = await getAntilink(jid, 'on');
-      const actionConfig = await getAntilink(jid, 'on');
+      const config = await getAntilink(jid, 'on');
       return message.send(
-        `*_Antilink Configuration:_*\n` +
-          `Status: ${status ? 'ON' : 'OFF'}\n` +
-          `Action: ${actionConfig ? actionConfig.action : 'Not set'}`
+        `*_Antilink Configuration:_*
+Status: ${config ? 'ON' : 'OFF'}
+Action: ${config ? config.action : 'Not set'}`
       );

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

bot/anticall.js (2)

51-51: 🧹 Nitpick (assertive)

Update misleading comment.

The comment suggests country codes, but the implementation shows it's used for any number prefix matching.

-      const bannedCountryCodes = antiCallConfig.jid; // Assuming this is an array of country codes
+      const bannedPrefixes = antiCallConfig.jid; // Array of number prefixes to block
📝 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.

      const bannedPrefixes = antiCallConfig.jid; // Array of number prefixes to block

12-13: ⚠️ Potential issue

Add error handling for database operation.

The getAntiCall operation could fail during the migration to JSON storage.

-    const antiCallConfig = await getAntiCall();
-    if (!antiCallConfig.on) return; // Exit if AntiCall is disabled
+    let antiCallConfig;
+    try {
+      antiCallConfig = await getAntiCall();
+    } catch (error) {
+      console.error('Failed to get AntiCall config:', error);
+      return;
+    }
+    if (!antiCallConfig?.on) return; // Exit if AntiCall is disabled
📝 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.

    let antiCallConfig;
    try {
      antiCallConfig = await getAntiCall();
    } catch (error) {
      console.error('Failed to get AntiCall config:', error);
      return;
    }
    if (!antiCallConfig?.on) return; // Exit if AntiCall is disabled
.github/contributing.md (1)

11-14: 🧹 Nitpick (assertive)

Add blank lines around code blocks.

According to markdown best practices, fenced code blocks should be surrounded by blank lines for better readability.

Example fix for the first code block:

   - Download your forked repository to your local machine:

     ```bash
     git clone https://github.com/<your-username>/Xstro.git
     cd Xstro
     ```

Also applies to: 19-21, 23-25, 30-32, 48-51, 56-58

🧰 Tools
🪛 Markdownlint (0.37.0)

11-11: null
Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

plugins/system.js (4)

69-73: ⚠️ Potential issue

Add error handling for logout operation.

The logout operation lacks error handling and could leave the bot in an inconsistent state if it fails.

   async (message) => {
     await message.send('_logging out_');
     await delay(3000);
-    await message.client.logout();
+    try {
+      await message.client.logout();
+    } catch (error) {
+      await message.send('Error during logout: ' + error.message);
+      throw error;
+    }
   }
📝 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.

  async (message) => {
    await message.send('_logging out_');
    await delay(3000);
    try {
      await message.client.logout();
    } catch (error) {
      await message.send('Error during logout: ' + error.message);
      throw error;
    }
  }

117-117: 🧹 Nitpick (assertive)

Use template literals for string concatenation.

Replace string concatenation with template literals for better readability.

-    await message.send('```' + response + '```');
+    await message.send(`\`\`\`${response}\`\`\``);
📝 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.

    await message.send(`\`\`\`${response}\`\`\``);
🧰 Tools
🪛 Biome (1.9.4)

[error] 117-117: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


83-89: ⚠️ Potential issue

Add input validation for fetch command URL.

The fetch command accepts URLs without validation, which could lead to security vulnerabilities.

   async (message, match) => {
     if (!match) return message.send('_I need a URL_');
     const [mode, url] = match.split(';');
     if (!url) return message.send('_Use: mode;url_');
+    try {
+      const validUrl = new URL(url);
+      if (!['http:', 'https:'].includes(validUrl.protocol)) {
+        return message.send('_Invalid URL protocol. Only HTTP/HTTPS allowed_');
+      }
       const data = mode === 'json' ? JSON.stringify(await getJson(url)) : await getBuffer(url);
       return await message.send(data, mode === 'json' ? { type: 'text' } : undefined);
+    } catch (error) {
+      return message.send('_Invalid URL format_');
+    }
   }
📝 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.

  async (message, match) => {
    if (!match) return message.send('_I need a URL_');
    const [mode, url] = match.split(';');
    if (!url) return message.send('_Use: mode;url_');
    try {
      const validUrl = new URL(url);
      if (!['http:', 'https:'].includes(validUrl.protocol)) {
        return message.send('_Invalid URL protocol. Only HTTP/HTTPS allowed_');
      }
      const data = mode === 'json' ? JSON.stringify(await getJson(url)) : await getBuffer(url);
      return await message.send(data, mode === 'json' ? { type: 'text' } : undefined);
    } catch (error) {
      return message.send('_Invalid URL format_');
    }
  }

17-20: 🧹 Nitpick (assertive)

Potential race condition in ping command.

The performance measurement might be affected by the message sending delay. Consider measuring the round-trip time instead.

-    const start = performance.now();
-    const msg = await message.send('Testing Speed...');
-    const end = performance.now();
-    await msg.edit(font.tiny(`Pong! ${(end - start).toFixed(1)} ms`));
+    const start = performance.now();
+    await message.send('Testing Speed...').then(async (msg) => {
+      const end = performance.now();
+      await msg.edit(font.tiny(`Pong! ${(end - start).toFixed(1)} ms`));
+    });
plugins/news.js (1)

12-18: ⚠️ Potential issue

Add error handling for news fetching.

The news fetching operation lacks error handling and could crash if the API fails.

   async (message) => {
+    try {
       const res = await XSTRO.news();
+      if (!res?.length) {
+        return message.send('No news available at the moment.');
+      }
       let data = '';
       for (const items of res) {
         data += `\`\`\`Title: ${items.title}\n\nDescription: ${items.description}\n\nlink: ${items.url}\`\`\`\n\n`;
       }
       return await message.send(data);
+    } catch (error) {
+      console.error('News fetch error:', error);
+      return message.send('Failed to fetch news. Please try again later.');
+    }
   }
📝 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.

    try {
      const res = await XSTRO.news();
      if (!res?.length) {
        return message.send('No news available at the moment.');
      }
      let data = '';
      for (const items of res) {
        data += `\`\`\`Title: ${items.title}\n\nDescription: ${items.description}\n\nlink: ${items.url}\`\`\`\n\n`;
      }
      return await message.send(data);
    } catch (error) {
      console.error('News fetch error:', error);
      return message.send('Failed to fetch news. Please try again later.');
    }
bot/antilink.js (1)

14-15: ⚠️ Potential issue

Improve URL detection regex.

The current regex might cause catastrophic backtracking with certain inputs. Consider using a more robust pattern.

-  const urlRegex = /(https?:\/\/)?([a-z0-9-]+\.)+[a-z]{2,}(\/[^\s]*)?/i;
+  const urlRegex = /^(?:https?:\/\/)?(?:[\w-]+\.)+[a-z]{2,}(?:\/[^\s]*)?$/i;
📝 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.

  const urlRegex = /^(?:https?:\/\/)?(?:[\w-]+\.)+[a-z]{2,}(?:\/[^\s]*)?$/i;
  return urlRegex.test(str);
sql/anticall.js (2)

6-11: ⚠️ Potential issue

Add directory creation and error handling for file operations.

File operations lack proper error handling and directory creation.

+const storeDir = 'store';
+if (!fs.existsSync(storeDir)) {
+  fs.mkdirSync(storeDir, { recursive: true });
+}
+
+try {
   if (!fs.existsSync(anticallStore)) {
     fs.writeFileSync(
       anticallStore,
       JSON.stringify({ id: 1, on: false, type: 'on', action: 'block', jid: null })
     );
   }
+} catch (error) {
+  console.error('Failed to initialize anticall store:', error);
+  throw error;
+}
📝 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.

const storeDir = 'store';
if (!fs.existsSync(storeDir)) {
  fs.mkdirSync(storeDir, { recursive: true });
}

try {
  if (!fs.existsSync(anticallStore)) {
    fs.writeFileSync(
      anticallStore,
      JSON.stringify({ id: 1, on: false, type: 'on', action: 'block', jid: null })
    );
  }
} catch (error) {
  console.error('Failed to initialize anticall store:', error);
  throw error;
}

13-14: ⚠️ Potential issue

Add atomic file operations for data consistency.

Current file operations are not atomic and could lead to data corruption.

-const readDB = () => JSON.parse(fs.readFileSync(anticallStore, 'utf8'));
-const writeDB = (data) => fs.writeFileSync(anticallStore, JSON.stringify(data, null, 2));
+const readDB = () => {
+  try {
+    return JSON.parse(fs.readFileSync(anticallStore, 'utf8'));
+  } catch (error) {
+    console.error('Failed to read anticall store:', error);
+    throw error;
+  }
+};
+
+const writeDB = (data) => {
+  const tempFile = `${anticallStore}.tmp`;
+  try {
+    fs.writeFileSync(tempFile, JSON.stringify(data, null, 2));
+    fs.renameSync(tempFile, anticallStore);
+  } catch (error) {
+    if (fs.existsSync(tempFile)) {
+      fs.unlinkSync(tempFile);
+    }
+    console.error('Failed to write anticall store:', error);
+    throw error;
+  }
+};
📝 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.

const readDB = () => {
  try {
    return JSON.parse(fs.readFileSync(anticallStore, 'utf8'));
  } catch (error) {
    console.error('Failed to read anticall store:', error);
    throw error;
  }
};

const writeDB = (data) => {
  const tempFile = `${anticallStore}.tmp`;
  try {
    fs.writeFileSync(tempFile, JSON.stringify(data, null, 2));
    fs.renameSync(tempFile, anticallStore);
  } catch (error) {
    if (fs.existsSync(tempFile)) {
      fs.unlinkSync(tempFile);
    }
    console.error('Failed to write anticall store:', error);
    throw error;
  }
};
plugins/afk.js (1)

74-77: ⚠️ Potential issue

Add cleanup for AFK tracking cache.

The afkTrack object grows indefinitely as it stores timestamps for all senders.

+const CLEANUP_INTERVAL = 3600000; // 1 hour
+const MAX_CACHE_SIZE = 1000;
+
+// Add at the top of the file
+setInterval(() => {
+  const now = Date.now();
+  Object.keys(afkTrack).forEach(key => {
+    if (now - afkTrack[key] > CLEANUP_INTERVAL) {
+      delete afkTrack[key];
+    }
+  });
+}, CLEANUP_INTERVAL);
+
 const now = Date.now();
 const lastMessageTime = afkTrack[message.sender] || 0;
+
+// Cleanup if cache gets too large
+if (Object.keys(afkTrack).length > MAX_CACHE_SIZE) {
+  const oldestEntries = Object.entries(afkTrack)
+    .sort(([,a], [,b]) => a - b)
+    .slice(0, Math.floor(MAX_CACHE_SIZE / 2));
+  oldestEntries.forEach(([key]) => delete afkTrack[key]);
+}
+
 if (now - lastMessageTime < 30000) return;
 afkTrack[message.sender] = now;

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

plugins/anticall.js (4)

60-60: 🧹 Nitpick (assertive)

Use const instead of let.

The variable num is never reassigned within the loop, making it a good candidate for const.

-    for (let num of numbersToCheck) {
+    for (const num of numbersToCheck) {
📝 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.

      for (const num of numbersToCheck) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 60-60: This let declares a variable that is only assigned once.

'num' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


80-80: 🧹 Nitpick (assertive)

Consider adding input validation for country codes.

The country code validation only checks length but doesn't verify if they are valid numeric codes.

Consider adding a regex pattern to validate that country codes contain only digits:

-.filter((code) => code.length > 0 && code.length <= 4);
+.filter((code) => code.length > 0 && code.length <= 4 && /^\d+$/.test(code));
📝 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.

        .filter((code) => code.length > 0 && code.length <= 4 && /^\d+$/.test(code)); // Ensures codes are not longer than 4 characters

38-38: 🛠️ Refactor suggestion

Avoid reassigning function parameters.

The parameter match is being reassigned. This can lead to confusion and make the code harder to maintain.

-    match = match.split(',');
+    const parts = match.split(',');
-    const mode = match[0];
+    const mode = parts[0];

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 38-38: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)


71-71: 💡 Codebase verification

Parameter order mismatch in addAntiCall call

The call at line 71 swaps the type and action parameters. Based on the function definition in sql/anticall.js, it should be:

await addAntiCall(anticallConfig.type, mode, match.slice(1));
🔗 Analysis chain

Verify consistency in addAntiCall parameters.

The addAntiCall function is called with different parameter orders in lines 43 and 71. This might indicate an inconsistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all usages of addAntiCall to verify parameter consistency
rg "addAntiCall\(" -A 1

Length of output: 735

plugins/bgm.js (2)

102-108: 🧹 Nitpick (assertive)

Add rate limiting for automatic BGM responses.

The text event listener should implement rate limiting to prevent spam.

Consider implementing a cooldown mechanism for automatic BGM responses to prevent abuse.


58-60: 🛠️ Refactor suggestion

Potential race condition in audio message loading.

The code loads and relays audio messages without checking if the message is still available in storage.

     const audioMessage = await message.client.loadMessage(messageId);
-    if (!audioMessage) return message.send('_Failed to load audio message_');
+    if (!audioMessage?.message?.message) {
+      await deleteBgm(word); // Clean up invalid entry
+      return message.send('_Failed to load audio message_');
+    }

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

plugins/schedule.js (2)

21-28: ⚠️ Potential issue

Potential race condition in schedule updates.

The code retrieves and updates schedules in separate operations, which could lead to race conditions in concurrent updates.

Consider implementing atomic updates or using a locking mechanism to prevent concurrent modifications.


94-95: 🛠️ Refactor suggestion

Inconsistent admin check methods.

The file uses different methods for checking admin status: message.isAdmin vs message.isUserAdmin().

-    if (!message.isAdmin) return message.send('```You are not an Admin```');
-    if (!message.isBotAdmin) return message.send('```I am not an Admin```');
+    if (!(await message.isUserAdmin())) return message.send('```You are not an Admin```');
+    if (!(await message.isBotAdmin())) return message.send('```I am not an Admin```');
plugins/greetings.js (2)

71-71: 🛠️ Refactor suggestion

Avoid arbitrary delays.

The use of delay(2000) seems arbitrary and could affect user experience.

Consider removing the delay or making it configurable if necessary.


57-59: 🧹 Nitpick (assertive)

Use template literals for string concatenation.

String concatenation with + operator should be replaced with template literals for better readability.

-      return message.send(
-        '_Goodbye Messages Enabled, use ' + prefix + 'goodbye your message, to customize it_'
-      );
+      return message.send(
+        `_Goodbye Messages Enabled, use ${prefix}goodbye your message, to customize it_`
+      );
📝 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.

      return message.send(
        `_Goodbye Messages Enabled, use ${prefix}goodbye your message, to customize it_`
      );
plugins/translate.js (2)

32-142: 🧹 Nitpick (assertive)

Consider moving language definitions to a separate file.

The large array of language definitions could be moved to a separate configuration file for better maintainability.

Consider creating a config/languages.js file to store the language definitions.


13-15: 🧹 Nitpick (assertive)

Optimize language code lookup.

The current implementation searches through the entire languages array for each translation. Consider using a Map for O(1) lookup.

+const languageMap = new Map(
+  languages.map(lang => {
+    const [name, code] = lang.split(' - ');
+    return [code.toLowerCase(), lang];
+  })
+);
+
 const targetLang = languages.find((lang) =>
   lang.toLowerCase().endsWith(`- ${langCode.toLowerCase()}`)
 );

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

plugins/antiword.js (2)

24-24: 🧹 Nitpick (assertive)

Use template literals for string interpolation.

Replace string concatenation with template literals for better readability and maintainability.

-        '_Please enable antiword first using "' + message.prefix + 'antiword on"_'
+        `_Please enable antiword first using "${message.prefix}antiword on"_`

-          '_Provide words to block. Usage: ' + message.prefix + 'antiword set word1,word2,word3_'
+          `_Provide words to block. Usage: ${message.prefix}antiword set word1,word2,word3_`

-      '```Usage:\n' +
-        '' +
-        message.prefix +
-        'antiword on - Enable antiword\n' +
-        '' +
-        message.prefix +
-        'antiword set word1,word2,word3 - Set blocked words\n' +
-        '' +
-        message.prefix +
-        'antiword get - View current antiwords\n' +
-        '' +
-        message.prefix +
-        'antiword del word1,word2 - Delete specific words```'
+      `\`\`\`Usage:
+${message.prefix}antiword on - Enable antiword
+${message.prefix}antiword set word1,word2,word3 - Set blocked words
+${message.prefix}antiword get - View current antiwords
+${message.prefix}antiword del word1,word2 - Delete specific words\`\`\``

Also applies to: 31-31, 72-84

🧰 Tools
🪛 Biome (1.9.4)

[error] 24-24: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


33-37: 🧹 Nitpick (assertive)

Consider using Array.from() for Set conversion.

The current implementation uses spread operator with Set. While both approaches work, Array.from() can be more explicit about the intention.

-      const uniqueWords = [...new Set(wordsToSet)];
+      const uniqueWords = Array.from(new Set(wordsToSet));
📝 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.

      const wordsToSet = args[0].split(',').map((word) => word.trim());
      const uniqueWords = Array.from(new Set(wordsToSet));
      const existingWords = antiwordStatus.words || [];
      const newWords = uniqueWords.filter((word) => !existingWords.includes(word));
      if (newWords.length === 0)
plugins/notes.js (2)

32-33: 🧹 Nitpick (assertive)

Use Number namespace functions for better type safety.

Replace global parseInt and isNaN with their Number namespace equivalents for better type safety and consistency with modern JavaScript.

-    const noteId = parseInt(match.trim());
-    if (!noteId || isNaN(noteId)) return await message.send('*Format*: _.delnote id_');
+    const noteId = Number.parseInt(match.trim(), 10);
+    if (!noteId || Number.isNaN(noteId)) return await message.send('*Format*: _.delnote id_');

-    const updatedNote = await updateNote(parseInt(id), updates).catch(() => null);
+    const updatedNote = await updateNote(Number.parseInt(id, 10), updates).catch(() => null);

-    const noteId = parseInt(match.trim());
-    if (!noteId || isNaN(noteId)) return await message.send('*Format*: _.cnote id_');
+    const noteId = Number.parseInt(match.trim(), 10);
+    if (!noteId || Number.isNaN(noteId)) return await message.send('*Format*: _.cnote id_');

Also applies to: 57-57, 87-88

🧰 Tools
🪛 Biome (1.9.4)

[error] 32-32: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 33-33: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)


16-17: 💡 Codebase verification

Consider using the cleanString utility for note content sanitization

The codebase already has a cleanString utility in utils/main.js that removes ambiguous characters. Consider using it to sanitize note content before storage to prevent potential markdown injection attacks:

  • plugins/notes.js: Apply cleanString to both title and content in addNote and editNote handlers
🔗 Analysis chain

Consider adding input sanitization for note content.

The word count check is good, but consider adding input sanitization to prevent potential XSS or injection attacks in note content.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential XSS patterns in existing notes
rg -l '<script|javascript:|data:text/html|vbscript:|livescript:|<img|<svg|onerror=|onload=' 

Length of output: 110


Script:

#!/bin/bash
# Check content of utils/convert.js
cat utils/convert.js

# Find where notes content is used/displayed
rg -A 3 "content\s*=|content\." plugins/notes.js

# Look for any sanitization functions
rg -l "sanitize|escape|clean|purify"

Length of output: 6583


Script:

#!/bin/bash
# Check sanitization functions in utils/main.js
cat utils/main.js

# Find where notes are displayed/rendered
rg -A 3 "displayNote|renderNote|showNote|message\.send.*note" 

# Look for addNote implementation
ast-grep --pattern 'async function addNote'

Length of output: 11119

plugins/chats.js (1)

61-70: 🧹 Nitpick (assertive)

Consider adding error logging for failed metadata retrieval.

While the error handling is present, adding error logging would help in debugging group metadata retrieval issues.

         } catch (error) {
+          console.error(`Failed to fetch metadata for group: ${chat.jid}`, error);
           return `GROUP: Unknown Group
Messages: ${chat.messageCount}
Last Message: ${new Date(chat.lastMessageTimestamp).toLocaleString()}`;
         }
📝 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.

        try {
          const groupMetadata = await getGroupMetadata(chat.jid);
          return `GROUP: ${groupMetadata?.subject || 'Unknown Group'}
Messages: ${chat.messageCount}
Last Message: ${new Date(chat.lastMessageTimestamp).toLocaleString()}`;
        } catch (error) {
          console.error(`Failed to fetch metadata for group: ${chat.jid}`, error);
          return `GROUP: Unknown Group
Messages: ${chat.messageCount}
Last Message: ${new Date(chat.lastMessageTimestamp).toLocaleString()}`;
        }
bot/metadatagc.js (1)

108-137: 🧹 Nitpick (assertive)

Consider adding monitoring metrics for rate limits and retries.

The rate limiting implementation is robust. Consider adding monitoring metrics to track rate limit hits and retry counts for better observability.

 export const updateGroupMetadata = async (client) => {
   const handler = new RateLimitHandler();
+  let rateLimitHits = 0;
+  let totalRetries = 0;

   const updateGroups = async () => {
     try {
       const groups = await client.groupFetchAllParticipating();

       if (!groups) {
         return;
       }

       const groupIds = Object.keys(groups);

       for (const jid of groupIds) {
         if (!handler.queue.has(jid)) {
           handler.queue.set(jid, 0);
         }
       }

       await handler.processQueue(client);
     } catch (error) {
       if (error?.data === 429) {
+        rateLimitHits++;
         await handler.delay(CONFIG.RATE_LIMIT_DELAY);
       }
     }
+    // Log metrics every interval
+    console.info(`Rate limit hits: ${rateLimitHits}, Total retries: ${totalRetries}`);
   };

   await handler.delay(CONFIG.INITIAL_DELAY);
   await updateGroups();
   setInterval(updateGroups, CONFIG.INITIAL_DELAY);
 };
📝 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.

export const updateGroupMetadata = async (client) => {
  const handler = new RateLimitHandler();
  let rateLimitHits = 0;
  let totalRetries = 0;

  const updateGroups = async () => {
    try {
      const groups = await client.groupFetchAllParticipating();

      if (!groups) {
        return;
      }

      const groupIds = Object.keys(groups);

      for (const jid of groupIds) {
        if (!handler.queue.has(jid)) {
          handler.queue.set(jid, 0);
        }
      }

      await handler.processQueue(client);
    } catch (error) {
      if (error?.data === 429) {
        rateLimitHits++;
        await handler.delay(CONFIG.RATE_LIMIT_DELAY);
      }
    }
    // Log metrics every interval
    console.info(`Rate limit hits: ${rateLimitHits}, Total retries: ${totalRetries}`);
  };

  await handler.delay(CONFIG.INITIAL_DELAY);
  await updateGroups();
  setInterval(updateGroups, CONFIG.INITIAL_DELAY);
};
plugins/filters.js (2)

119-128: 🧹 Nitpick (assertive)

Consider adding rate limiting for filter responses.

The chat updates handler processes every message and responds immediately when a filter matches. This could potentially be abused to spam the chat.

Consider implementing:

  1. Rate limiting per user/group
  2. Cooldown period between filter responses
  3. Maximum responses per minute

34-42: 🛠️ Refactor suggestion

Add input validation for filter text and response.

The filter text and response are directly used without validation. Consider adding checks for:

  • Maximum length limits
  • Restricted characters or patterns
  • Empty strings after trimming
 const [text, response] = match.split(';');
 if (!text || !response) return await message.send('Both text and response are required.');
+const trimmedText = text.trim();
+const trimmedResponse = response.trim();
+if (!trimmedText || !trimmedResponse) return await message.send('Text and response cannot be empty after trimming.');
+if (trimmedText.length > 100) return await message.send('Filter text cannot exceed 100 characters.');
+if (trimmedResponse.length > 1000) return await message.send('Filter response cannot exceed 1000 characters.');
 
-const result = await addFilter('dm', text.trim(), response.trim());
+const result = await addFilter('dm', trimmedText, trimmedResponse);
📝 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.

  async (message, match) => {
    if (!match.includes(';'))
      return await message.send('Use the format: pfilter <text>;<response>');

    const [text, response] = match.split(';');
    if (!text || !response) return await message.send('Both text and response are required.');
    const trimmedText = text.trim();
    const trimmedResponse = response.trim();
    if (!trimmedText || !trimmedResponse) return await message.send('Text and response cannot be empty after trimming.');
    if (trimmedText.length > 100) return await message.send('Filter text cannot exceed 100 characters.');
    if (trimmedResponse.length > 1000) return await message.send('Filter response cannot exceed 1000 characters.');

    const result = await addFilter('dm', trimmedText, trimmedResponse);
    return await message.send(`\`\`\`${result}\`\`\``);
bot/greetings.js (2)

45-57: 🧹 Nitpick (assertive)

Optimize memory usage for large groups.

The current implementation loads all member profile pictures synchronously. For large groups, this could lead to high memory usage and slower performance.

Consider:

  1. Loading profile pictures asynchronously
  2. Implementing a cache for frequently accessed pictures
  3. Adding a limit to concurrent profile picture downloads

21-43: ⚠️ Potential issue

Add error handling for external API calls.

The XSTRO API calls for facts, quotes, and advice lack error handling. If any of these calls fail, the entire welcome message will fail.

-        const facts = await XSTRO.facts();
-        const quotes = await XSTRO.quotes();
-        const advice = await XSTRO.advice();
+        let facts = '', quotes = '', advice = '';
+        try {
+          facts = await XSTRO.facts();
+        } catch (error) {
+          console.error('Failed to fetch facts:', error);
+          facts = 'Interesting fact not available at the moment.';
+        }
+        try {
+          quotes = await XSTRO.quotes();
+        } catch (error) {
+          console.error('Failed to fetch quotes:', error);
+          quotes = 'Quote not available at the moment.';
+        }
+        try {
+          advice = await XSTRO.advice();
+        } catch (error) {
+          console.error('Failed to fetch advice:', error);
+          advice = 'Advice not available at the moment.';
+        }
📝 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.

    for (const newMember of update.participants) {
      const pp = await client.profilePictureUrl(newMember, 'image').catch(() => null);
      let message;

      if (!welcomesettings.message) {
        message = `@${newMember.split('@')[0]} welcome to ${groupInfo.subject}, Nice to meet you, we have ${groupInfo.size} group members now, @${groupInfo.subjectOwner.split('@')[0]} created this group on ${new Date(groupInfo.creation).toLocaleString('en-US', dateOptions)}, ${groupInfo.desc ? 'Read Group Description:\n\n' + groupInfo.desc : ''}`;
      } else {
        let facts = '', quotes = '', advice = '';
        try {
          facts = await XSTRO.facts();
        } catch (error) {
          console.error('Failed to fetch facts:', error);
          facts = 'Interesting fact not available at the moment.';
        }
        try {
          quotes = await XSTRO.quotes();
        } catch (error) {
          console.error('Failed to fetch quotes:', error);
          quotes = 'Quote not available at the moment.';
        }
        try {
          advice = await XSTRO.advice();
        } catch (error) {
          console.error('Failed to fetch advice:', error);
          advice = 'Advice not available at the moment.';
        }

        message = welcomesettings.message
          .replace('@owner', `@${groupInfo.subjectOwner.split('@')[0]}`)
          .replace('@gname', groupInfo.subject)
          .replace('@created', new Date(groupInfo.creation * 1000).toLocaleString())
          .replace('@user', `@${newMember.split('@')[0]}`)
          .replace('@gdesc', groupInfo.desc || 'No description')
          .replace('@members', groupInfo.size)
          .replace('@facts', facts)
          .replace('@quotes', quotes)
          .replace('@advice', advice)
          .replace('@pp', '');
      }
🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

bot/group_events.js (2)

13-24: 🧹 Nitpick (assertive)

Reduce code duplication in message sending logic.

The message sending logic is duplicated across promote and demote handlers. Consider extracting this into a reusable function.

+async function sendGroupEventMessage(client, group, participant, promoter, pp, message) {
+  const messageContent = pp !== null
+    ? {
+        image: await getBuffer(pp),
+        caption: message,
+        mentions: [participant, promoter],
+      }
+    : {
+        text: message,
+        mentions: [participant, promoter],
+      };
+  return await client.sendMessage(group, messageContent);
+}

 // Usage in promote handler
-    if (pp !== null) {
-      await client.sendMessage(events.Group, {
-        image: await getBuffer(pp),
-        caption: `\`\`\`@${participant.split('@')[0]} congrats...`,
-        mentions: [participant, promoter],
-      });
-    } else {
-      await client.sendMessage(events.Group, {
-        text: `\`\`\`@${participant.split('@')[0]} congrats...`,
-        mentions: [participant, promoter],
-      });
-    }
+    await sendGroupEventMessage(
+      client,
+      events.Group,
+      participant,
+      promoter,
+      pp,
+      `\`\`\`@${participant.split('@')[0]} congrats...`
+    );

Also applies to: 29-40


77-94: 🧹 Nitpick (assertive)

Add validation for ephemeral duration values.

The ephemeral duration check uses magic numbers. Consider using constants for better maintainability.

+const EPHEMERAL_DURATIONS = {
+  '86400': '24 hours',
+  '604800': '7 days',
+  '7776000': '90 days',
+};

-    if (update.ephemeralDuration === 86400) duration = '24 hours';
-    if (update.ephemeralDuration === 604800) duration = '7 days';
-    if (update.ephemeralDuration === 7776000) duration = '90 days';
+    duration = EPHEMERAL_DURATIONS[update.ephemeralDuration] || 'invalid duration';
📝 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.

  const EPHEMERAL_DURATIONS = {
    '86400': '24 hours',
    '604800': '7 days',
    '7776000': '90 days',
  };

  if (typeof update.ephemeralDuration !== 'undefined') {
    let duration = '';
    if (!update.ephemeralDuration) {
      return await client.sendMessage(update.id, {
        text: `\`\`\`@${update?.author ? update.author.split('@')[0] : 'Unknown'} has disabled disappearing messages\`\`\``,
        mentions: [update.author],
      });
    }

    duration = EPHEMERAL_DURATIONS[update.ephemeralDuration] || 'invalid duration';

    return await client.sendMessage(update.id, {
      text: `\`\`\`@${update.author.split('@')[0]} has set disappearing messages to ${duration}\`\`\``,
      mentions: [update.author],
    });
  }
plugins/ai.js (3)

17-17: ⚠️ Potential issue

Security: Encode URL parameters to prevent injection.

API endpoints are called with unencoded parameters, which could lead to URL injection vulnerabilities.

-await getJson(`https://bk9.fun/ai/chataibot?q=${match || message.reply_message.text}`)
+await getJson(`https://bk9.fun/ai/chataibot?q=${encodeURIComponent(match || message.reply_message.text)}`)

Apply similar changes to all API calls in the file.

Also applies to: 33-33, 50-50, 68-68, 82-82, 103-103, 124-124, 145-145, 164-164, 182-182


14-14: 🧹 Nitpick (assertive)

Use template literals instead of string concatenation.

Replace string concatenation with template literals for better readability.

-return message.send('_Hello there ' + pushName + '_');
+return message.send(`_Hello there ${pushName}_`);

Also applies to: 98-98, 119-119, 140-140, 161-161, 178-178

🧰 Tools
🪛 Biome (1.9.4)

[error] 14-14: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


81-86: ⚠️ Potential issue

Add error handling for image generation.

The DALLE image generation lacks proper error handling and could fail silently.

 async (message, match) => {
   if (!match) return message.send('_Give me a prompt!_');
-  const res = await getBuffer(`https://bk9.fun/ai/magicstudio?prompt=${match}`);
-  return await message.send(res, {
-    caption: `_Here is your image for:_ ${match}`,
-  });
+  try {
+    const msg = await message.send('_Generating image..._');
+    const res = await getBuffer(`https://bk9.fun/ai/magicstudio?prompt=${encodeURIComponent(match)}`);
+    await message.send(res, {
+      caption: `_Here is your image for:_ ${match}`,
+    });
+    return await msg.delete();
+  } catch (error) {
+    return message.send('Failed to generate image. Please try again later.');
+  }
 }
📝 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.

    if (!match) return message.send('_Give me a prompt!_');
    try {
      const msg = await message.send('_Generating image..._');
      const res = await getBuffer(`https://bk9.fun/ai/magicstudio?prompt=${encodeURIComponent(match)}`);
      await message.send(res, {
        caption: `_Here is your image for:_ ${match}`,
      });
      return await msg.delete();
    } catch (error) {
      return message.send('Failed to generate image. Please try again later.');
    }
  }
plugins/dev.js (3)

15-140: 🧹 Nitpick (assertive)

⚠️ Potential issue

Security concern: Unsafe code execution.

The implementation uses new Function() for code execution, which poses security risks similar to eval(). Consider implementing a more secure approach:

  1. Use a dedicated sandbox environment
  2. Implement strict input validation
  3. Limit available APIs and resources
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: This let declares a variable that is only assigned once.

'importedModules' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


144-181: ⚠️ Potential issue

Critical security vulnerability: Direct use of eval().

The direct use of eval() is highly dangerous as it can execute arbitrary code. This poses significant security risks:

  1. Remote Code Execution (RCE) vulnerability
  2. No sandboxing or isolation
  3. Access to sensitive context

Replace this implementation with a secure alternative that doesn't use eval(). Consider using:

  1. A dedicated code execution sandbox
  2. Static code analysis
  3. Restricted command execution
🧰 Tools
🪛 Biome (1.9.4)

[error] 155-155: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)


41-41: 🧹 Nitpick (assertive)

Use const for variables that are not reassigned.

Replace let with const as the variable is only assigned once.

-let importedModules = {};
+const importedModules = {};
📝 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.

      const importedModules = {};
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: This let declares a variable that is only assigned once.

'importedModules' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

readme.md (4)

52-54: 🧹 Nitpick (assertive)

Enhance deployment instructions clarity.

The deployment instructions for various platforms could be more detailed:

  1. Explain what each environment variable (SESSION_ID, BOT_INFO, etc.) represents
  2. Provide example values or format requirements
  3. Add troubleshooting steps for common deployment issues

Also applies to: 59-61, 66-72


79-79: 🧹 Nitpick (assertive)

Fix macOS capitalization.

Correct the capitalization of "MacOS" to "macOS" to align with Apple's official branding.

-### Windows/Linux/MacOS Deploy
+### Windows/Linux/macOS 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.

### Windows/Linux/macOS Deploy
🧰 Tools
🪛 LanguageTool

[grammar] ~79-~79: The operating system from Apple is written “macOS”.
Context: .../wiki/Panel-Support) ### Windows/Linux/MacOS Deploy #### 1. Install Node.js * **Wi...

(MAC_OS)


61-61: 🧹 Nitpick (assertive)

Add hyphens to compound modifier.

Add hyphens to "pre and post" when used as a compound modifier before "deployment".

-alter the pre and post deployment process
+alter the pre- and post-deployment process
📝 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.

* If you are not an advanced koyeb user, just tap on the `deploy` button, after you have filled the variables and aviod any necessary options that "may" or "will" alter the pre- and post-deployment process.
🧰 Tools
🪛 LanguageTool

[grammar] ~61-~61: It appears that hyphens are missing.
Context: ... options that "may" or "will" alter the pre and post deployment process. * Watch Video Tutorial ##...

(PRE_AND_POST_NN)


55-55: 💡 Codebase verification

Empty video tutorial links should be removed

The verification confirms that there are three empty video tutorial links [Watch Video Tutorial]() in the deployment sections for Heroku, Koyeb, and Render. These placeholder links should be removed until actual tutorial videos are available to avoid misleading users.

  • Line 55: Empty Heroku tutorial link
  • Line 62: Empty Koyeb tutorial link
  • Line 73: Empty Render tutorial link
🔗 Analysis chain

Add video tutorial links or remove placeholder references.

The documentation contains empty video tutorial links for Heroku, Koyeb, and Render deployments. Either provide the actual tutorial links or remove these references to avoid confusion.

Also applies to: 62-62, 73-73

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if video tutorials exist in the repository
fd -e mp4 -e webm -e mkv tutorial

Length of output: 35


Script:

#!/bin/bash
# Check the content of readme.md and look for video-related references
echo "=== Readme Content ==="
cat readme.md

echo -e "\n=== Searching for video-related terms ==="
rg -i "video|tutorial|watch" --type md

Length of output: 6794

🧰 Tools
🪛 Markdownlint (0.37.0)

55-55: null
No empty links

(MD042, no-empty-links)

plugins/download.js (2)

17-17: ⚠️ Potential issue

Move API credentials to environment variables.

The API key is hardcoded in the source code, which is a security risk. Move it to environment variables.

-const KEY = `free_key@maher_apis`;
+const KEY = process.env.NEXORACLE_API_KEY;

Also applies to: 29-29


146-147: 🧹 Nitpick (assertive)

Implement rate limiting for API calls.

Add rate limiting to prevent abuse of external APIs, especially for resource-intensive operations like media downloads.

Consider using a rate limiting library like express-rate-limit or implement a custom solution using a token bucket algorithm.

Also applies to: 186-192

plugins/whatsapp.js (5)

69-85: 🧹 Nitpick (assertive)

Use const and add error handling.

The implementation can be improved by:

  1. Using const instead of let for the key variable
  2. Adding proper error handling for message loading failures
 bot(
   {
     pattern: 'quoted',
     public: false,
     type: 'whatsapp',
     desc: 'quoted message',
   },
   async (message) => {
     if (!message.reply_message) return await message.send('```Reply A Message```');
-    let key = message.reply_message.key.id;
-    let msg = await message.client.loadMessage(key);
-    if (!msg) return await message.send('```Xstro will not quoted Bot Message```');
-    msg = await serialize(JSON.parse(JSON.stringify(msg.message)), message.client);
-    if (!msg.quoted) return await message.send('_No quoted message found_');
-    await message.forward(message.jid, msg.quoted, {
-      quoted: msg.quoted,
-    });
+    try {
+      const key = message.reply_message.key.id;
+      const msg = await message.client.loadMessage(key);
+      if (!msg) return await message.send('```Xstro will not quoted Bot Message```');
+      const serializedMsg = await serialize(JSON.parse(JSON.stringify(msg.message)), message.client);
+      if (!serializedMsg.quoted) return await message.send('_No quoted message found_');
+      await message.forward(message.jid, serializedMsg.quoted, {
+        quoted: serializedMsg.quoted,
+      });
+    } catch (error) {
+      return await message.send('_Failed to process quoted message_');
+    }
   }
 );
🧰 Tools
🪛 Biome (1.9.4)

[error] 77-77: This let declares a variable that is only assigned once.

'key' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


4-4: 🛠️ Refactor suggestion

Remove unused import.

The isJidBroadcast import is not used in this file.

-import { delay, isJidBroadcast, isJidGroup } from 'baileys';
+import { delay, isJidGroup } from 'baileys';
📝 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.

import { delay, isJidGroup } from 'baileys';

6-17: 🧹 Nitpick (assertive)

Add error handling for network failures.

The vv command should handle potential network failures when downloading viewonce messages.

 bot(
   {
     pattern: 'vv',
     public: false,
     desc: 'Downloads A Viewonce Message',
     type: 'whatsapp',
   },
   async (message) => {
     if (!message.reply_message.viewonce) return message.send('_Reply A Viewonce Message_');
-    const res = await ModifyViewOnceMessage(message.id, message.client);
-    return message.client.relayMessage(message.jid, res.message, {});
+    try {
+      const res = await ModifyViewOnceMessage(message.id, message.client);
+      return message.client.relayMessage(message.jid, res.message, {});
+    } catch (error) {
+      return message.send('_Failed to download viewonce message_');
+    }
   }
 );
📝 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.

bot(
  {
    pattern: 'vv',
    public: false,
    desc: 'Downloads A Viewonce Message',
    type: 'whatsapp',
  },
  async (message) => {
    if (!message.reply_message.viewonce) return message.send('_Reply A Viewonce Message_');
    try {
      const res = await ModifyViewOnceMessage(message.id, message.client);
      return message.client.relayMessage(message.jid, res.message, {});
    } catch (error) {
      return message.send('_Failed to download viewonce message_');
    }
  }

20-36: 🧹 Nitpick (assertive)

Simplify media type check and add error handling.

The media type check can be simplified, and error handling should be added for conversion failures.

 bot(
   {
     pattern: 'tovv',
     public: true,
     desc: 'Converts A Normal Media Message to ViewOnce',
     type: 'whatsapp',
   },
   async (message) => {
-    if (
-      !message.reply_message.video &&
-      !message.reply_message.audio &&
-      !message.reply_message.image
-    )
+    const validTypes = ['video', 'audio', 'image'];
+    if (!validTypes.some(type => message.reply_message[type]))
       return message.send('_Reply an Image | Video | Audio_');
-    const viewonceMessage = await convertNormalMessageToViewOnce(message.data.quoted.message);
-    return message.client.relayMessage(message.jid, viewonceMessage, {});
+    try {
+      const viewonceMessage = await convertNormalMessageToViewOnce(message.data.quoted.message);
+      return message.client.relayMessage(message.jid, viewonceMessage, {});
+    } catch (error) {
+      return message.send('_Failed to convert to viewonce message_');
+    }
   }
 );
📝 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.

bot(
  {
    pattern: 'tovv',
    public: true,
    desc: 'Converts A Normal Media Message to ViewOnce',
    type: 'whatsapp',
  },
  async (message) => {
    const validTypes = ['video', 'audio', 'image'];
    if (!validTypes.some(type => message.reply_message[type]))
      return message.send('_Reply an Image | Video | Audio_');
    try {
      const viewonceMessage = await convertNormalMessageToViewOnce(message.data.quoted.message);
      return message.client.relayMessage(message.jid, viewonceMessage, {});
    } catch (error) {
      return message.send('_Failed to convert to viewonce message_');
    }
  }
);

214-237: 🧹 Nitpick (assertive)

Improve JID handling and add error handling.

The implementation can be improved by:

  1. Simplifying the JID validation logic
  2. Adding error handling for forwarding failures
 bot(
   {
     pattern: 'forward',
     public: false,
     type: 'whatsapp',
     desc: 'Forwards A Replied Message',
   },
   async (message, match) => {
     if (!message.reply_message) return message.send('_Reply A Message!_');
-    let jid;
-    if (message.mention && message.mention[0]) {
-      jid = message.mention[0];
-    } else if (isJidGroup(match)) {
-      return message.send('_Use Gforward command to forward to groups_');
-    } else if (!isJidGroup(match)) {
-      jid = toJid(match);
-    }
-    if (!jid) return message.send('_You have to provide a number/tag someone_');
-    const msg = message.data?.quoted;
-    await message.forward(jid, msg, { quoted: msg });
-    return await message.send(`_Message forward to @${jid.split('@')[0]}_`, {
-      mentions: [jid],
-    });
+    try {
+      const jid = message.mention?.[0] || (!isJidGroup(match) && toJid(match));
+      if (!jid) return message.send('_You have to provide a number/tag someone_');
+      if (isJidGroup(match)) return message.send('_Use Gforward command to forward to groups_');
+      const msg = message.data?.quoted;
+      await message.forward(jid, msg, { quoted: msg });
+      return await message.send(`_Message forwarded to @${jid.split('@')[0]}_`, {
+        mentions: [jid],
+      });
+    } catch (error) {
+      return message.send('_Failed to forward message_');
+    }
   }
 );
📝 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.

bot(
  {
    pattern: 'forward',
    public: false,
    type: 'whatsapp',
    desc: 'Forwards A Replied Message',
  },
  async (message, match) => {
    if (!message.reply_message) return message.send('_Reply A Message!_');
    try {
      const jid = message.mention?.[0] || (!isJidGroup(match) && toJid(match));
      if (!jid) return message.send('_You have to provide a number/tag someone_');
      if (isJidGroup(match)) return message.send('_Use Gforward command to forward to groups_');
      const msg = message.data?.quoted;
      await message.forward(jid, msg, { quoted: msg });
      return await message.send(`_Message forwarded to @${jid.split('@')[0]}_`, {
        mentions: [jid],
      });
    } catch (error) {
      return message.send('_Failed to forward message_');
    }
  }
);
🧰 Tools
🪛 Biome (1.9.4)

[error] 224-224: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

plugins/group.js (3)

86-86: 🛠️ Refactor suggestion

Replace unsafe isNaN with Number.isNaN.

The global isNaN function attempts type coercion and can lead to unexpected results.

-    if (!countryCode || isNaN(countryCode))
+    if (!countryCode || Number.isNaN(Number(countryCode)))
📝 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.

    if (!countryCode || Number.isNaN(Number(countryCode)))
🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)


235-241: 🧹 Nitpick (assertive)

Use const for variables and improve array handling.

Multiple variables declared with let are never reassigned. Also, the array handling can be improved.

-    let [pollName, pollOptions] = match.split(';');
+    const [pollName, pollOptions] = match.split(';');
     if (!pollOptions)
       return await message.send(message.prefix + 'poll question;option1,option2,option3.....');
-    let options = [];
-    for (let option of pollOptions.split(','))
-      if (option && option.trim() !== '') options.push(option.trim());
+    const options = pollOptions.split(',')
+      .map(option => option.trim())
+      .filter(Boolean);
📝 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.

    const [pollName, pollOptions] = match.split(';');
    if (!pollOptions)
      return await message.send(message.prefix + 'poll question;option1,option2,option3.....');
    const options = pollOptions.split(',')
      .map(option => option.trim())
      .filter(Boolean);
    await message.client.sendMessage(message.jid, {
🧰 Tools
🪛 Biome (1.9.4)

[error] 237-237: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


[error] 235-235: This let declares some variables that are only assigned once.

'pollName' is never reassigned.

'pollOptions' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 238-238: This let declares a variable that is only assigned once.

'options' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 239-239: This let declares a variable that is only assigned once.

'option' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


387-391: 🧹 Nitpick (assertive)

Use const and array methods for request handling.

The request handling code can be improved using const and modern array methods.

-    let requestJids = [];
-    for (let request of joinRequests) {
-      requestList += `@${request.jid.split('@')[0]}\n`;
-      requestJids.push(request.jid);
-    }
+    const requestJids = joinRequests.map(request => {
+      requestList += `@${request.jid.split('@')[0]}\n`;
+      return request.jid;
+    });

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 387-387: This let declares a variable that is only assigned once.

'requestJids' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 388-388: This let declares a variable that is only assigned once.

'request' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

plugins/areact.js (3)

39-1569: 🛠️ Refactor suggestion

Move emojis to a separate configuration file.

The large emoji array should be:

  1. Declared as a constant
  2. Moved to a separate configuration file
  3. Potentially categorized for better management

Create a new file config/emojis.js:

export const emojis = {
  hearts: ['💘', '💝', '💖', /* ... */],
  faces: ['😀', '😃', '😄', /* ... */],
  // ... more categories
};

26-36: 🛠️ Refactor suggestion

Add rate limiting to auto-react feature.

The auto-react feature should include rate limiting to prevent spam and excessive reactions.

 bot(
   {
     on: 'text',
     dontAddCommandList: true,
   },
   async (message) => {
     const autoReactSetting = await AutoReact.findOne();
     if (autoReactSetting?.status) {
+      const lastReactTime = await message.client.getLastReactTime(message.jid);
+      const now = Date.now();
+      if (lastReactTime && now - lastReactTime < 5000) return; // 5 seconds cooldown
       const emoji = getRandom(emojis);
       await message.react(emoji);
+      await message.client.setLastReactTime(message.jid, now);
     }
   }
 );

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


6-22: 🧹 Nitpick (assertive)

Improve areact command validation.

The areact command should validate the status input and provide better feedback.

 bot(
   {
     pattern: 'areact',
     public: false,
     desc: 'Toggle Auto React On/Off',
     type: 'user',
   },
   async (message, match) => {
+    if (!match || !['on', 'off'].includes(match.toLowerCase())) {
+      return message.send('_Usage: .areact on/off_');
+    }
-    const status = match;
-    const newStatus = status === 'on';
+    const newStatus = match.toLowerCase() === 'on';
     const currentSetting = await AutoReact.findOne();
     if (currentSetting) {
       await AutoReact.update({ status: newStatus }, { where: {} });
     } else {
       await AutoReact.create({ status: newStatus });
     }
     await message.send(`_Autoreact set to ${newStatus ? 'ON' : 'OFF'}._`);
   }
 );
📝 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.

  {
    pattern: 'areact',
    public: false,
    desc: 'Toggle Auto React On/Off',
    type: 'user',
  },
  async (message, match) => {
    if (!match || !['on', 'off'].includes(match.toLowerCase())) {
      return message.send('_Usage: .areact on/off_');
    }
    const newStatus = match.toLowerCase() === 'on';
    const currentSetting = await AutoReact.findOne();
    if (currentSetting) {
      await AutoReact.update({ status: newStatus }, { where: {} });
    } else {
      await AutoReact.create({ status: newStatus });
    }
    await message.send(`_Autoreact set to ${newStatus ? 'ON' : 'OFF'}._`);
  }
plugins/forex.js (1)

169-170: ⚠️ Potential issue

Fix incorrect API endpoints in fxasia and fxpacific commands.

Both commands are using the 'fxmajor' endpoint instead of their respective endpoints.

- const res = await XSTRO.forex('fxmajor');
+ const res = await XSTRO.forex('fxasia');
- const res = await XSTRO.forex('fxmajor');
+ const res = await XSTRO.forex('fxpacific');

Also applies to: 197-198

plugins/converter.js (1)

71-73: ⚠️ Potential issue

Fix undefined variable reference.

The validDirections array is referenced but not defined. This will cause a runtime error.

+ const validDirections = ['left', 'right', 'vertical', 'horizontal'];
  if (!['left', 'right', 'vertical', 'horizontal'].includes(match)) {
-   return message.send(`_Usage: ${prefix}flip <${validDirections.join('/')}>`);
+   return message.send(`_Usage: ${prefix}flip <${['left', 'right', 'vertical', 'horizontal'].join('/')}>`);
  }
📝 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.

    const validDirections = ['left', 'right', 'vertical', 'horizontal'];
    if (!['left', 'right', 'vertical', 'horizontal'].includes(match)) {
      return message.send(`_Usage: ${prefix}flip <${['left', 'right', 'vertical', 'horizontal'].join('/')}>`);
    }
lib/class.js (1)

266-287: 🛠️ Refactor suggestion

Add cleanup for temporary files.

The download method creates temporary files but doesn't clean them up. This could lead to disk space issues over time.

  async download(file = false) {
    const buffer = await downloadMediaMessage(
      {
        key: this.data.quoted.key,
        message: this.data?.quoted?.message,
      },
      'buffer',
      {},
      {
        logger: console,
        reuploadRequest: this.client.updateMediaMessage,
      }
    );
    if (file) {
      const extension = await FileTypeFromBuffer(buffer);
      const filename = `${Date.now()}.${extension}`;
      const filepath = path.join(os.tmpdir(), filename);
      await fs.promises.writeFile(filepath, buffer);
+     // Schedule cleanup after a reasonable delay (e.g., 1 hour)
+     setTimeout(async () => {
+       try {
+         await fs.promises.unlink(filepath);
+       } catch (error) {
+         console.error(`Failed to cleanup temporary file ${filepath}:`, error);
+       }
+     }, 3600000);
      return filepath;
    }
    return buffer;
  }
📝 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.

  async download(file = false) {
    const buffer = await downloadMediaMessage(
      {
        key: this.data.quoted.key,
        message: this.data?.quoted?.message,
      },
      'buffer',
      {},
      {
        logger: console,
        reuploadRequest: this.client.updateMediaMessage,
      }
    );
    if (file) {
      const extension = await FileTypeFromBuffer(buffer);
      const filename = `${Date.now()}.${extension}`;
      const filepath = path.join(os.tmpdir(), filename);
      await fs.promises.writeFile(filepath, buffer);
      // Schedule cleanup after a reasonable delay (e.g., 1 hour)
      setTimeout(async () => {
        try {
          await fs.promises.unlink(filepath);
        } catch (error) {
          console.error(`Failed to cleanup temporary file ${filepath}:`, error);
        }
      }, 3600000);
      return filepath;
    }
    return buffer;
  }
plugins/config.js (3)

12-17: 🛠️ Refactor suggestion

Add error handling for database operations.

The commands make external calls to getConfig() and updateConfig() without proper error handling. This could lead to unhandled exceptions if the database operations fail.

Example implementation:

 async (message, match) => {
   try {
     const dbConfig = await getConfig();
     // ... existing logic ...
     await updateConfig('key', value);
     return await message.send('Success message');
   } catch (error) {
     console.error('Failed to update configuration:', error);
     return await message.send('_Failed to update configuration. Please try again._');
   }
 }

Also applies to: 27-35, 46-54, 65-73, 84-92, 103-111, 122-130, 141-146, 157-170, 181-190, 201-210, 221-230, 241-249, 260-268


163-168: ⚠️ Potential issue

Fix command validation in disable command.

The command filtering logic doesn't verify if the provided command exists. The cmds variable is never used to validate the command name.

-    const cmds = commands.filter(
-      (cmd) =>
-        cmd.pattern && !cmd.dontAddCommandList && !cmd.pattern.toString().includes('undefined')
-    );
-    if (!cmds) return await message.send('_Command not found_');
+    const cmd = commands.find(
+      (cmd) =>
+        cmd.pattern && 
+        !cmd.dontAddCommandList && 
+        !cmd.pattern.toString().includes('undefined') &&
+        cmd.pattern.toString() === match
+    );
+    if (!cmd) return await message.send('_Command not found_');
📝 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.

    const cmd = commands.find(
      (cmd) =>
        cmd.pattern && 
        !cmd.dontAddCommandList && 
        !cmd.pattern.toString().includes('undefined') &&
        cmd.pattern.toString() === match
    );
    if (!cmd) return await message.send('_Command not found_');
    if (await isCmdDisabled(match)) return await message.send('_Command already disabled_');

129-130: ⚠️ Potential issue

Fix incorrect configuration key in cmdread command.

The command updates cmdReact instead of cmdRead in the database, which will cause unexpected behavior.

-    await updateConfig('cmdReact', newValue);
+    await updateConfig('cmdRead', newValue);
📝 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.

    await updateConfig('cmdRead', newValue);
    return await message.send(`_CmdRead set to ${newValue ? 'on' : 'off'}._`);
plugins/search.js (5)

15-15: 🧹 Nitpick (assertive)

Move API URL to configuration.

The API URL is hardcoded in the code. Consider moving it to a configuration file to make it easier to maintain and update.


36-54: 🧹 Nitpick (assertive)

Use const for variables that aren't reassigned.

The variables imdbInfo and forecastMessage are never reassigned and should use const instead of let.

-    let imdbInfo = [
+    const imdbInfo = [
     // ...
-    let forecastMessage = forecast
+    const forecastMessage = forecast

Also applies to: 305-316

🧰 Tools
🪛 Biome (1.9.4)

[error] 36-36: This let declares a variable that is only assigned once.

'imdbInfo' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


34-34: ⚠️ Potential issue

Secure API keys and sanitize user input.

Several security concerns need to be addressed:

  1. API keys are hardcoded in the code (e.g., OMDB API key, OpenWeatherMap API key)
  2. User input is used directly in API calls without proper sanitization

This could lead to API key exposure and potential injection attacks.

  1. Move API keys to environment variables:
-      `http://www.omdbapi.com/?apikey=742b2d09&t=${encodeURIComponent(match)}&plot=full`
+      `http://www.omdbapi.com/?apikey=${process.env.OMDB_API_KEY}&t=${encodeURIComponent(match)}&plot=full`
  1. Add input validation and sanitization:
+    if (match.length > 100) return message.send('_Search query too long_');
+    if (!/^[a-zA-Z0-9\s]+$/.test(match)) return message.send('_Invalid characters in search query_');
     const res = await getJson(/* ... */);

Also applies to: 70-70, 274-274


150-153: 🧹 Nitpick (assertive)

Use template literals instead of string concatenation.

Replace string concatenation with template literals for better readability.

-      return message.send('_Please provide a zodiac sign_\nValid signs: ' + signs.join(', '));
+      return message.send(`_Please provide a zodiac sign_\nValid signs: ${signs.join(', ')}`);
-      return message.send('_Invalid zodiac sign_\nValid signs: ' + signs.join(', '));
+      return message.send(`_Invalid zodiac sign_\nValid signs: ${signs.join(', ')}`);
📝 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.

      return message.send(`_Please provide a zodiac sign_\nValid signs: ${signs.join(', ')}`);
    const sign = match.toLowerCase();
    if (!signs.includes(sign))
      return message.send(`_Invalid zodiac sign_\nValid signs: ${signs.join(', ')}`);
🧰 Tools
🪛 Biome (1.9.4)

[error] 150-150: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


[error] 153-153: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


15-20: ⚠️ Potential issue

Add error handling for lyrics API call.

The external API call lacks error handling, which could lead to unhandled exceptions if the API is unavailable or returns an error.

-    const res = await getJson(`https://itzpire.com/search/lyrics?query=${req}`);
-    const { title, album, thumb, lyrics } = res.data;
-    const image = await getBuffer(thumb);
-    return await message.send(image, {
-      caption: `*${title}*\n\`\`\`${album}\n\n${lyrics}\`\`\``,
-    });
+    try {
+      const res = await getJson(`https://itzpire.com/search/lyrics?query=${req}`);
+      if (!res?.data) {
+        return await message.send('_No lyrics found_');
+      }
+      const { title, album, thumb, lyrics } = res.data;
+      const image = await getBuffer(thumb);
+      return await message.send(image, {
+        caption: `*${title}*\n\`\`\`${album}\n\n${lyrics}\`\`\``,
+      });
+    } catch (error) {
+      console.error('Failed to fetch lyrics:', error);
+      return await message.send('_Failed to fetch lyrics. Please try again._');
+    }
📝 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.

    try {
      const res = await getJson(`https://itzpire.com/search/lyrics?query=${req}`);
      if (!res?.data) {
        return await message.send('_No lyrics found_');
      }
      const { title, album, thumb, lyrics } = res.data;
      const image = await getBuffer(thumb);
      return await message.send(image, {
        caption: `*${title}*\n\`\`\`${album}\n\n${lyrics}\`\`\``,
      });
    } catch (error) {
      console.error('Failed to fetch lyrics:', error);
      return await message.send('_Failed to fetch lyrics. Please try again._');
    }

Copy link

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 435f6e7 and 52e3a53.

📒 Files selected for processing (4)
  • bot/antidelete.js (1 hunks)
  • lib/client.js (1 hunks)
  • lib/events.js (1 hunks)
  • lib/message.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
lib/client.js

[error] 11-11: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 99-99: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 58-58: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)

lib/events.js

[error] 16-16: This let declares a variable that is only assigned once.

'tasks' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

bot/antidelete.js Outdated Show resolved Hide resolved
Comment on lines 14 to 16
// console.log(msg.isProtocol);
// console.log(store);

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Eliminate unused commented-out code

The commented-out code in lines 14-16 is not needed and can be removed to keep the code clean.

Apply this diff to remove the unnecessary comments:

-  // console.log(msg.isProtocol);
-  // console.log(store);

bot/antidelete.js Outdated Show resolved Hide resolved
Comment on lines 12 to 13
const client = msg.client;
const store = await msg.client.loadMessage(msg.isProtocol.key.id);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove unused variables 'client' and 'store'

The variables client and store are assigned but not used within the function. Consider removing them to avoid confusion.

Apply this diff to remove the unused variables:

-  const client = msg.client;
-  const store = await msg.client.loadMessage(msg.isProtocol.key.id);

lib/events.js Outdated Show resolved Hide resolved
Comment on lines +31 to +36
if (isGroup) {
const metadata = await conn.groupMetadata(remoteJid);
const participant = messages.key.participant;
msg.isAdmin = !!metadata.participants.find((p) => p.id === participant)?.admin || false;
msg.isBotAdmin = !!metadata.participants.find((p) => p.id === owner)?.admin || false;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for group metadata fetch.

The groupMetadata call could fail if the group doesn't exist or if there are network issues. Consider adding try-catch block:

 if (isGroup) {
+  try {
     const metadata = await conn.groupMetadata(remoteJid);
     const participant = messages.key.participant;
     msg.isAdmin = !!metadata.participants.find((p) => p.id === participant)?.admin || false;
     msg.isBotAdmin = !!metadata.participants.find((p) => p.id === owner)?.admin || false;
+  } catch (error) {
+    console.error('Failed to fetch group metadata:', error);
+    msg.isAdmin = false;
+    msg.isBotAdmin = false;
+  }
 }
📝 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
if (isGroup) {
const metadata = await conn.groupMetadata(remoteJid);
const participant = messages.key.participant;
msg.isAdmin = !!metadata.participants.find((p) => p.id === participant)?.admin || false;
msg.isBotAdmin = !!metadata.participants.find((p) => p.id === owner)?.admin || false;
}
if (isGroup) {
try {
const metadata = await conn.groupMetadata(remoteJid);
const participant = messages.key.participant;
msg.isAdmin = !!metadata.participants.find((p) => p.id === participant)?.admin || false;
msg.isBotAdmin = !!metadata.participants.find((p) => p.id === owner)?.admin || false;
} catch (error) {
console.error('Failed to fetch group metadata:', error);
msg.isAdmin = false;
msg.isBotAdmin = false;
}
}

lib/message.js Outdated Show resolved Hide resolved
lib/message.js Show resolved Hide resolved
await msg.send(
`\`\`\`An Error Occurred while running ${cmd.pattern.toString().split(/\W+/)[2]} command!\`\`\``
);
const name = cmd.pattern.toString().split(/\W+/)[1] || 'UNKNOWN CMD';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve command name extraction reliability.

The current regex pattern split might be fragile. Consider adding a fallback for command name extraction:

-      const name = cmd.pattern.toString().split(/\W+/)[1] || 'UNKNOWN CMD';
+      const name = extractCommandName(cmd.pattern);

+function extractCommandName(pattern) {
+  try {
+    const matches = pattern.toString().match(/\w+/g);
+    return matches?.[1] || 'UNKNOWN CMD';
+  } catch {
+    return 'UNKNOWN CMD';
+  }
+}

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

Comment on lines +70 to +87
const quoted =
messages.message?.[msg.type]?.contextInfo?.quotedMessage ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.quotedMessage
)
);

if (quoted) {
const quotedMessage = normalizeMessageContent(quoted);
const quotedType = getContentType(quotedMessage);
const stanzaId =
messages.message?.[msg.type]?.contextInfo?.stanzaId ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
)
);
msg.quoted = {
key: {
id: normalizeMessageContent(stanzaId) || null,
fromMe: messages.message?.[msg.type]?.contextInfo?.participant === owner,
remoteJid: msg.key.remoteJid,
participant: isGroup
? normalizeMessageContent(messages.message?.[InquotedType]?.contextInfo?.participant)
: undefined
},
message: quotedMessage,
type: quotedType,
viewonce: quotedMessage?.[quotedType]?.viewOnce || false,
body:
quotedMessage?.conversation ||
quotedMessage?.[quotedType]?.text ||
quotedMessage?.[quotedType]?.caption ||
false
};
} else {
msg.quoted = null;
}
if (quoted) {
const quotedMessage = normalizeMessageContent(quoted);
const quotedType = getContentType(quotedMessage);
const stanzaId =
messages.message?.[msg.type]?.contextInfo?.stanzaId ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
)
);
Copy link

@coderabbitai coderabbitai bot Jan 18, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract helper functions for quoted message processing.

The repeated normalization calls and deep nesting make the code hard to follow. Consider extracting helper functions:

+function getQuotedMessage(messages, msgType, InquotedType, deepQuotedType) {
+  return messages.message?.[msgType]?.contextInfo?.quotedMessage ||
+    normalizeMessageContent(
+      normalizeMessageContent(
+        messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.quotedMessage
+      )
+    );
+}

+function getStanzaId(messages, msgType, InquotedType, deepQuotedType) {
+  return messages.message?.[msgType]?.contextInfo?.stanzaId ||
+    normalizeMessageContent(
+      normalizeMessageContent(
+        messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
+      )
+    );
+}

-  const quoted = messages.message?.[msg.type]?.contextInfo?.quotedMessage ||
-    normalizeMessageContent(
-      normalizeMessageContent(
-        messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.quotedMessage
-      )
-    );
+  const quoted = getQuotedMessage(messages, msg.type, InquotedType, deepQuotedType);

-  const stanzaId = messages.message?.[msg.type]?.contextInfo?.stanzaId ||
-    normalizeMessageContent(
-      normalizeMessageContent(
-        messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
-      )
-    );
+  const stanzaId = getStanzaId(messages, msg.type, InquotedType, deepQuotedType);
📝 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 quoted =
messages.message?.[msg.type]?.contextInfo?.quotedMessage ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.quotedMessage
)
);
if (quoted) {
const quotedMessage = normalizeMessageContent(quoted);
const quotedType = getContentType(quotedMessage);
const stanzaId =
messages.message?.[msg.type]?.contextInfo?.stanzaId ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
)
);
msg.quoted = {
key: {
id: normalizeMessageContent(stanzaId) || null,
fromMe: messages.message?.[msg.type]?.contextInfo?.participant === owner,
remoteJid: msg.key.remoteJid,
participant: isGroup
? normalizeMessageContent(messages.message?.[InquotedType]?.contextInfo?.participant)
: undefined
},
message: quotedMessage,
type: quotedType,
viewonce: quotedMessage?.[quotedType]?.viewOnce || false,
body:
quotedMessage?.conversation ||
quotedMessage?.[quotedType]?.text ||
quotedMessage?.[quotedType]?.caption ||
false
};
} else {
msg.quoted = null;
}
if (quoted) {
const quotedMessage = normalizeMessageContent(quoted);
const quotedType = getContentType(quotedMessage);
const stanzaId =
messages.message?.[msg.type]?.contextInfo?.stanzaId ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
)
);
function getQuotedMessage(messages, msgType, InquotedType, deepQuotedType) {
return messages.message?.[msgType]?.contextInfo?.quotedMessage ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.quotedMessage
)
);
}
function getStanzaId(messages, msgType, InquotedType, deepQuotedType) {
return messages.message?.[msgType]?.contextInfo?.stanzaId ||
normalizeMessageContent(
normalizeMessageContent(
messages.message?.[InquotedType]?.message?.[deepQuotedType]?.contextInfo?.stanzaId
)
);
}
const quoted = getQuotedMessage(messages, msg.type, InquotedType, deepQuotedType);
if (quoted) {
const quotedMessage = normalizeMessageContent(quoted);
const quotedType = getContentType(quotedMessage);
const stanzaId = getStanzaId(messages, msg.type, InquotedType, deepQuotedType);

Copy link
Owner Author

Choose a reason for hiding this comment

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

Nice

Copy link

Choose a reason for hiding this comment

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

@AstroX11 Great! Feel free to implement the suggested changes to improve the code's readability. Let me know if you need any further assistance.

Necessary fix

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@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: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52e3a53 and b37bc72.

📒 Files selected for processing (1)
  • lib/events.js (1 hunks)
🔇 Additional comments (2)
lib/events.js (2)

23-23: Function call update looks good

The update to updateGroupMetadata(msg.client) reflects the change in the function's signature and uses the appropriate argument.


18-24: ⚠️ Potential issue

Critical Issue: Functions executed before conditional checks leading to unintended side effects

The functions StickerCMD(msg), AntiDelete(msg), AntiViewOnce(msg), AntiSpammer(msg), and updateGroupMetadata(msg.client) are being invoked immediately when pushed into the tasks array. If any of these functions have side effects or consume resources, they will execute even if the subsequent conditional checks cause an early return from the upserts function. This can lead to unintended behavior and performance issues.

Apply this diff to move the function calls after the conditional checks:

 export async function upserts(msg) {
   const tasks = [];
   const config = await getConfig();
+  if (!msg.isGroup) {
+    if (config.disabledm && msg.from !== msg.user) return;
+  }
+  if (msg.isGroup) {
+    if (isJidGroup(msg.from) && config.disablegc) return;
+  }
   tasks.push(
     StickerCMD(msg),
     AntiDelete(msg),
     AntiViewOnce(msg),
     AntiSpammer(msg),
     updateGroupMetadata(msg.client)
   );

Likely invalid or redundant comment.

Comment on lines +28 to +29
if (msg.isGroup) {
if (isJidGroup(msg.from) && config.disablegc) return;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Suggestion: Simplify redundant condition in group check

Inside the if (msg.isGroup) block, the condition isJidGroup(msg.from) may be redundant because msg.isGroup is already true. Unless there are specific cases where msg.isGroup is true but isJidGroup(msg.from) is false, consider removing isJidGroup(msg.from) to simplify the condition.

Apply this diff to simplify the condition:

   if (msg.isGroup) {
-    if (isJidGroup(msg.from) && config.disablegc) return;
+    if (config.disablegc) return;
     tasks.push(Antilink(msg), schedules(msg), AntiWord(msg), AutoKick(msg));
   }
📝 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
if (msg.isGroup) {
if (isJidGroup(msg.from) && config.disablegc) return;
if (msg.isGroup) {
if (config.disablegc) return;

Copy link

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b37bc72 and ba6d2d2.

⛔ Files ignored due to path filters (4)
  • media/intro.mp4 is excluded by !**/*.mp4
  • media/logo.jpg is excluded by !**/*.jpg
  • media/thumb.jpg is excluded by !**/*.jpg
  • media/xstro.jpg is excluded by !**/*.jpg
📒 Files selected for processing (4)
  • bot/antidelete.js (1 hunks)
  • lib/client.js (1 hunks)
  • lib/message.js (1 hunks)
  • lib/plugins.js (1 hunks)
🧰 Additional context used
📓 Learnings (2)
lib/message.js (1)
Learnt from: AstroX11
PR: AstroX11/Xstro#17
File: lib/message.js:21-25
Timestamp: 2025-01-18T20:27:57.036Z
Learning: In the message serialization logic of Xstro, the sender property should be defined inline within the msg object using ternary operations, rather than being extracted to a separate helper function, to maintain the codebase's design pattern.
bot/antidelete.js (1)
Learnt from: AstroX11
PR: AstroX11/Xstro#17
File: bot/antidelete.js:7-11
Timestamp: 2025-01-18T20:25:38.168Z
Learning: Debug comments and commented-out code checks in the codebase should be preserved as they may serve as debugging checkpoints or document message flow.
🪛 Biome (1.9.4)
lib/client.js

[error] 11-11: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 100-100: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 58-58: Reassigning a function parameter is confusing.

The parameter is declared here:

Use a local variable instead.

(lint/style/noParameterAssign)

🔇 Additional comments (8)
lib/client.js (2)

11-11: Use 'node:' protocol when importing Node.js built-in modules

The events module is a Node.js built-in module. Importing it with the node: protocol explicitly indicates that it's a core module.

- import { EventEmitter } from 'events';
+ import { EventEmitter } from 'node:events';
🧰 Tools
🪛 Biome (1.9.4)

[error] 11-11: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


33-33: Verify proxy configuration reliability

The proxy configuration is dynamically fetched for each socket creation. This could potentially cause connection issues if the proxy service is unreliable.

Consider implementing a fallback mechanism or caching the proxy configuration:

- agent: new ProxyAgent(`http://${await proxy()}`),
+ const proxyUrl = await proxy();
+ agent: proxyUrl ? new ProxyAgent(`http://${proxyUrl}`) : undefined,
bot/antidelete.js (2)

5-11: Well-structured guard clauses!

The early return conditions are clear and effectively prevent unnecessary processing.


13-20: 🧹 Nitpick (assertive)

Optimize variable declarations.

The variables client and store are intermediary and could be removed. Consider destructuring directly:

-  const client = msg.client;
-  const messageId = msg?.message?.protocolMessage?.key.id;
-  const store = await client.loadMessage(messageId);
-  const sender = store.message.sender;
-  const deleted = msg?.sender;
-  const time = formatTime(Date.now());
-  const message = store.message.message;
-  const chat = msg.isGroup ? msg.from : msg.user;
+  const messageId = msg?.message?.protocolMessage?.key.id;
+  const store = await msg.client.loadMessage(messageId);
+  const { sender, message: { message } } = store;
+  const deleted = msg?.sender;
+  const time = formatTime(Date.now());
+  const chat = msg.isGroup ? msg.from : msg.user;

Likely invalid or redundant comment.

lib/plugins.js (1)

6-12: Clean command setup implementation!

The command pattern and property initialization is well-structured.

lib/message.js (3)

10-14: Well-structured sender determination logic!

The inline ternary operations for sender determination maintain the codebase's design pattern.


36-41: 🛠️ Refactor suggestion

Add error handling for group metadata fetch.

The group metadata fetch could fail if the group doesn't exist or if there are network issues. Consider adding a try-catch block:

 if (isGroup) {
+  try {
     const metadata = await conn.groupMetadata(remoteJid);
     const participant = messages.key.participant;
     msg.isAdmin = !!metadata.participants.find((p) => p.id === participant)?.admin || false;
     msg.isBotAdmin = !!metadata.participants.find((p) => p.id === owner)?.admin || false;
+  } catch (error) {
+    console.error('Failed to fetch group metadata:', error);
+    msg.isAdmin = false;
+    msg.isBotAdmin = false;
+  }
 }

Likely invalid or redundant comment.


143-143: 🧹 Nitpick (assertive)

Improve command name extraction reliability.

The current regex pattern split might be fragile. Consider adding a fallback for command name extraction:

-      const name = cmd.pattern.toString().split(/\W+/)[1] || 'UNKNOWN CMD';
+      const name = extractCommandName(cmd.pattern);
+
+function extractCommandName(pattern) {
+  try {
+    const matches = pattern.toString().match(/\w+/g);
+    return matches?.[1] || 'UNKNOWN CMD';
+  } catch {
+    return 'UNKNOWN CMD';
+  }
+}

Likely invalid or redundant comment.

lib/client.js Show resolved Hide resolved
lib/client.js Show resolved Hide resolved
const { autoRead, autoStatusRead, autolikestatus } = await getConfig();

for (const message of messages) {
const msg = await serialize(JSON.parse(JSON.stringify(message, null, 2)), conn);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Optimize message serialization performance

The current implementation uses JSON.parse(JSON.stringify()) for deep cloning, which can be inefficient for large messages.

Consider using the imported deepClone utility instead:

- const msg = await serialize(JSON.parse(JSON.stringify(message, null, 2)), conn);
+ const msg = await serialize(deepClone(message), conn);

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

}
}
};
import { getAntiDelete } from '#sql';
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Update import alias to reflect JSON storage.

The import alias #sql is misleading since the project has transitioned from SQL to JSON storage. Consider updating the alias to better reflect its current implementation (e.g., #config or #storage).

Comment on lines +32 to +34
const groupInfo = msg.isGroup
? `*ɢʀᴏᴜᴘ:* ${(await client.groupMetadata(msg.from)).subject}\n`
: '';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for group metadata fetch.

The group metadata fetch could fail if the group doesn't exist or if there are network issues. Consider adding a try-catch block:

-    const groupInfo = msg.isGroup
-      ? `*ɢʀᴏᴜᴘ:* ${(await client.groupMetadata(msg.from)).subject}\n`
-      : '';
+    let groupInfo = '';
+    if (msg.isGroup) {
+      try {
+        const metadata = await client.groupMetadata(msg.from);
+        groupInfo = `*ɢʀᴏᴜᴘ:* ${metadata.subject}\n`;
+      } catch (error) {
+        console.error('Failed to fetch group metadata:', error);
+      }
+    }
📝 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 groupInfo = msg.isGroup
? `*ɢʀᴏᴜᴘ:* ${(await client.groupMetadata(msg.from)).subject}\n`
: '';
let groupInfo = '';
if (msg.isGroup) {
try {
const metadata = await client.groupMetadata(msg.from);
groupInfo = `*ɢʀᴏᴜᴘ:* ${metadata.subject}\n`;
} catch (error) {
console.error('Failed to fetch group metadata:', error);
}
}

lib/plugins.js Show resolved Hide resolved
lib/plugins.js Show resolved Hide resolved
lib/message.js Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant