code cleanups and performance optimization.#147
Conversation
📝 WalkthroughWalkthroughThis PR removes multiple WAPI serialize helpers, introduces findChat/getMeUser, replaces many sendExist/getMaybeMe calls with those helpers, adds a debounced message queue (_queueNewMessage) for listeners, and adds Vitest unit tests and test utilities. Changes
Sequence Diagram(s)sequenceDiagram
participant Listener as Client (on add)
participant WAPI as window.WAPI
participant Queue as _newMessagesQueue
participant Debouncer as Debouncer (1000ms)
participant Callbacks as _newMessagesCallbacks
Listener->>WAPI: process new message -> processMessageObj
alt processMessageObj falsy
WAPI-->>Listener: return early
else
WAPI->>Listener: dispatch onAnyMessage immediately
alt message not from me
Listener->>WAPI: _queueNewMessage(processedMessage)
WAPI->>Queue: push message to buffers
alt debouncer inactive
WAPI->>Debouncer: setTimeout(1000ms)
end
end
end
Debouncer->>Queue: timeout fires
Queue->>Callbacks: invoke each callback with queuedMessages
Callbacks->>Listener: callback(queuedMessages) -> triggers onMessage handlers
Callbacks->>WAPI: remove callbacks flagged rmAfterUse
WAPI->>Queue: clear _newMessagesQueue/_newMessagesBuffer and debouncer
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/lib/wapi/serializers/serialize-message.js`:
- Around line 6-16: isGroupMsg detects group messages using obj?.to?.server and
obj?.from?.server but groupInfo always uses obj.from._serialized; update the
retrieval to use the group ID depending on which side is the group (prefer
obj.to._serialized when obj.to.server === 'g.us', otherwise
obj.from._serialized) before calling window.Store.Chat.get and
WAPI._serializeContactObj; adjust the conditional that checks for a serialized
id to use this resolved groupId variable so outgoing group messages fetch the
correct group chat/contact info.
- Around line 63-64: The latitude/longitude assignments use the `|| undefined`
pattern which wrongly treats 0 as absent; change the `lat: obj?.lat ||
undefined` and `lng: obj?.lng || undefined` lines to use nullish coalescing so
that only null/undefined become undefined (e.g., `obj?.lat ?? undefined` and
`obj?.lng ?? undefined`) in the serialize logic in serialize-message.js.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
dist/lib/wapi/wapi.jsis excluded by!**/dist/**
📒 Files selected for processing (8)
src/lib/wapi/serialize/index.jssrc/lib/wapi/serialize/serialize-chat.jssrc/lib/wapi/serialize/serialize-contact.jssrc/lib/wapi/serialize/serialize-message.jssrc/lib/wapi/serialize/serialize-profile-pic-thumb.jssrc/lib/wapi/serialize/serialize-raw.jssrc/lib/wapi/serialize/serielize-me.jssrc/lib/wapi/serializers/serialize-message.js
💤 Files with no reviewable changes (7)
- src/lib/wapi/serialize/serialize-contact.js
- src/lib/wapi/serialize/index.js
- src/lib/wapi/serialize/serialize-profile-pic-thumb.js
- src/lib/wapi/serialize/serialize-raw.js
- src/lib/wapi/serialize/serialize-chat.js
- src/lib/wapi/serialize/serialize-message.js
- src/lib/wapi/serialize/serielize-me.js
🧰 Additional context used
📓 Path-based instructions (1)
src/lib/wapi/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI layer code is built with webpack and injected into the Puppeteer browser context
Files:
src/lib/wapi/serializers/serialize-message.js
🔇 Additional comments (1)
src/lib/wapi/serializers/serialize-message.js (1)
22-25: LGTM!Using
|| undefinedfor these serialized string IDs is appropriate—empty or falsy values aren't meaningful for these fields.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/api/layers/listener.layer.ts`:
- Around line 173-180: Guard against processMessageObj being undefined before
dispatch: after computing processMessageObj (from processMessageObj(...) or
similar), check it is truthy and only then call
window.onAnyMessage(processMessageObj) and
window.WAPI._queueNewMessage(processMessageObj) (retain existing isSentByMe
check for _queueNewMessage). This ensures you don't pass undefined to
onAnyMessage and only queue valid message objects.
In `@src/lib/wapi/listeners/init-listeners.js`:
- Around line 15-19: The debounce handler currently captures queuedMessages then
clears window.WAPI._newMessagesQueue, which can lose messages pushed
concurrently; fix by atomically swapping the queue: assign a new empty array to
window.WAPI._newMessagesQueue first (e.g., const queuedMessages =
window.WAPI._newMessagesQueue; window.WAPI._newMessagesQueue = []; OR better:
const queuedMessages = window.WAPI._newMessagesQueue.splice(0);), then process
queuedMessages, and only after processing set window.WAPI._newMessagesDebouncer
= null; ensure this change references window.WAPI._newMessagesDebouncer,
window.WAPI._newMessagesQueue, and the _queueNewMessage callers so no messages
are dropped.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
dist/lib/wapi/wapi.jsis excluded by!**/dist/**
📒 Files selected for processing (3)
src/api/layers/listener.layer.tssrc/lib/wapi/listeners/init-listeners.jssrc/types/WAPI.d.ts
🧰 Additional context used
📓 Path-based instructions (2)
src/api/layers/*.layer.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Keep functionality layers in src/api/layers using the *.layer.ts naming (e.g., sender.layer.ts, listener.layer.ts, group.layer.ts, profile.layer.ts, controls.layer.ts, retriever.layer.ts)
Files:
src/api/layers/listener.layer.ts
src/lib/wapi/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI layer code is built with webpack and injected into the Puppeteer browser context
Files:
src/lib/wapi/listeners/init-listeners.js
🧠 Learnings (1)
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/api/layers/*.layer.ts : Keep functionality layers in src/api/layers using the *.layer.ts naming (e.g., sender.layer.ts, listener.layer.ts, group.layer.ts, profile.layer.ts, controls.layer.ts, retriever.layer.ts)
Applied to files:
src/api/layers/listener.layer.ts
🧬 Code graph analysis (2)
src/api/layers/listener.layer.ts (1)
src/lib/wapi/functions/process-message-object.js (1)
processMessageObj(1-16)
src/lib/wapi/listeners/init-listeners.js (6)
src/lib/wapi/functions/sendMessageOptions.js (1)
message(105-121)src/lib/wapi/functions/send-message-scope.js (2)
message(116-125)message(148-159)src/lib/wapi/functions/get-unread-messages-in-chat.js (1)
message(33-37)src/lib/wapi/functions/get-unread-messages.js (1)
message(14-14)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
message(22-26)src/lib/wapi/functions/get-data-messages.js (1)
message(96-96)
🔇 Additional comments (4)
src/lib/wapi/listeners/init-listeners.js (1)
1-40: LGTM on the debounce structure and callback handling.The guard for null/undefined messages, the debounce pattern, and the callback removal logic are well-implemented. The dual-queue approach (queue for processing, buffer for persistence) aligns with the existing
_unloadInformflow.src/types/WAPI.d.ts (1)
271-271: LGTM on the type declaration.The
_queueNewMessagesignature correctly matches the implementation. The underscore prefix appropriately signals this as an internal API.src/api/layers/listener.layer.ts (2)
163-183: Good implementation of dual-path message handling.The separation of concerns is clear:
onAnyMessage: immediate notification for all messages (including sent-by-me)onMessage(via debounced queue): batched incoming messages onlyThe comment at line 163 effectively documents this architecture.
119-123: Clarify the dual-message-path design and verify intended behavior.Two separate paths feed messages into
onMessagehandlers:
window.WAPI.waitNewMessages(lines 119-123) — WAPI listener- Store.Msg 'add' event →
window.WAPI._queueNewMessage(line 179) — internal debounced pathBoth ultimately invoke
window.onMessage, which emits theonMessageevent. ThemessageCachededuplication (lines 386-388) prevents duplicate user callbacks for identical messages (byfromandid), but confirm whether this dual-path design is intentional or if one path should be disabled to avoid redundant processing.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
|
@coderabbitai, please review |
|
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/lib/wapi/listeners/init-listeners.js`:
- Around line 4-8: The _newMessagesBuffer is unbounded—modify
window.WAPI._queueNewMessage (and the corresponding message-processing routine
that clears _newMessagesQueue) so the buffer is bounded: after pushing to
window.WAPI._newMessagesBuffer enforce a maximum size (e.g., MAX_BUFFER_LENGTH)
and drop oldest entries (shift) when exceeded, or alternatively remove messages
from window.WAPI._newMessagesBuffer when they are successfully processed by the
existing consumer that clears window.WAPI._newMessagesQueue; reference
_queueNewMessage, window.WAPI._newMessagesBuffer, and the
message-processing/flush callback to implement the trimming or removal logic.
- Around line 23-30: Wrap each invocation of callbackObj.callback inside a
try-catch so one throwing callback doesn't stop the forEach, ensuring you still
evaluate callbackObj.rmAfterUse and push to removeCallbacks even if the callback
throws; use the catch to log or swallow the error (including callback
identity/context) and continue so removeCallbacks is fully populated and
subsequent callbacks run.
🧹 Nitpick comments (2)
src/lib/wapi/functions/check-send-exist.js (2)
146-179: Extract duplicated error handling into a helper function.The error handling logic in
returnChat(lines 146-179) andsendExist(lines 276-309) is nearly identical. Consider extracting this into a shared helper to improve maintainability and reduce duplication.♻️ Proposed refactor
+async function handleSendSeenError(e, chatId, chat, context) { + const errorInfo = { + message: e?.message, + stack: e?.stack, + undefinedProp: e?.message?.match(/Cannot read properties of undefined \(reading '(.+)'\)/)?.[1], + chatId: chatId, + chatExists: !!chat, + chatKeys: chat ? Object.keys(chat).slice(0, 30) : [], + chatProto: chat ? Object.getOwnPropertyNames(Object.getPrototypeOf(chat)).slice(0, 20) : [] + }; + window.onLog(`sendSeen failed in ${context}: ` + JSON.stringify(errorInfo)); + + try { + const stackMatch = e?.stack?.match(/(https:\/\/static\.whatsapp\.net\/[^\s:]+):(\d+):(\d+)/); + if (stackMatch) { + const [, url, line, col] = stackMatch; + const response = await fetch(url); + const source = await response.text(); + const lineNum = parseInt(line, 10); + const colNum = parseInt(col, 10); + const lines = source.split('\n'); + const targetLine = lines[lineNum - 1] || ''; + const start = Math.max(0, colNum - 50); + const snippet = targetLine.substring(start, start + 100); + window.onLog('WA source context: ' + JSON.stringify({ url, line, col, snippet })); + } + } catch (srcErr) { + // Ignore source fetch errors + } +}Then in
returnChat:if (Send) { try { await window.Store.ReadSeen.sendSeen(chat, false); } catch (e) { - const errorInfo = { ... }; - // ... all the error handling code + await handleSendSeenError(e, chatId, chat, 'returnChat'); } }And similarly in
sendExist.Also applies to: 276-309
161-178: Consider adding a timeout for the source fetch.Fetching WhatsApp's minified JS bundles (which can be several MB) on every error without a timeout could cause delays. Consider using
AbortControllerwith a reasonable timeout to prevent hanging on slow or failed network requests.♻️ Suggested improvement
if (stackMatch) { const [, url, line, col] = stackMatch; - const response = await fetch(url); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 3000); + const response = await fetch(url, { signal: controller.signal }); + clearTimeout(timeoutId); const source = await response.text();
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
dist/cjs/api/layers/listener.layer.jsis excluded by!**/dist/**dist/cjs/api/layers/listener.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/esm/api/layers/listener.layer.jsis excluded by!**/dist/**dist/esm/api/layers/listener.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/lib/wapi/wapi.jsis excluded by!**/dist/**
📒 Files selected for processing (3)
src/api/layers/listener.layer.tssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/listeners/init-listeners.js
🚧 Files skipped from review as they are similar to previous changes (1)
- src/api/layers/listener.layer.ts
🧰 Additional context used
📓 Path-based instructions (2)
src/lib/wapi/functions/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run
npm run build:wapito rebuild
Files:
src/lib/wapi/functions/check-send-exist.js
src/lib/wapi/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI layer code is built with webpack and injected into the Puppeteer browser context
Files:
src/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/listeners/init-listeners.js
🧬 Code graph analysis (1)
src/lib/wapi/listeners/init-listeners.js (6)
src/lib/wapi/functions/sendMessageOptions.js (1)
message(105-121)src/lib/wapi/functions/send-message-scope.js (2)
message(116-125)message(148-159)src/lib/wapi/functions/get-unread-messages-in-chat.js (1)
message(33-37)src/lib/wapi/functions/get-unread-messages.js (1)
message(14-14)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
message(22-26)src/lib/wapi/functions/get-data-messages.js (1)
message(96-96)
🔇 Additional comments (3)
src/lib/wapi/functions/check-send-exist.js (1)
146-148: Good addition of error handling forsendSeen.Wrapping
sendSeenin try-catch ensures that failures in this non-critical "mark as seen" operation don't break the main chat retrieval flow. The detailed error logging will help diagnose issues with WhatsApp API changes.src/lib/wapi/listeners/init-listeners.js (2)
16-19: Race condition fix looks correct.The atomic swap pattern (capture queue reference, then immediately reassign to empty array) properly addresses the previously identified race condition. Messages arriving during callback processing will be queued for the next debounce cycle.
42-64: LGTM!The
_unloadInformhandler correctly persists buffered messages and notifies callbacks of the page reload. This integrates well with the new queueing mechanism.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| window.WAPI._queueNewMessage = function (message) { | ||
| if (!message) return; | ||
|
|
||
| window.WAPI._newMessagesDebouncer = null; | ||
| window.WAPI._newMessagesQueue = []; | ||
| window.WAPI._newMessagesQueue.push(message); | ||
| window.WAPI._newMessagesBuffer.push(message); |
There was a problem hiding this comment.
_newMessagesBuffer grows unboundedly during the session.
Messages are pushed to _newMessagesBuffer but never removed. While _newMessagesQueue is cleared after processing, the buffer accumulates all messages until page unload (when it's persisted to sessionStorage). In long-running sessions with high message volume, this could cause memory pressure.
Consider periodically trimming or capping the buffer size, or clearing processed messages from the buffer after successful callback execution.
🤖 Prompt for AI Agents
In `@src/lib/wapi/listeners/init-listeners.js` around lines 4 - 8, The
_newMessagesBuffer is unbounded—modify window.WAPI._queueNewMessage (and the
corresponding message-processing routine that clears _newMessagesQueue) so the
buffer is bounded: after pushing to window.WAPI._newMessagesBuffer enforce a
maximum size (e.g., MAX_BUFFER_LENGTH) and drop oldest entries (shift) when
exceeded, or alternatively remove messages from window.WAPI._newMessagesBuffer
when they are successfully processed by the existing consumer that clears
window.WAPI._newMessagesQueue; reference _queueNewMessage,
window.WAPI._newMessagesBuffer, and the message-processing/flush callback to
implement the trimming or removal logic.
| window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) { | ||
| if (callbackObj.callback !== undefined) { | ||
| callbackObj.callback(queuedMessages); | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| }); | ||
| if (callbackObj.rmAfterUse === true) { | ||
| removeCallbacks.push(callbackObj); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Missing error handling: one throwing callback breaks all subsequent callbacks.
If any callback throws an exception at line 25, the forEach loop terminates early. This means:
- Remaining callbacks won't execute
removeCallbackswon't be fully populated- Cleanup for
rmAfterUsecallbacks may be incomplete
Wrap each callback invocation in a try-catch to isolate failures.
🔧 Proposed fix to isolate callback failures
window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) {
if (callbackObj.callback !== undefined) {
- callbackObj.callback(queuedMessages);
+ try {
+ callbackObj.callback(queuedMessages);
+ } catch (err) {
+ console.error('Error in newMessagesCallback:', err);
+ }
}
if (callbackObj.rmAfterUse === true) {
removeCallbacks.push(callbackObj);
}
});📝 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.
| window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) { | |
| if (callbackObj.callback !== undefined) { | |
| callbackObj.callback(queuedMessages); | |
| } | |
| } | |
| } | |
| ); | |
| }); | |
| if (callbackObj.rmAfterUse === true) { | |
| removeCallbacks.push(callbackObj); | |
| } | |
| }); | |
| window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) { | |
| if (callbackObj.callback !== undefined) { | |
| try { | |
| callbackObj.callback(queuedMessages); | |
| } catch (err) { | |
| console.error('Error in newMessagesCallback:', err); | |
| } | |
| } | |
| if (callbackObj.rmAfterUse === true) { | |
| removeCallbacks.push(callbackObj); | |
| } | |
| }); |
🤖 Prompt for AI Agents
In `@src/lib/wapi/listeners/init-listeners.js` around lines 23 - 30, Wrap each
invocation of callbackObj.callback inside a try-catch so one throwing callback
doesn't stop the forEach, ensuring you still evaluate callbackObj.rmAfterUse and
push to removeCallbacks even if the callback throws; use the catch to log or
swallow the error (including callback identity/context) and continue so
removeCallbacks is fully populated and subsequent callbacks run.
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
package.json (1)
93-118: Add explicit Node.js version requirement to package.json.Vitest 3.x requires Node.js 18 or newer. The project should declare this minimum requirement using an
"engines"field in package.json to prevent installation on incompatible Node versions. Add the following to clarify the supported runtime environment before release.
🤖 Fix all issues with AI agents
In `@coverage/api/helpers/deduplication-cache.ts.html`:
- Around line 1-415: The repo is tracking generated coverage HTML under
coverage/ (e.g., coverage/api/helpers/deduplication-cache.ts.html); add
coverage/ to .gitignore, remove the tracked coverage files from Git, and commit
the change. Specifically: add the line "coverage/" to .gitignore, run git rm
--cached -r coverage (or use your history-rewrite tool like git filter-repo/BFG
if you need to purge older commits), and commit & push the removal; this will
stop files like the generated deduplication-cache.ts.html from being committed
alongside code and keep classes like DeduplicationCache and exported alias
callbackWile out of versioned coverage artifacts.
In `@coverage/api/helpers/index.ts.html`:
- Around line 1-127: Add "coverage/" to the repository .gitignore and stop
tracking the already committed coverage artifacts (the files under coverage/,
e.g., coverage/api/helpers/index.ts.html) by running git rm -r --cached coverage
and committing that change so the directory is removed from history going
forward; after that, ensure CI is configured to generate/publish coverage as
build artifacts or push to a coverage service (e.g., Codecov/Coveralls) instead
of committing coverage output.
In `@coverage/api/helpers/layers-interface.ts.html`:
- Around line 145-162: The validation loop uses `for (let i in data)` which
yields string keys so the `typeof i == 'number'` check always fails and
validation never runs; replace the loop with a numeric index loop (e.g., `for
(let i = 0; i < data.length; i++)`) or a `for (const [i, item] of
data.entries())` pattern so `i` is a numeric index (or use `for (const item of
data)` and refer to `item`), then keep the existing logic that computes `result`
using `infoType(data[i].value, data[i].type)` (or `infoType(item.value,
item.type)`) and return the same error object when `!result`.
In `@coverage/api/helpers/scrape-deletetoken.ts.html`:
- Around line 110-122: The function scrapeDeleteToken has a type mismatch
because .catch(() => undefined) allows returning undefined despite the
Promise<boolean> signature; change the error path to return a boolean (e.g.,
replace .catch(() => undefined) with .catch(() => false)) and ensure the
page.evaluate callback always returns a boolean, or alternatively relax the
signature to Promise<boolean | undefined> if undefined is intended; also remove
the generated coverage artifact file from the commit so the coverage HTML isn't
included in source.
In `@coverage/base.css`:
- Around line 52-55: The .quiet class contains two duplicate color declarations;
remove the redundant one so only a single modern value remains (e.g., keep
color: rgba(0,0,0,0.5); and delete color: `#7f7f7f`;), or if you need the hex
fallback move the hex into an `@supports-compatible` fallback block and leave the
rgba as the primary value in the .quiet rule.
- Around line 5-8: The font-family declaration in the body selector uses an
unquoted multi-word family name; update the body { font-family: ... } rule to
quote "Helvetica Neue" (e.g., "Helvetica Neue", Helvetica, Arial) so the
multi-word family is treated as a single font family and to avoid duplicate-name
lint warnings.
- Around line 216-220: Remove the duplicate height declaration in the .wrapper
rule: delete the redundant "height: 100%;" line (leaving min-height and the
legacy "height: auto !important;" only) so there is a single, intentional height
declaration and the lint error is resolved.
In `@coverage/block-navigation.js`:
- Around line 24-38: The toggleClass/makeCurrent logic assumes
missingCoverageElements.item(...) returns an element; guard against empty lists
by checking missingCoverageElements.length and that currentIndex is not
null/undefined before accessing .classList; only call
missingCoverageElements.item(currentIndex).classList.remove(...) when
missingCoverageElements.length > 0 and currentIndex is a valid index, and
likewise ensure missingCoverageElements.item(index) exists before calling
.classList.add(...) and scrollIntoView in makeCurrent.
In `@coverage/prettify.js`:
- Around line 1-2: Summary: Biome is linting generated vendor file
coverage/prettify.js and raising noUselessUndefinedInitialization; exclude the
coverage/ directory in biome.json. Fix: open biome.json and add "coverage/**"
(or "coverage/") to the "exclude" array (or create an "exclude" array if
missing) so Biome ignores the generated files; ensure the pattern covers nested
files (use glob "**") and commit the change. Reference: the lint rule name
noUselessUndefinedInitialization and the generated file coverage/prettify.js to
verify the exclusion works.
In `@test/unit/wapi/send-message.test.ts`:
- Around line 189-202: The test and source contain a typo in the error string —
update the error message in the sendMessage implementation (function
sendMessage) from "Error to gerate newId" to "Error to generate newId" and then
update the unit test expectation in send-message.test.ts to expect 'Error to
generate newId' so both implementation and test match; ensure no other
occurrences of "gerate" remain.
♻️ Duplicate comments (7)
coverage/utils/sleep.ts.html (1)
2-88: Duplicate: generated coverage artifacts.Same note as earlier about keeping
coverage/out of version control unless you intentionally publish reports in-repo.coverage/api/helpers/delete-file.ts.html (1)
2-151: Duplicate: generated coverage artifacts.Same note as earlier about keeping
coverage/out of version control unless you intentionally publish reports in-repo.coverage/api/helpers/scrape-img-qr.ts.html (1)
1-22: Duplicate: generated coverage artifact.Same suggestion as other coverage HTML files—consider excluding
coverage/from VCS unless intentionally versioned.coverage/api/helpers/sleep.ts.html (1)
1-22: Duplicate: generated coverage artifact.Same suggestion as other coverage HTML files—consider excluding
coverage/from VCS unless intentionally versioned.coverage/utils/qr-generator.ts.html (1)
1-436: Skip - duplicate of coverage directory concern.Same issue as
coverage/api/helpers/index.ts.html- this is a generated coverage artifact that should not be committed.coverage/utils/semver.ts.html (1)
2-169: Generated coverage artifact (see prior note).
Same repo-hygiene recommendation as incoverage/utils/index.html.coverage/utils/logger.ts.html (1)
2-214: Generated coverage artifact (see prior note).
Same repo-hygiene recommendation as incoverage/utils/index.html.
🧹 Nitpick comments (12)
coverage/api/helpers/dowload-meta.ts.html (1)
1-322: Exclude generated coverage HTML from source control.This is a generated Istanbul coverage report, which is typically better kept as a CI artifact rather than committed to the repo. Consider adding coverage outputs to
.gitignoreor documenting why these artifacts must be versioned.coverage/api/helpers/layers-interface.ts.html (1)
2-185: Consider excluding generated coverage HTML from the repo.
This file looks like an Istanbul report artifact; committing it can bloat the repo and cause noisy diffs. Prefer generating in CI and publishing as an artifact, and add coverage output to.gitignore.package.json (1)
53-55: Wire unit tests into the default test pipeline.
test:unitis opt‑in, whilenpm test/build:teststill only runtest/index.js. If unit coverage should run in CI, consider chaining the Vitest run into the default path.Suggested tweak (if build:test is the CI entrypoint)
- "build:test": "npm run build && npm test", + "build:test": "npm run build && npm test && npm run test:unit",coverage/api/helpers/base64-mimetype.ts.html (1)
2-112: Avoid committing generated coverage HTML.Coverage reports are typically build artifacts and tend to churn. Consider ignoring
coverage/and publishing reports as CI artifacts instead.Example .gitignore addition
+coverage/coverage/api/helpers/check-token-file.ts.html (1)
1-22: Consider excluding generated coverage artifacts from VCS.This appears to be a generated coverage report; if it’s not intentionally versioned, add the
coverage/directory to.gitignoreand publish reports via CI artifacts to reduce repo churn and size.coverage/api/helpers/download-file.ts.html (1)
191-191: Empty catch block silently swallows errors in the source code.The embedded source reveals that
downloadFileToBase64insrc/api/helpers/download-file.tshas an empty catch block (line 191:} catch (error) {}). This silently swallows all HTTP errors, network failures, and other exceptions without any logging, making debugging difficult.Consider adding error logging in the actual source file:
- } catch (error) {} + } catch (error) { + console.error(`Failed to download file from ${_path}:`, error); + }Also, this is a generated coverage artifact that should not be committed (see earlier comment about adding
coverage/to.gitignore).coverage/api/helpers/select-sticker.ts.html (1)
205-207: Verify animated WebP output for_t === 1.If
_t === 1is meant for animated stickers,sharptypically requireswebp({ animated: true })to preserve frames. Please confirm with the sharp docs.🛠️ Suggested fix
- _w = sharp(_B, { animated: true }).webp(); + _w = sharp(_B, { animated: true }).webp({ animated: true });coverage/api/helpers/force-connect.ts.html (1)
1-295: Confirm generated coverage artifacts are intentional.This appears to be Istanbul HTML output; if it isn’t meant for version control, consider ignoring it or publishing as a build artifact to keep the repo lean.
test/unit/wapi/setup.ts (1)
11-30: Preserve any pre-existingwindow/globals in test setup.Overwriting
global.windowcan drop jsdom APIs and leak across suites; consider merging into an existing window and restoring previous values in cleanup.♻️ Suggested safer setup/cleanup
- // Set up global window object with Store and WAPI - (global as Record<string, unknown>).window = { - Store: storeMock, - WAPI: wapiMock, - onLog: vi.fn() - }; - - // Also expose at global level (some WAPI functions use Store directly) - (global as Record<string, unknown>).Store = storeMock; - (global as Record<string, unknown>).WAPI = wapiMock; - - const cleanup = () => { - delete (global as Record<string, unknown>).window; - delete (global as Record<string, unknown>).Store; - delete (global as Record<string, unknown>).WAPI; - }; + const globalAny = global as Record<string, unknown>; + const prevWindow = globalAny.window; + const prevStore = globalAny.Store; + const prevWapi = globalAny.WAPI; + + const win = + prevWindow && typeof prevWindow === 'object' + ? (prevWindow as Record<string, unknown>) + : {}; + win.Store = storeMock; + win.WAPI = wapiMock; + win.onLog = vi.fn(); + globalAny.window = win; + + // Also expose at global level (some WAPI functions use Store directly) + globalAny.Store = storeMock; + globalAny.WAPI = wapiMock; + + const cleanup = () => { + if (prevWindow === undefined) delete globalAny.window; + else globalAny.window = prevWindow; + if (prevStore === undefined) delete globalAny.Store; + else globalAny.Store = prevStore; + if (prevWapi === undefined) delete globalAny.WAPI; + else globalAny.WAPI = prevWapi; + };test/unit/wapi/get-all-chats.test.ts (1)
1-4: Import structure looks good, butviimport is missing here.The
viimport is needed on line 41 forvi.fn(), but it's imported at the bottom of the file (lines 91-92). While this works due to hoisting, it's unconventional and reduces readability.♻️ Proposed fix: move vi import to top
-import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { setupWapiTestEnv, type WapiTestEnv } from './setup.js'; import { createChatMock } from './mocks/store-mock.js'; import { getAllChats } from '../../../src/lib/wapi/functions/get-all-chats.js';And remove lines 91-92:
- -// Need to import vi for the doneFn mock -import { vi } from 'vitest';test/unit/helpers/deduplication-cache.test.ts (1)
115-125: Consider adding a test for the cleanup timer invocation.The coverage report shows
removeExpired()(the timer callback) is not covered. While TTL expiration is tested viaget()andhas(), consider adding a test that advances time pastCLEANUP_INTERVAL_MS(60 seconds) to trigger the background cleanup and verify entries are removed.💡 Suggested test for timer-based cleanup
it('should remove expired entries via background cleanup timer', () => { const ttlMs = 1000; cache = new DeduplicationCache(ttlMs); cache.add('msg1', 'serialized-content-1'); // Advance past TTL vi.advanceTimersByTime(ttlMs + 100); // Advance past cleanup interval (60 seconds) to trigger removeExpired vi.advanceTimersByTime(60 * 1000); // Entry should be removed by the cleanup timer expect(cache.get('serialized-content-1')).toBeUndefined(); });coverage/utils/index.html (1)
2-160: Consider excluding generated coverage artifacts from version control.
These HTML reports (with timestamps) add repo noise and churn; prefer generating in CI and ignoringcoverage/.♻️ Suggested .gitignore entry
+coverage/
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
coverage/favicon.pngis excluded by!**/*.pngcoverage/sort-arrow-sprite.pngis excluded by!**/*.pngpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (45)
coverage/api/helpers/base64-mimetype.ts.htmlcoverage/api/helpers/check-token-file.ts.htmlcoverage/api/helpers/closes-browser.ts.htmlcoverage/api/helpers/decrypt.ts.htmlcoverage/api/helpers/deduplication-cache.ts.htmlcoverage/api/helpers/delete-file.ts.htmlcoverage/api/helpers/dowload-meta.ts.htmlcoverage/api/helpers/download-file.ts.htmlcoverage/api/helpers/exposed.enum.ts.htmlcoverage/api/helpers/file-to-base64.ts.htmlcoverage/api/helpers/filename-from-mimetype.ts.htmlcoverage/api/helpers/force-connect.ts.htmlcoverage/api/helpers/index.htmlcoverage/api/helpers/index.ts.htmlcoverage/api/helpers/layers-interface.ts.htmlcoverage/api/helpers/scrape-deletetoken.ts.htmlcoverage/api/helpers/scrape-desconnect.ts.htmlcoverage/api/helpers/scrape-img-qr.ts.htmlcoverage/api/helpers/scrape-login.ts.htmlcoverage/api/helpers/select-sticker.ts.htmlcoverage/api/helpers/sleep.ts.htmlcoverage/base.csscoverage/block-navigation.jscoverage/index.htmlcoverage/prettify.csscoverage/prettify.jscoverage/sorter.jscoverage/utils/index.htmlcoverage/utils/logger.ts.htmlcoverage/utils/qr-generator.ts.htmlcoverage/utils/semver.ts.htmlcoverage/utils/sleep.ts.htmlpackage.jsontest/unit/helpers/base64-mimetype.test.tstest/unit/helpers/deduplication-cache.test.tstest/unit/helpers/filename-from-mimetype.test.tstest/unit/utils/logger.test.tstest/unit/utils/semver.test.tstest/unit/wapi/check-chat.test.tstest/unit/wapi/get-all-chats.test.tstest/unit/wapi/mocks/store-mock.tstest/unit/wapi/mocks/wapi-mock.tstest/unit/wapi/send-message.test.tstest/unit/wapi/setup.tsvitest.config.ts
✅ Files skipped from review due to trivial changes (8)
- coverage/index.html
- coverage/prettify.css
- coverage/api/helpers/exposed.enum.ts.html
- coverage/api/helpers/index.html
- coverage/api/helpers/decrypt.ts.html
- coverage/api/helpers/scrape-login.ts.html
- coverage/api/helpers/scrape-desconnect.ts.html
- coverage/api/helpers/file-to-base64.ts.html
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to test/index.js : Use test/index.js as the main test script; tests are basic scripts without a formal framework
Applied to files:
package.json
📚 Learning: 2025-09-10T17:12:13.000Z
Learnt from: 9cb14c1ec0
Repo: venomlib/venom PR: 65
File: src/api/helpers/delete-file.ts:3-8
Timestamp: 2025-09-10T17:12:13.000Z
Learning: The venom project build system does not support or prefers not to use Node built-in specifiers (node:path, node:fs) and has specific import pattern requirements that differ from modern Node.js conventions.
Applied to files:
package.json
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to tsconfig.json : TypeScript must target ESNext with CommonJS modules, output to ./dist, and generate declaration files and source maps
Applied to files:
package.json
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/api/helpers/**/*.{ts,js} : Put utility helpers (e.g., encryption, QR code utilities) under src/api/helpers
Applied to files:
coverage/api/helpers/index.ts.htmlcoverage/utils/qr-generator.ts.html
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/lib/wapi/**/*.js : WAPI layer code is built with webpack and injected into the Puppeteer browser context
Applied to files:
test/unit/wapi/setup.ts
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/lib/wapi/functions/**/*.js : WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run `npm run build:wapi` to rebuild
Applied to files:
test/unit/wapi/setup.ts
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/api/layers/*.layer.ts : Keep functionality layers in src/api/layers using the *.layer.ts naming (e.g., sender.layer.ts, listener.layer.ts, group.layer.ts, profile.layer.ts, controls.layer.ts, retriever.layer.ts)
Applied to files:
coverage/api/helpers/layers-interface.ts.html
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/config/**/*.ts : Keep browser/Puppeteer and session management configuration under src/config
Applied to files:
vitest.config.tscoverage/api/helpers/closes-browser.ts.html
🧬 Code graph analysis (10)
test/unit/helpers/base64-mimetype.test.ts (1)
src/api/helpers/file-to-base64.ts (2)
fileToBase64(9-19)Mine(21-27)
test/unit/wapi/get-all-chats.test.ts (3)
test/unit/wapi/setup.ts (2)
WapiTestEnv(5-9)setupWapiTestEnv(11-33)test/unit/wapi/mocks/store-mock.ts (1)
createChatMock(17-28)src/types/WAPI.d.ts (1)
WAPI(14-271)
test/unit/wapi/setup.ts (4)
test/unit/wapi/mocks/store-mock.ts (2)
StoreMock(77-77)createStoreMock(42-75)test/unit/wapi/mocks/wapi-mock.ts (2)
WapiMock(77-77)createWapiMock(11-75)src/types/WAPI.d.ts (2)
Window(274-276)WAPI(14-271)src/lib/wapi/wapi.js (1)
window(534-537)
test/unit/wapi/mocks/store-mock.ts (4)
src/api/model/chat.ts (1)
Chat(5-31)src/types/WAPI.d.ts (1)
WAPI(14-271)src/lib/wapi/store/store-objects.js (6)
module(4-7)module(285-286)module(31-32)module(68-69)module(141-142)module(146-146)src/api/model/message.ts (1)
Message(1-81)
coverage/api/helpers/base64-mimetype.ts.html (2)
src/api/helpers/file-to-base64.ts (2)
fileToBase64(9-19)Mine(21-27)src/api/layers/sender.layer.ts (1)
sendFileFromBase64(856-894)
coverage/utils/qr-generator.ts.html (3)
src/utils/qr-generator.ts (1)
generateASCIIQR(30-117)src/controllers/auth.ts (1)
asciiQr(93-100)vendor/QRCode/index.js (2)
test(232-246)test(248-285)
coverage/api/helpers/layers-interface.ts.html (1)
src/api/helpers/layers-interface.ts (1)
Scope(1-5)
test/unit/wapi/send-message.test.ts (3)
test/unit/wapi/setup.ts (2)
WapiTestEnv(5-9)setupWapiTestEnv(11-33)test/unit/wapi/mocks/store-mock.ts (1)
createChatMock(17-28)src/lib/wapi/serializers/serialize-message.js (1)
groupId(13-16)
test/unit/utils/logger.test.ts (1)
src/utils/logger.ts (7)
LoggerFunction(3-3)setLogger(17-19)getLogger(21-23)logInfo(29-31)logSuccess(33-35)logFail(37-39)logWarn(41-43)
test/unit/wapi/mocks/wapi-mock.ts (1)
src/lib/wapi/functions/get-message-by-id.js (1)
erro(4-4)
🪛 Biome (2.1.2)
coverage/base.css
[error] 6-6: Duplicate font names are redundant and unnecessary: Helvetica
Remove duplicate font names within the property
(lint/suspicious/noDuplicateFontNames)
[error] 54-54: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
color is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
[error] 219-219: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
height is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
coverage/prettify.js
[error] 2-2: 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:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 2-2: 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:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 2-2: Shouldn't redeclare 'ar'. Consider to delete it or rename it.
'ar' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ar'. Consider to delete it or rename it.
'ar' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'at'. Consider to delete it or rename it.
'at' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'am'. Consider to delete it or rename it.
'am' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ag'. Consider to delete it or rename it.
'ag' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'af'. Consider to delete it or rename it.
'af' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'am'. Consider to delete it or rename it.
'am' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ag'. Consider to delete it or rename it.
'ag' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'V'. Consider to delete it or rename it.
'V' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'U'. Consider to delete it or rename it.
'U' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ae'. Consider to delete it or rename it.
'ae' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'Y'. Consider to delete it or rename it.
'Y' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'W'. Consider to delete it or rename it.
'W' is defined here:
(lint/suspicious/noRedeclare)
🔇 Additional comments (40)
vitest.config.ts (1)
1-13: Config looks good; confirm the test glob matches all intended unit tests.
includeis limited totest/unit/**/*.test.ts. If any tests live elsewhere or use.spec.ts, they won't run.test/unit/helpers/base64-mimetype.test.ts (1)
1-41: Solid test coverage forbase64MimeType.Covers valid data URIs, special-character MIME types, invalid inputs, non-strings, and non‑base64 markers.
coverage/api/helpers/filename-from-mimetype.ts.html (1)
1-22: No review comment for this generated report.test/unit/helpers/filename-from-mimetype.test.ts (1)
1-39: LGTM! Comprehensive test coverage for the filename helper.The tests cover important edge cases: matching extensions, mismatched MIME types, missing extensions, unknown MIME types, and special handling for audio/video/WebP formats. The structure follows vitest conventions correctly.
One minor note: Line 32 expects
audio/mpeg→.mpga. While.mpgais technically a valid IANA-registered extension foraudio/mpeg,.mp3is more commonly expected. Verify this matches the actual behavior offilenameFromMimeTypeand is intentional.coverage/api/helpers/closes-browser.ts.html (1)
131-156: The infinite loop is intentional and has proper termination. This function is designed as a background monitoring task (fire-and-forget pattern) that polls every 2 seconds until the browser closes. It will always resolve whenbrowser['isClose']is detected or the browser disconnects, as set up by the close handler at line 218–219 in initializer.ts. The actual call site never awaits this function, only chains.catch()for error handling. AnAbortSignalparameter is unnecessary for this use case.coverage/api/helpers/select-sticker.ts.html (1)
213-227: The claim thatmetadata.pageHeightis undefined for static images is incorrect.Sharp v0.34.0 documentation confirms that
pageHeightis defined for both static and animated images. For static (single-page) images,pageHeightequalsheight. For animated images,pageHeightis the frame height andheightis the total image height. The suggested fallback pattern is therefore unnecessary and based on a misunderstanding of the sharp library's behavior.Likely an incorrect or invalid review comment.
test/unit/wapi/mocks/wapi-mock.ts (1)
3-24: No changes needed. The mock correctly implements the productionscope()function behavior.The production
scope()function incheck-send-exist.jsalways receives and returns a booleanerrovalue. All production calls toWAPI.scope()pass boolean literals (trueorfalse). ThegetMessageById()function returns its own object shape with{ erro: true }directly—it does not pass throughscope(). These are separate code paths, so there is no divergence between the mock and production.The mock's
scopeFncorrectly typeserroasbooleanand returns it asbooleaninScopeResult, matching how it's used throughout the codebase and how tests expect it.Likely an incorrect or invalid review comment.
coverage/sorter.js (9)
10-25: Helper selectors are clean and scoped.Centralizing table lookups keeps DOM queries consistent.
27-56: Filter input handling is robust.Graceful regex fallback avoids runtime errors.
58-64: Search box wiring looks good.
66-89: Column metadata and sort UI setup are solid.Default descending for numeric columns is a nice touch.
92-118: Row data caching is straightforward.Parsing numeric values up front simplifies sorting.
120-149: Sorting and row reattachment logic is correct.Comparator + descending inversion reads clearly.
150-163: Sort indicator toggling is clear.
165-196: UI event wiring is clean.Handler toggles direction and updates indicators as expected.
198-210: Initialization sequence is cohesive.Early table guard avoids unnecessary work.
test/unit/wapi/mocks/store-mock.ts (2)
3-40: Mock interfaces and factories are well-scoped.Defaults plus override hooks make tests ergonomic.
42-77: Store mock surface looks aligned with test usage.Nested namespaces with vi.fn stubs provide good isolation.
test/unit/wapi/setup.ts (1)
5-9: WapiTestEnv interface is clear.test/unit/wapi/send-message.test.ts (3)
1-15: Well-structured test setup with proper isolation.Good use of
beforeEachandafterEachhooks to ensure test isolation. The cleanup pattern prevents global state leakage between tests.
17-52: Comprehensive input validation tests.The input validation tests cover the key edge cases: empty content, non-string content, empty recipient, and non-string recipient. Good use of type casting (
as unknown as string) to test type boundary conditions.
54-81: Status message boundary validation is well-tested.Testing both the 701-character rejection and 700-character acceptance confirms proper boundary handling.
test/unit/wapi/get-all-chats.test.ts (2)
17-67: Good coverage of successful retrieval scenarios.Tests properly validate array length, serialization call count, callback invocation, and empty list handling. The mock patterns are consistent with other test files.
69-88: User authentication edge cases are well-covered.Testing both null user and 404 status ensures the function handles authentication failures gracefully.
test/unit/wapi/check-chat.test.ts (4)
1-15: Clean test setup following established patterns.Consistent with other WAPI test files in the PR. Proper import ordering and test isolation via setup/cleanup.
17-51: Good coverage of valid ID format variations.Tests all three valid chat ID formats: contact (
@c.us), group (@g.us), and broadcast (@broadcast).
53-75: Invalid input handling is properly tested.Tests cover missing suffix, non-string input, and empty string - good boundary validation.
77-114: Chat not found and successful lookup scenarios are well-covered.The falsy timestamp test (line 92:
mockChat.t = 0) is a good edge case to verify. The successful lookup test properly verifies serialization is called with the mock chat object.test/unit/helpers/deduplication-cache.test.ts (4)
1-16: Excellent test setup with fake timers.Proper use of
vi.useFakeTimers()inbeforeEachandvi.useRealTimers()inafterEachensures deterministic TTL testing. The conditionalcache.dispose()prevents errors if a test fails before cache initialization.
18-39: Good coverage of add behavior including duplicate handling.Tests verify both the return value semantics (true for new, false for duplicate) and the side effect (id gets updated on duplicate).
41-89: Comprehensive has, get, and updateId tests.Tests cover the key scenarios: existence checks with matching/non-matching IDs, successful retrieval, and update behavior on existing vs non-existing entries.
91-113: TTL expiration tests properly validate time-based eviction.Good use of
vi.advanceTimersByTime()to simulate TTL expiration. Testing bothget()andhas()for expired entries ensures both code paths are covered.test/unit/utils/semver.test.ts (3)
4-31: Solid coverage for numeric semver ordering.
Covers equality and major/minor/patch comparisons cleanly.
33-50: Partial-version cases are well covered.
Two-part, single-part, and mixed partials are exercised.
52-69: Edge-case tests look thorough.
Empty inputs, null/undefined, and non-semver fallbacks are covered.test/unit/utils/logger.test.ts (5)
16-19: Good test isolation via reset to default logger.
Keeps global logger state predictable between tests.
21-33: Custom vs default logger behavior is well validated.
Covers set/get and reset semantics.
35-47: Core log function behavior is well tested.
Explicit and default levels are both verified.
49-73: Level-specific helpers are covered cleanly.
Each helper routes to the expected level.
75-93: Default logger output expectations are clear.
Prefix formatting for each level is validated.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
|
|
||
| <!doctype html> | ||
| <html lang="en"> | ||
|
|
||
| <head> | ||
| <title>Code coverage report for api/helpers/deduplication-cache.ts</title> | ||
| <meta charset="utf-8" /> | ||
| <link rel="stylesheet" href="../../prettify.css" /> | ||
| <link rel="stylesheet" href="../../base.css" /> | ||
| <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <style type='text/css'> | ||
| .coverage-summary .sorter { | ||
| background-image: url(../../sort-arrow-sprite.png); | ||
| } | ||
| </style> | ||
| </head> | ||
|
|
||
| <body> | ||
| <div class='wrapper'> | ||
| <div class='pad1'> | ||
| <h1><a href="../../index.html">All files</a> / <a href="index.html">api/helpers</a> deduplication-cache.ts</h1> | ||
| <div class='clearfix'> | ||
|
|
||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">89.87% </span> | ||
| <span class="quiet">Statements</span> | ||
| <span class='fraction'>71/79</span> | ||
| </div> | ||
|
|
||
|
|
||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">100% </span> | ||
| <span class="quiet">Branches</span> | ||
| <span class='fraction'>20/20</span> | ||
| </div> | ||
|
|
||
|
|
||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">88.88% </span> | ||
| <span class="quiet">Functions</span> | ||
| <span class='fraction'>8/9</span> | ||
| </div> | ||
|
|
||
|
|
||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">89.87% </span> | ||
| <span class="quiet">Lines</span> | ||
| <span class='fraction'>71/79</span> | ||
| </div> | ||
|
|
||
|
|
||
| </div> | ||
| <p class="quiet"> | ||
| Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block. | ||
| </p> | ||
| <template id="filterTemplate"> | ||
| <div class="quiet"> | ||
| Filter: | ||
| <input type="search" id="fileSearch"> | ||
| </div> | ||
| </template> | ||
| </div> | ||
| <div class='status-line high'></div> | ||
| <pre><table class="coverage"> | ||
| <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a> | ||
| <a name='L2'></a><a href='#L2'>2</a> | ||
| <a name='L3'></a><a href='#L3'>3</a> | ||
| <a name='L4'></a><a href='#L4'>4</a> | ||
| <a name='L5'></a><a href='#L5'>5</a> | ||
| <a name='L6'></a><a href='#L6'>6</a> | ||
| <a name='L7'></a><a href='#L7'>7</a> | ||
| <a name='L8'></a><a href='#L8'>8</a> | ||
| <a name='L9'></a><a href='#L9'>9</a> | ||
| <a name='L10'></a><a href='#L10'>10</a> | ||
| <a name='L11'></a><a href='#L11'>11</a> | ||
| <a name='L12'></a><a href='#L12'>12</a> | ||
| <a name='L13'></a><a href='#L13'>13</a> | ||
| <a name='L14'></a><a href='#L14'>14</a> | ||
| <a name='L15'></a><a href='#L15'>15</a> | ||
| <a name='L16'></a><a href='#L16'>16</a> | ||
| <a name='L17'></a><a href='#L17'>17</a> | ||
| <a name='L18'></a><a href='#L18'>18</a> | ||
| <a name='L19'></a><a href='#L19'>19</a> | ||
| <a name='L20'></a><a href='#L20'>20</a> | ||
| <a name='L21'></a><a href='#L21'>21</a> | ||
| <a name='L22'></a><a href='#L22'>22</a> | ||
| <a name='L23'></a><a href='#L23'>23</a> | ||
| <a name='L24'></a><a href='#L24'>24</a> | ||
| <a name='L25'></a><a href='#L25'>25</a> | ||
| <a name='L26'></a><a href='#L26'>26</a> | ||
| <a name='L27'></a><a href='#L27'>27</a> | ||
| <a name='L28'></a><a href='#L28'>28</a> | ||
| <a name='L29'></a><a href='#L29'>29</a> | ||
| <a name='L30'></a><a href='#L30'>30</a> | ||
| <a name='L31'></a><a href='#L31'>31</a> | ||
| <a name='L32'></a><a href='#L32'>32</a> | ||
| <a name='L33'></a><a href='#L33'>33</a> | ||
| <a name='L34'></a><a href='#L34'>34</a> | ||
| <a name='L35'></a><a href='#L35'>35</a> | ||
| <a name='L36'></a><a href='#L36'>36</a> | ||
| <a name='L37'></a><a href='#L37'>37</a> | ||
| <a name='L38'></a><a href='#L38'>38</a> | ||
| <a name='L39'></a><a href='#L39'>39</a> | ||
| <a name='L40'></a><a href='#L40'>40</a> | ||
| <a name='L41'></a><a href='#L41'>41</a> | ||
| <a name='L42'></a><a href='#L42'>42</a> | ||
| <a name='L43'></a><a href='#L43'>43</a> | ||
| <a name='L44'></a><a href='#L44'>44</a> | ||
| <a name='L45'></a><a href='#L45'>45</a> | ||
| <a name='L46'></a><a href='#L46'>46</a> | ||
| <a name='L47'></a><a href='#L47'>47</a> | ||
| <a name='L48'></a><a href='#L48'>48</a> | ||
| <a name='L49'></a><a href='#L49'>49</a> | ||
| <a name='L50'></a><a href='#L50'>50</a> | ||
| <a name='L51'></a><a href='#L51'>51</a> | ||
| <a name='L52'></a><a href='#L52'>52</a> | ||
| <a name='L53'></a><a href='#L53'>53</a> | ||
| <a name='L54'></a><a href='#L54'>54</a> | ||
| <a name='L55'></a><a href='#L55'>55</a> | ||
| <a name='L56'></a><a href='#L56'>56</a> | ||
| <a name='L57'></a><a href='#L57'>57</a> | ||
| <a name='L58'></a><a href='#L58'>58</a> | ||
| <a name='L59'></a><a href='#L59'>59</a> | ||
| <a name='L60'></a><a href='#L60'>60</a> | ||
| <a name='L61'></a><a href='#L61'>61</a> | ||
| <a name='L62'></a><a href='#L62'>62</a> | ||
| <a name='L63'></a><a href='#L63'>63</a> | ||
| <a name='L64'></a><a href='#L64'>64</a> | ||
| <a name='L65'></a><a href='#L65'>65</a> | ||
| <a name='L66'></a><a href='#L66'>66</a> | ||
| <a name='L67'></a><a href='#L67'>67</a> | ||
| <a name='L68'></a><a href='#L68'>68</a> | ||
| <a name='L69'></a><a href='#L69'>69</a> | ||
| <a name='L70'></a><a href='#L70'>70</a> | ||
| <a name='L71'></a><a href='#L71'>71</a> | ||
| <a name='L72'></a><a href='#L72'>72</a> | ||
| <a name='L73'></a><a href='#L73'>73</a> | ||
| <a name='L74'></a><a href='#L74'>74</a> | ||
| <a name='L75'></a><a href='#L75'>75</a> | ||
| <a name='L76'></a><a href='#L76'>76</a> | ||
| <a name='L77'></a><a href='#L77'>77</a> | ||
| <a name='L78'></a><a href='#L78'>78</a> | ||
| <a name='L79'></a><a href='#L79'>79</a> | ||
| <a name='L80'></a><a href='#L80'>80</a> | ||
| <a name='L81'></a><a href='#L81'>81</a> | ||
| <a name='L82'></a><a href='#L82'>82</a> | ||
| <a name='L83'></a><a href='#L83'>83</a> | ||
| <a name='L84'></a><a href='#L84'>84</a> | ||
| <a name='L85'></a><a href='#L85'>85</a> | ||
| <a name='L86'></a><a href='#L86'>86</a> | ||
| <a name='L87'></a><a href='#L87'>87</a> | ||
| <a name='L88'></a><a href='#L88'>88</a> | ||
| <a name='L89'></a><a href='#L89'>89</a> | ||
| <a name='L90'></a><a href='#L90'>90</a> | ||
| <a name='L91'></a><a href='#L91'>91</a> | ||
| <a name='L92'></a><a href='#L92'>92</a> | ||
| <a name='L93'></a><a href='#L93'>93</a> | ||
| <a name='L94'></a><a href='#L94'>94</a> | ||
| <a name='L95'></a><a href='#L95'>95</a> | ||
| <a name='L96'></a><a href='#L96'>96</a> | ||
| <a name='L97'></a><a href='#L97'>97</a> | ||
| <a name='L98'></a><a href='#L98'>98</a> | ||
| <a name='L99'></a><a href='#L99'>99</a> | ||
| <a name='L100'></a><a href='#L100'>100</a> | ||
| <a name='L101'></a><a href='#L101'>101</a> | ||
| <a name='L102'></a><a href='#L102'>102</a> | ||
| <a name='L103'></a><a href='#L103'>103</a> | ||
| <a name='L104'></a><a href='#L104'>104</a> | ||
| <a name='L105'></a><a href='#L105'>105</a> | ||
| <a name='L106'></a><a href='#L106'>106</a> | ||
| <a name='L107'></a><a href='#L107'>107</a> | ||
| <a name='L108'></a><a href='#L108'>108</a> | ||
| <a name='L109'></a><a href='#L109'>109</a> | ||
| <a name='L110'></a><a href='#L110'>110</a> | ||
| <a name='L111'></a><a href='#L111'>111</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">11x</span> | ||
| <span class="cline-any cline-yes">11x</span> | ||
| <span class="cline-any cline-yes">11x</span> | ||
| <span class="cline-any cline-yes">11x</span> | ||
| <span class="cline-any cline-yes">11x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">4x</span> | ||
| <span class="cline-any cline-yes">4x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">4x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">4x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">3x</span> | ||
| <span class="cline-any cline-yes">3x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">4x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">14x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">13x</span> | ||
| <span class="cline-any cline-yes">14x</span> | ||
| <span class="cline-any cline-yes">14x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span> | ||
| <span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">import { AckType } from '../model/enum/index.js'; | ||
| | ||
| const DEFAULT_TTL_MS = 5 * 60 * 1000; // 5 minutes | ||
| const CLEANUP_INTERVAL_MS = 60 * 1000; // Clean up every minute | ||
| | ||
| interface CacheEntry { | ||
| id: AckType | string; | ||
| timestamp: number; | ||
| } | ||
| | ||
| export class DeduplicationCache { | ||
| private cache: Map<string, CacheEntry>; | ||
| private ttlMs: number; | ||
| private cleanupTimer: ReturnType<typeof setInterval> | null = null; | ||
| | ||
| constructor(ttlMs: number = DEFAULT_TTL_MS) { | ||
| this.cache = new Map(); | ||
| this.ttlMs = ttlMs; | ||
| this.startCleanupTimer(); | ||
| } | ||
| | ||
| private startCleanupTimer() { | ||
| this.cleanupTimer = setInterval(() => { | ||
| <span class="cstat-no" title="statement not covered" > this.removeExpired();</span> | ||
| }, CLEANUP_INTERVAL_MS); | ||
| | ||
| // Don't prevent process exit | ||
| if (this.cleanupTimer.unref) { | ||
| this.cleanupTimer.unref(); | ||
| } | ||
| } | ||
| | ||
| private <span class="fstat-no" title="function not covered" >removeExpired() {</span> | ||
| <span class="cstat-no" title="statement not covered" > const now = Date.now();</span> | ||
| <span class="cstat-no" title="statement not covered" > for (const [key, entry] of this.cache) {</span> | ||
| <span class="cstat-no" title="statement not covered" > if (now - entry.timestamp > this.ttlMs) {</span> | ||
| <span class="cstat-no" title="statement not covered" > this.cache.delete(key);</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| | ||
| add(id: AckType | string, serialized: string): boolean { | ||
| const existing = this.cache.get(serialized); | ||
| | ||
| if (existing) { | ||
| // Update existing entry | ||
| existing.id = id; | ||
| existing.timestamp = Date.now(); | ||
| return false; | ||
| } | ||
| | ||
| this.cache.set(serialized, { | ||
| id, | ||
| timestamp: Date.now() | ||
| }); | ||
| return true; | ||
| } | ||
| | ||
| has(id: AckType | string, serialized: string): boolean { | ||
| const entry = this.cache.get(serialized); | ||
| if (!entry) { | ||
| return false; | ||
| } | ||
| | ||
| // Check if expired | ||
| if (Date.now() - entry.timestamp > this.ttlMs) { | ||
| this.cache.delete(serialized); | ||
| return false; | ||
| } | ||
| | ||
| return entry.id === id; | ||
| } | ||
| | ||
| get(serialized: string): CacheEntry | undefined { | ||
| const entry = this.cache.get(serialized); | ||
| if (!entry) { | ||
| return undefined; | ||
| } | ||
| | ||
| // Check if expired | ||
| if (Date.now() - entry.timestamp > this.ttlMs) { | ||
| this.cache.delete(serialized); | ||
| return undefined; | ||
| } | ||
| | ||
| return entry; | ||
| } | ||
| | ||
| updateId(serialized: string, newId: AckType | string): boolean { | ||
| const entry = this.cache.get(serialized); | ||
| if (!entry) { | ||
| return false; | ||
| } | ||
| | ||
| entry.id = newId; | ||
| entry.timestamp = Date.now(); | ||
| return true; | ||
| } | ||
| | ||
| dispose() { | ||
| if (this.cleanupTimer) { | ||
| clearInterval(this.cleanupTimer); | ||
| this.cleanupTimer = null; | ||
| } | ||
| this.cache.clear(); | ||
| } | ||
| } | ||
| | ||
| // Backwards compatibility alias | ||
| export { DeduplicationCache as callbackWile }; | ||
| </pre></td></tr></table></pre> | ||
|
|
||
| <div class='push'></div><!-- for sticky footer --> | ||
| </div><!-- /wrapper --> | ||
| <div class='footer quiet pad2 space-top1 center small'> | ||
| Code coverage generated by | ||
| <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> | ||
| at 2026-01-16T00:43:53.943Z | ||
| </div> | ||
| <script src="../../prettify.js"></script> | ||
| <script> | ||
| window.onload = function () { | ||
| prettyPrint(); | ||
| }; | ||
| </script> | ||
| <script src="../../sorter.js"></script> | ||
| <script src="../../block-navigation.js"></script> | ||
| </body> | ||
| </html> | ||
|
No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if coverage directory is in .gitignore
if [ -f .gitignore ]; then
echo "=== Contents of .gitignore ==="
cat .gitignore | grep -i coverage || echo "coverage/ not found in .gitignore"
else
echo ".gitignore file not found"
fi
# Check how many coverage files are being added
echo -e "\n=== Coverage files in repository ==="
find coverage -type f 2>/dev/null | wc -l
echo "Coverage files found"
# Show first few coverage files
echo -e "\n=== Sample of coverage files ==="
find coverage -type f 2>/dev/null | head -10
# Check if coverage is in git
echo -e "\n=== Git status for coverage directory ==="
git ls-files coverage/ 2>/dev/null | wc -l
echo "Coverage files tracked by git"Repository: venomlib/venom
Length of output: 727
Add coverage/ directory to .gitignore to prevent committing auto-generated coverage reports.
This repository currently tracks 34 Istanbul coverage HTML files that are regenerated on every test run. These build artifacts should not be committed and are increasing repository size unnecessarily. Add coverage/ to .gitignore and remove the tracked coverage files from git history.
🤖 Prompt for AI Agents
In `@coverage/api/helpers/deduplication-cache.ts.html` around lines 1 - 415, The
repo is tracking generated coverage HTML under coverage/ (e.g.,
coverage/api/helpers/deduplication-cache.ts.html); add coverage/ to .gitignore,
remove the tracked coverage files from Git, and commit the change. Specifically:
add the line "coverage/" to .gitignore, run git rm --cached -r coverage (or use
your history-rewrite tool like git filter-repo/BFG if you need to purge older
commits), and commit & push the removal; this will stop files like the generated
deduplication-cache.ts.html from being committed alongside code and keep classes
like DeduplicationCache and exported alias callbackWile out of versioned
coverage artifacts.
| <span class="cstat-no" title="statement not covered" > for (let i in data) {</span> | ||
| <span class="cstat-no" title="statement not covered" > if (typeof i == 'number') {</span> | ||
| <span class="cstat-no" title="statement not covered" > let result =</span> | ||
| <span class="cstat-no" title="statement not covered" > data[i].type && data[i].value && infoType(data[i].value, data[i].type)</span> | ||
| <span class="cstat-no" title="statement not covered" > ? true</span> | ||
| <span class="cstat-no" title="statement not covered" > : !data[i].value && data[i].isUser === false</span> | ||
| <span class="cstat-no" title="statement not covered" > ? true</span> | ||
| <span class="cstat-no" title="statement not covered" > : false;</span> | ||
| <span class="cstat-no" title="statement not covered" > if (!result) {</span> | ||
| <span class="cstat-no" title="statement not covered" > return {</span> | ||
| <span class="cstat-no" title="statement not covered" > erro: true,</span> | ||
| <span class="cstat-no" title="statement not covered" > param: data[i].param,</span> | ||
| <span class="cstat-no" title="statement not covered" > function: data[i].function,</span> | ||
| <span class="cstat-no" title="statement not covered" > text: `Invalid parameter in ${data[i].param}! Pass a variable of type ${data[i].type}!`</span> | ||
| <span class="cstat-no" title="statement not covered" > };</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd "layers-interface.ts" --type fRepository: venomlib/venom
Length of output: 139
🏁 Script executed:
wc -l src/api/helpers/layers-interface.tsRepository: venomlib/venom
Length of output: 96
🏁 Script executed:
cat -n src/api/helpers/layers-interface.tsRepository: venomlib/venom
Length of output: 1195
Validation loop is effectively skipped — validation never runs.
for (let i in data) produces string keys ('0', '1', '2', etc.), so typeof i == 'number' is always false and the validation block never executes. This allows invalid array items to pass through unchecked. Switch to for (let i = 0; i < data.length; i++) or for (const item of data) with an index counter.
🤖 Prompt for AI Agents
In `@coverage/api/helpers/layers-interface.ts.html` around lines 145 - 162, The
validation loop uses `for (let i in data)` which yields string keys so the
`typeof i == 'number'` check always fails and validation never runs; replace the
loop with a numeric index loop (e.g., `for (let i = 0; i < data.length; i++)`)
or a `for (const [i, item] of data.entries())` pattern so `i` is a numeric index
(or use `for (const item of data)` and refer to `item`), then keep the existing
logic that computes `result` using `infoType(data[i].value, data[i].type)` (or
`infoType(item.value, item.type)`) and return the same error object when
`!result`.
| <span class="cstat-no" title="statement not covered" >export async function scrapeDeleteToken(page: Page): Promise<boolean> {</span> | ||
| <span class="cstat-no" title="statement not covered" > const result = await page</span> | ||
| <span class="cstat-no" title="statement not covered" > .evaluate(() => {</span> | ||
| <span class="cstat-no" title="statement not covered" > const scrape = window.pathSession;</span> | ||
| <span class="cstat-no" title="statement not covered" > if (scrape === true) {</span> | ||
| <span class="cstat-no" title="statement not covered" > return true;</span> | ||
| <span class="cstat-no" title="statement not covered" > } else {</span> | ||
| <span class="cstat-no" title="statement not covered" > return false;</span> | ||
| <span class="cstat-no" title="statement not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > })</span> | ||
| <span class="cstat-no" title="statement not covered" > .catch(() => undefined);</span> | ||
| <span class="cstat-no" title="statement not covered" > return result;</span> | ||
| <span class="cstat-no" title="statement not covered" >}</span> |
There was a problem hiding this comment.
Type mismatch: function can return undefined despite Promise<boolean> return type.
The embedded source reveals a type safety issue in src/api/helpers/scrape-deletetoken.ts. The function signature declares Promise<boolean>, but the .catch(() => undefined) on line 120 means result can be undefined, which is then returned on line 121.
This will cause issues for callers expecting a boolean. In the actual source file, consider:
export async function scrapeDeleteToken(page: Page): Promise<boolean> {
const result = await page
.evaluate(() => {
const scrape = window.pathSession;
- if (scrape === true) {
- return true;
- } else {
- return false;
- }
+ return scrape === true;
})
- .catch(() => undefined);
- return result;
+ .catch(() => false);
+ return result ?? false;
}Also, this is a generated coverage artifact that should not be committed.
🤖 Prompt for AI Agents
In `@coverage/api/helpers/scrape-deletetoken.ts.html` around lines 110 - 122, The
function scrapeDeleteToken has a type mismatch because .catch(() => undefined)
allows returning undefined despite the Promise<boolean> signature; change the
error path to return a boolean (e.g., replace .catch(() => undefined) with
.catch(() => false)) and ensure the page.evaluate callback always returns a
boolean, or alternatively relax the signature to Promise<boolean | undefined> if
undefined is intended; also remove the generated coverage artifact file from the
commit so the coverage HTML isn't included in source.
coverage/base.css
Outdated
| body { | ||
| font-family: Helvetica Neue, Helvetica, Arial; | ||
| font-size: 14px; | ||
| color:#333; |
There was a problem hiding this comment.
Quote the multi-word font family to avoid unintended fallback.
Unquoted Helvetica Neue is parsed as two separate family names, so the intended font may never be selected and Helvetica is duplicated. Quoting it also resolves the duplicate-name lint warning.
🛠️ Suggested fix
-body {
- font-family: Helvetica Neue, Helvetica, Arial;
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;📝 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.
| body { | |
| font-family: Helvetica Neue, Helvetica, Arial; | |
| font-size: 14px; | |
| color:#333; | |
| body { | |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| font-size: 14px; | |
| color:`#333`; |
🧰 Tools
🪛 Biome (2.1.2)
[error] 6-6: Duplicate font names are redundant and unnecessary: Helvetica
Remove duplicate font names within the property
(lint/suspicious/noDuplicateFontNames)
🤖 Prompt for AI Agents
In `@coverage/base.css` around lines 5 - 8, The font-family declaration in the
body selector uses an unquoted multi-word family name; update the body {
font-family: ... } rule to quote "Helvetica Neue" (e.g., "Helvetica Neue",
Helvetica, Arial) so the multi-word family is treated as a single font family
and to avoid duplicate-name lint warnings.
coverage/base.css
Outdated
| .quiet { | ||
| color: #7f7f7f; | ||
| color: rgba(0,0,0,0.5); | ||
| } |
There was a problem hiding this comment.
Remove the duplicate color declaration to satisfy lint.
The second color overrides the first; keep a single modern value (or move fallback into @supports if you still need it).
🛠️ Suggested fix
.quiet {
- color: `#7f7f7f`;
- color: rgba(0,0,0,0.5);
+ color: rgb(0 0 0 / 0.5);
}📝 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.
| .quiet { | |
| color: #7f7f7f; | |
| color: rgba(0,0,0,0.5); | |
| } | |
| .quiet { | |
| color: rgb(0 0 0 / 0.5); | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 54-54: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
color is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
🤖 Prompt for AI Agents
In `@coverage/base.css` around lines 52 - 55, The .quiet class contains two
duplicate color declarations; remove the redundant one so only a single modern
value remains (e.g., keep color: rgba(0,0,0,0.5); and delete color: `#7f7f7f`;),
or if you need the hex fallback move the hex into an `@supports-compatible`
fallback block and leave the rgba as the primary value in the .quiet rule.
coverage/base.css
Outdated
| .wrapper { | ||
| min-height: 100%; | ||
| height: auto !important; | ||
| height: 100%; | ||
| margin: 0 auto -48px; |
There was a problem hiding this comment.
Drop the duplicate height rule in .wrapper.
Two height declarations trigger the lint error and the latter overrides the former. Remove the redundant line unless you still need the legacy hack.
🛠️ Suggested fix
.wrapper {
min-height: 100%;
height: auto !important;
- height: 100%;
margin: 0 auto -48px;
}📝 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.
| .wrapper { | |
| min-height: 100%; | |
| height: auto !important; | |
| height: 100%; | |
| margin: 0 auto -48px; | |
| .wrapper { | |
| min-height: 100%; | |
| height: auto !important; | |
| margin: 0 auto -48px; | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 219-219: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
height is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
🤖 Prompt for AI Agents
In `@coverage/base.css` around lines 216 - 220, Remove the duplicate height
declaration in the .wrapper rule: delete the redundant "height: 100%;" line
(leaving min-height and the legacy "height: auto !important;" only) so there is
a single, intentional height declaration and the lint error is resolved.
coverage/block-navigation.js
Outdated
| function toggleClass(index) { | ||
| missingCoverageElements | ||
| .item(currentIndex) | ||
| .classList.remove('highlighted'); | ||
| missingCoverageElements.item(index).classList.add('highlighted'); | ||
| } | ||
|
|
||
| function makeCurrent(index) { | ||
| toggleClass(index); | ||
| currentIndex = index; | ||
| missingCoverageElements.item(index).scrollIntoView({ | ||
| behavior: 'smooth', | ||
| block: 'center', | ||
| inline: 'center' | ||
| }); |
There was a problem hiding this comment.
Guard against empty coverage lists before toggling classes.
When there are no matching elements, .item(...) returns null and .classList will throw on the first keypress. Add a length check and only remove the previous highlight when currentIndex is set.
🛠️ Suggested fix
function toggleClass(index) {
- missingCoverageElements
- .item(currentIndex)
- .classList.remove('highlighted');
- missingCoverageElements.item(index).classList.add('highlighted');
+ if (!missingCoverageElements.length) return;
+ if (typeof currentIndex === 'number') {
+ const currentEl = missingCoverageElements.item(currentIndex);
+ if (currentEl) currentEl.classList.remove('highlighted');
+ }
+ const nextEl = missingCoverageElements.item(index);
+ if (nextEl) nextEl.classList.add('highlighted');
}📝 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.
| function toggleClass(index) { | |
| missingCoverageElements | |
| .item(currentIndex) | |
| .classList.remove('highlighted'); | |
| missingCoverageElements.item(index).classList.add('highlighted'); | |
| } | |
| function makeCurrent(index) { | |
| toggleClass(index); | |
| currentIndex = index; | |
| missingCoverageElements.item(index).scrollIntoView({ | |
| behavior: 'smooth', | |
| block: 'center', | |
| inline: 'center' | |
| }); | |
| function toggleClass(index) { | |
| if (!missingCoverageElements.length) return; | |
| if (typeof currentIndex === 'number') { | |
| const currentEl = missingCoverageElements.item(currentIndex); | |
| if (currentEl) currentEl.classList.remove('highlighted'); | |
| } | |
| const nextEl = missingCoverageElements.item(index); | |
| if (nextEl) nextEl.classList.add('highlighted'); | |
| } | |
| function makeCurrent(index) { | |
| toggleClass(index); | |
| currentIndex = index; | |
| missingCoverageElements.item(index).scrollIntoView({ | |
| behavior: 'smooth', | |
| block: 'center', | |
| inline: 'center' | |
| }); |
🤖 Prompt for AI Agents
In `@coverage/block-navigation.js` around lines 24 - 38, The
toggleClass/makeCurrent logic assumes missingCoverageElements.item(...) returns
an element; guard against empty lists by checking missingCoverageElements.length
and that currentIndex is not null/undefined before accessing .classList; only
call missingCoverageElements.item(currentIndex).classList.remove(...) when
missingCoverageElements.length > 0 and currentIndex is a valid index, and
likewise ensure missingCoverageElements.item(index) exists before calling
.classList.add(...) and scrollIntoView in makeCurrent.
coverage/prettify.js
Outdated
| /* eslint-disable */ | ||
| window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.ignoreCase){ac=true}else{if(/[a-z]/i.test(ae.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){S=true;ac=false;break}}}var Y={b:8,t:9,n:10,v:11,f:12,r:13};function ab(ah){var ag=ah.charCodeAt(0);if(ag!==92){return ag}var af=ah.charAt(1);ag=Y[af];if(ag){return ag}else{if("0"<=af&&af<="7"){return parseInt(ah.substring(1),8)}else{if(af==="u"||af==="x"){return parseInt(ah.substring(2),16)}else{return ah.charCodeAt(1)}}}}function T(af){if(af<32){return(af<16?"\\x0":"\\x")+af.toString(16)}var ag=String.fromCharCode(af);if(ag==="\\"||ag==="-"||ag==="["||ag==="]"){ag="\\"+ag}return ag}function X(am){var aq=am.substring(1,am.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));var ak=[];var af=[];var ao=aq[0]==="^";for(var ar=ao?1:0,aj=aq.length;ar<aj;++ar){var ah=aq[ar];if(/\\[bdsw]/i.test(ah)){ak.push(ah)}else{var ag=ab(ah);var al;if(ar+2<aj&&"-"===aq[ar+1]){al=ab(aq[ar+2]);ar+=2}else{al=ag}af.push([ag,al]);if(!(al<65||ag>122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;ar<af.length;++ar){var at=af[ar];if(at[0]<=ap[1]+1){ap[1]=Math.max(ap[1],at[1])}else{ai.push(ap=at)}}var an=["["];if(ao){an.push("^")}an.push.apply(an,ak);for(var ar=0;ar<ai.length;++ar){var at=ai[ar];an.push(T(at[0]));if(at[1]>at[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){an[af]=-1}}}}for(var ak=1;ak<an.length;++ak){if(-1===an[ak]){an[ak]=++ad}}for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am;if(an[am]===undefined){aj[ak]="(?:"}}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){aj[ak]="\\"+an[am]}}}}for(var ak=0,am=0;ak<ah;++ak){if("^"===aj[ak]&&"^"!==aj[ak+1]){aj[ak]=""}}if(al.ignoreCase&&S){for(var ak=0;ak<ah;++ak){var ag=aj[ak];var ai=ag.charAt(0);if(ag.length>=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.global||ae.multiline){throw new Error(""+ae)}aa.push("(?:"+W(ae)+")")}return new RegExp(aa.join("|"),ac?"gi":"g")}function a(V){var U=/(?:^|\s)nocode(?:\s|$)/;var X=[];var T=0;var Z=[];var W=0;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=document.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Y=S&&"pre"===S.substring(0,3);function aa(ab){switch(ab.nodeType){case 1:if(U.test(ab.className)){return}for(var ae=ab.firstChild;ae;ae=ae.nextSibling){aa(ae)}var ad=ab.nodeName;if("BR"===ad||"LI"===ad){X[W]="\n";Z[W<<1]=T++;Z[(W++<<1)|1]=ab}break;case 3:case 4:var ac=ab.nodeValue;if(ac.length){if(!Y){ac=ac.replace(/[ \t\r\n]+/g," ")}else{ac=ac.replace(/\r\n?/g,"\n")}X[W]=ac;Z[W<<1]=T;T+=ac.length;Z[(W++<<1)|1]=ab}break}}aa(V);return{sourceCode:X.join("").replace(/\n$/,""),spans:Z}}function B(S,U,W,T){if(!U){return}var V={sourceCode:U,basePos:S};W(V);T.push.apply(T,V.decorations)}var v=/\S/;function o(S){var V=undefined;for(var U=S.firstChild;U;U=U.nextSibling){var T=U.nodeType;V=(T===1)?(V?S:U):(T===3)?(v.test(U.nodeValue)?S:V):V}return V===S?undefined:V}function g(U,T){var S={};var V;(function(){var ad=U.concat(T);var ah=[];var ag={};for(var ab=0,Z=ad.length;ab<Z;++ab){var Y=ad[ab];var ac=Y[3];if(ac){for(var ae=ac.length;--ae>=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae<aq;++ae){var ag=an[ae];var ap=aj[ag];var ai=void 0;var am;if(typeof ap==="string"){am=false}else{var aa=S[ag.charAt(0)];if(aa){ai=ag.match(aa[1]);ap=aa[0]}else{for(var ao=0;ao<X;++ao){aa=T[ao];ai=ag.match(aa[1]);if(ai){ap=aa[0];break}}if(!ai){ap=F}}am=ap.length>=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y<W.length;++Y){ae(W[Y])}if(ag===(ag|0)){W[0].setAttribute("value",ag)}var aa=ac.createElement("OL");aa.className="linenums";var X=Math.max(0,((ag-1))|0)||0;for(var Y=0,T=W.length;Y<T;++Y){af=W[Y];af.className="L"+((Y+X)%10);if(!af.firstChild){af.appendChild(ac.createTextNode("\xA0"))}aa.appendChild(af)}V.appendChild(aa)}function D(ac){var aj=/\bMSIE\b/.test(navigator.userAgent);var am=/\n/g;var al=ac.sourceCode;var an=al.length;var V=0;var aa=ac.spans;var T=aa.length;var ah=0;var X=ac.decorations;var Y=X.length;var Z=0;X[Y]=an;var ar,aq;for(aq=ar=0;aq<Y;){if(X[aq]!==X[aq+2]){X[ar++]=X[aq++];X[ar++]=X[aq++]}else{aq+=2}}Y=ar;for(aq=ar=0;aq<Y;){var at=X[aq];var ab=X[aq+1];var W=aq+2;while(W+2<=Y&&X[W+1]===ab){W+=2}X[ar++]=at;X[ar++]=ab;aq=W}Y=X.length=ar;var ae=null;while(ah<T){var af=aa[ah];var S=aa[ah+2]||an;var ag=X[Z];var ap=X[Z+2]||an;var W=Math.min(S,ap);var ak=aa[ah+1];var U;if(ak.nodeType!==1&&(U=al.substring(V,W))){if(aj){U=U.replace(am,"\r")}ak.nodeValue=U;var ai=ak.ownerDocument;var ao=ai.createElement("SPAN");ao.className=X[Z+1];var ad=ak.parentNode;ad.replaceChild(ao,ak);ao.appendChild(ak);if(V<S){aa[ah+1]=ak=ai.createTextNode(al.substring(W,S));ad.insertBefore(ak,ao.nextSibling)}}V=W;if(V>=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*</.test(S)?"default-markup":"default-code"}return t[T]}c(K,["default-code"]);c(g([],[[F,/^[^<?]+/],[E,/^<!\w[^>]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa<ac.length;++aa){for(var Z=0,V=ac[aa].length;Z<V;++Z){T.push(ac[aa][Z])}}ac=null;var W=Date;if(!W.now){W={now:function(){return +(new Date)}}}var X=0;var S;var ab=/\blang(?:uage)?-([\w.]+)(?!\S)/;var ae=/\bprettyprint\b/;function U(){var ag=(window.PR_SHOULD_USE_CONTINUATION?W.now()+250:Infinity);for(;X<T.length&&W.now()<ag;X++){var aj=T[X];var ai=aj.className;if(ai.indexOf("prettyprint")>=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X<T.length){setTimeout(U,250)}else{if(ad){ad()}}}U()}window.prettyPrintOne=y;window.prettyPrint=b;window.PR={createSimpleLexer:g,registerLangHandler:c,sourceDecorator:i,PR_ATTRIB_NAME:P,PR_ATTRIB_VALUE:n,PR_COMMENT:j,PR_DECLARATION:E,PR_KEYWORD:z,PR_LITERAL:G,PR_NOCODE:N,PR_PLAIN:F,PR_PUNCTUATION:L,PR_SOURCE:J,PR_STRING:C,PR_TAG:m,PR_TYPE:O}})();PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^<script\b[^>]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:<!--|-->)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check for Biome configuration files
find . -maxdepth 2 -type f \( -name "biome.json" -o -name ".biomeignore" -o -name "biome.jsonc" \) 2>/dev/null | head -20Repository: venomlib/venom
Length of output: 70
🏁 Script executed:
# Check if coverage/ directory exists and its purpose
ls -la coverage/ 2>/dev/null | head -20Repository: venomlib/venom
Length of output: 802
🏁 Script executed:
# Verify the file exists and is indeed minified
wc -l coverage/prettify.js 2>/dev/null
file coverage/prettify.js 2>/dev/nullRepository: venomlib/venom
Length of output: 82
🏁 Script executed:
# Look for Biome configuration in package.json or other config locations
if [ -f "package.json" ]; then cat package.json | grep -A 10 '"biome"'; fiRepository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Search for any existing ignores or patterns for minified/vendor files
find . -maxdepth 2 -type f \( -name ".prettierignore" -o -name ".eslintignore" -o -name ".gitignore" \) -exec head -30 {} + 2>/dev/nullRepository: venomlib/venom
Length of output: 305
🏁 Script executed:
# Read the biome.json to understand current configuration
cat biome.jsonRepository: venomlib/venom
Length of output: 1832
🏁 Script executed:
# Check if there's a .biomeignore file that wasn't found in earlier search
cat .biomeignore 2>/dev/null || echo "No .biomeignore file found"Repository: venomlib/venom
Length of output: 84
🏁 Script executed:
# Look for comments or directives in prettify.js that might already exclude it
head -5 coverage/prettify.js
tail -5 coverage/prettify.jsRepository: venomlib/venom
Length of output: 35237
🏁 Script executed:
# Search for any biome-related ignore patterns in root config files
find . -maxdepth 1 -type f -name "*.json" -o -name "*.jsonc" -o -name "*.js" -o -name "*.ts" 2>/dev/null | xargs grep -l "coverage\|prettify\|ignore" 2>/dev/null | head -10Repository: venomlib/venom
Length of output: 123
🏁 Script executed:
# Check if this file is mentioned in any configuration or comments
rg "coverage/prettify|prettify\.js" --type json --type js --type ts -B 2 -A 2 2>/dev/null | head -30Repository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Check if coverage/ directory is generated or part of the build process
find . -maxdepth 2 -type f \( -name "*.json" -o -name "*.ts" -o -name "*.js" -o -name "Makefile" \) -exec grep -l "coverage\|prettify" {} + 2>/dev/null | head -10Repository: venomlib/venom
Length of output: 132
🏁 Script executed:
# Check if there's a build script in package.json
if [ -f "package.json" ]; then grep -A 5 '"scripts"' package.json | head -20; fiRepository: venomlib/venom
Length of output: 329
🏁 Script executed:
# Verify if the /* eslint-disable */ comment is sufficient or if Biome needs additional configuration
rg "biomeignore|ignorePatterns" biome.jsonRepository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Check Biome documentation or configuration for alternative ways to ignore files
# Look at full biome.json to see if there are any ignore patterns or overrides
cat biome.json | python3 -m json.tool 2>/dev/null | grep -A 5 -B 5 "ignore\|pattern\|exclude"Repository: venomlib/venom
Length of output: 144
🏁 Script executed:
# Verify if biome supports ignore patterns in its config
rg "ignore|exclude|pattern" biome.json --no-headingRepository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Check if there's documentation or examples in the repo about handling vendor files
find . -maxdepth 2 -type f \( -name "README*" -o -name "CONTRIBUTING*" -o -name ".gitignore" \) -exec grep -l "coverage\|vendor\|generated" {} + 2>/dev/nullRepository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Verify the coverage directory is indeed for test coverage or documentation
head -20 coverage/index.html 2>/dev/null | head -15Repository: venomlib/venom
Length of output: 557
🏁 Script executed:
# Check Biome official documentation about ignore patterns - search for any references
web_search "Biome .biomeignore configuration"Repository: venomlib/venom
Length of output: 108
🏁 Script executed:
# Look for any existing biome-ignore comments or patterns in the codebase
rg "biome-ignore|@biome" --type js --type ts -B 1 -A 1 2>/dev/null | head -20Repository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Check if there are any other vendor/minified files that might already be handled
find coverage -type f -name "*.js" -o -name "*.css" 2>/dev/null | xargs wc -l | sort -rn | head -10Repository: venomlib/venom
Length of output: 208
🌐 Web query:
Biome ignore patterns configuration biomeignore
💡 Result:
Short guide — how to configure ignore patterns for Biome
-
Where to put them: in your project Biome config (biome.json / biome.config.*) under the files, formatter or linter sections depending on what you want to ignore. [1][2]
-
Basic files include/ignore:
- Use files.includes with globs; negated patterns exclude. Example to include everything but ignore dist/:
{ "files": { "includes": ["", "!dist", "!/dist"] } }. - Note: excluding a folder using "!dist" will prevent traversal; using "!dist/**" only excludes files but still crawls the folder (worse perf). Prefer "!dist" for directories. [1][2]
- Use files.includes with globs; negated patterns exclude. Example to include everything but ignore dist/:
-
Force-ignore (prevent the scanner from even indexing a path):
- Start the negation with double bang !!. Example to never look inside any dist folder:
{ "files": { "includes": ["", "!!/dist"] } }. Use this for build/output folders or nested biome.json/.gitignore you want ignored. [2]
- Start the negation with double bang !!. Example to never look inside any dist folder:
-
Formatter / Linter specific ignores:
- Formatter: use formatter.ignore or formatter.include arrays (unix shell style globs). When both present, ignore takes precedence. Example:
{ "formatter": { "ignore": ["scripts/*.js"] } }. [4] - Linter: use overrides with include/ignore for per-pattern control. Both linter and formatter support per-override include/ignore. [4][6]
- Formatter: use formatter.ignore or formatter.include arrays (unix shell style globs). When both present, ignore takes precedence. Example:
-
In-file suppressions:
- Use single-line suppression comments for specific lint/format cases, e.g.:
// biome-ignore lint: reason
// biome-ignore format: reason - Biome does not provide an in-file comment to ignore an entire file; use config ignores for that. [1][3][6]
- Use single-line suppression comments for specific lint/format cases, e.g.:
References
- Biome configuration (files includes/ignore, force-ignore, scanner behavior). [1]
- Biome configuration reference (force-ignore examples + scanner notes). [2]
- Formatter ignore & ignore-code comments. [3][4]
If you want, tell me which files/folders you need to ignore and I’ll produce the exact biome.json snippet.
🏁 Script executed:
# Check Biome documentation or comments in biome.json schema reference
head -1 biome.json | grep schemaRepository: venomlib/venom
Length of output: 40
🏁 Script executed:
# Try running biome check on just that file to see if errors actually occur
# First, let's see if biome is installed/available
if command -v biome &> /dev/null; then biome --version; else echo "Biome not in PATH"; fiRepository: venomlib/venom
Length of output: 73
🏁 Script executed:
# Now that we know biome is installed, let's check if it actually reports errors on prettify.js
biome check coverage/prettify.js 2>&1 | head -30Repository: venomlib/venom
Length of output: 50371
🏁 Script executed:
# Check the current linter rules for JavaScript files in biome.json to understand what might trigger on this file
grep -A 50 '"linter"' biome.json | grep -E '"rules"|"recommended"'Repository: venomlib/venom
Length of output: 187
Exclude the coverage/ directory from Biome linting.
Biome reports noUselessUndefinedInitialization on coverage/prettify.js—a minified vendor file used for test coverage reports. Since this is generated code, exclude it in biome.json:
Suggested configuration
# biome.json
{
"linter": {
"enabled": true,
+ "ignore": ["coverage"],
"rules": {🧰 Tools
🪛 Biome (2.1.2)
[error] 2-2: 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:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 2-2: 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:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 2-2: Shouldn't redeclare 'ar'. Consider to delete it or rename it.
'ar' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ar'. Consider to delete it or rename it.
'ar' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'at'. Consider to delete it or rename it.
'at' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'am'. Consider to delete it or rename it.
'am' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ag'. Consider to delete it or rename it.
'ag' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'af'. Consider to delete it or rename it.
'af' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'am'. Consider to delete it or rename it.
'am' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ak'. Consider to delete it or rename it.
'ak' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ag'. Consider to delete it or rename it.
'ag' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'V'. Consider to delete it or rename it.
'V' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'U'. Consider to delete it or rename it.
'U' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'ae'. Consider to delete it or rename it.
'ae' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'Y'. Consider to delete it or rename it.
'Y' is defined here:
(lint/suspicious/noRedeclare)
[error] 2-2: Shouldn't redeclare 'W'. Consider to delete it or rename it.
'W' is defined here:
(lint/suspicious/noRedeclare)
🤖 Prompt for AI Agents
In `@coverage/prettify.js` around lines 1 - 2, Summary: Biome is linting generated
vendor file coverage/prettify.js and raising noUselessUndefinedInitialization;
exclude the coverage/ directory in biome.json. Fix: open biome.json and add
"coverage/**" (or "coverage/") to the "exclude" array (or create an "exclude"
array if missing) so Biome ignores the generated files; ensure the pattern
covers nested files (use glob "**") and commit the change. Reference: the lint
rule name noUselessUndefinedInitialization and the generated file
coverage/prettify.js to verify the exclusion works.
| it('should handle message ID generation failure', async () => { | ||
| const chatId = '1234567890@c.us'; | ||
| const mockChat = createChatMock(chatId); | ||
|
|
||
| env.storeMock.FindOrCreateChat.findOrCreateLatestChat.mockResolvedValue({ | ||
| chat: mockChat | ||
| }); | ||
| env.wapiMock.getNewMessageId.mockResolvedValue(null); | ||
|
|
||
| const result = await sendMessage(chatId, 'Hello'); | ||
|
|
||
| expect(result.erro).toBe(true); | ||
| expect(result.text).toBe('Error to gerate newId'); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "gerate" --type=jsRepository: venomlib/venom
Length of output: 50371
Fix typo in error message: "gerate" should be "generate".
The source code at src/lib/wapi/functions/send-message.js:62 contains the typo 'Error to gerate newId'. Update this to 'Error to generate newId' and adjust the test expectation accordingly.
🤖 Prompt for AI Agents
In `@test/unit/wapi/send-message.test.ts` around lines 189 - 202, The test and
source contain a typo in the error string — update the error message in the
sendMessage implementation (function sendMessage) from "Error to gerate newId"
to "Error to generate newId" and then update the unit test expectation in
send-message.test.ts to expect 'Error to generate newId' so both implementation
and test match; ensure no other occurrences of "gerate" remain.
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
src/lib/wapi/functions/mark-markSeen-message.js (1)
7-13: Handle falsychatfromfindChatto avoid runtime errors.When
findChatreturns null/false,chat.errothrows. Guard and return the error scope early.🛠️ Proposed fix
- const chat = await WAPI.findChat(id); - if (!chat.erro) { - //await Store.ReadSeen.markUnread(chat); - await Store.ReadSeen.sendSeen(chat, false); - return WAPI.scope(undefined, false, 'OK', null); - } else { - return WAPI.scope(undefined, true, 'Error', null); - } + const chat = await WAPI.findChat(id); + if (!chat || chat.erro) { + return WAPI.scope(undefined, true, 'Error', null); + } + //await Store.ReadSeen.markUnread(chat); + await Store.ReadSeen.sendSeen(chat, false); + return WAPI.scope(undefined, false, 'OK', null);src/lib/wapi/functions/forward-messages.js (1)
18-26: Potential null dereference:chat.idaccessed before validation.Line 18-19 access
chat.id._serializedandchat.idbefore the validation on line 24 checks ifchat.idexists. IffindChatreturns an error object without anidproperty, this will throw.Consider moving the
chat.idcheck earlier:+ if (!chat || !chat.id) { + throw chat; + } + let newMsgId = await window.WAPI.getNewMessageId(chat.id._serialized); let inChat = await WAPI.getchatId(chat.id).catch(() => {}); if (inChat) { chat.lastReceivedKey._serialized = inChat._serialized; chat.lastReceivedKey.id = inChat.id; } - if (!chat.id) { - throw chat; - }src/lib/wapi/functions/promote-participant.js (1)
8-13: Guard against falsy results fromWAPI.findChat.
IffindChatreturnsfalse/nullfor any contact, the current filter dereferencesc.erroand will throw. Add a null guard before accessing fields.🔧 Proposed fix
- contactsId = contactsId - .filter((c) => !c.erro && c.isUser) + contactsId = contactsId + .filter((c) => c && !c.erro && c.isUser) .map((c) => chat.groupMetadata.participants.get(c.id))src/lib/wapi/functions/set-profile-pic.js (1)
2-8: NormalizeWAPI.getMeUser()return value to a Wid before passing tosendSetPicture.The code path when
idis falsy passes the raw result fromgetMeUser()(a Store object) directly tosendSetPicture, while the truthy path wraps the id withStore.WidFactory.createWid(). This type inconsistency can causesendSetPictureto receive incompatible types. Align both code paths to normalize the return value usingStore.WidFactory.createWid(), following the pattern used elsewhere in the codebase (e.g.,get-host.js).src/lib/wapi/functions/set-new-message.js (1)
9-22: Guard against nullchatbefore dereferencingchat.id.
WAPI.findChatcan fail or return a 404-like object (as handled elsewhere). Accessingchat.idwithout checkingchatcan throw and break message creation.🛠️ Proposed fix
- if (chat.id) { + if (chat && chat.status !== 404 && chat.id) { const newMsgId = new Object(); newMsgId.fromMe = true; newMsgId.id = info.id; newMsgId.remote = await new Store.WidFactory.createWid( chat.id._serialized ); newMsgId._serialized = `${newMsgId.fromMe}_${newMsgId.remote}_${newMsgId.id}`; const Msgkey = await new Store.MsgKey(newMsgId); return Msgkey; - } else { - return false; } + return false;src/lib/wapi/functions/simulate-status-chat.js (1)
6-68: Avoidchat.erroaccess whenfindChatreturns null/false.With the new
findChatpath, these functions will throw if it returns a falsy value. Add a guard before touchingchat.erro(apply to all four helpers).🛠️ Proposed fix (apply to each function)
export async function startTyping(chatId, checkNumber = true) { const chat = await WAPI.findChat(chatId); - if (chat && chat.status != 404 && chat.id) { + if (!chat) return chat; + if (chat.status != 404 && chat.id) { await WAPI.presenceAvailable(); const result = await Store.SetStatusChat.markComposing(chat); return WAPI.scope(undefined, false, result); } if (!chat.erro) { chat.erro = true; } return chat; }
🤖 Fix all issues with AI agents
In `@src/lib/wapi/functions/add-participant.js`:
- Around line 8-11: The code maps contactsId via WAPI.findChat then immediately
checks length and passes results to addParticipants, but Promise.all preserves
input length and findChat can return error objects (status === 404); update the
flow to filter the Promise.all results (for example filter out entries where
c.erro is truthy or c.isUser is false) before calling addParticipants and change
the emptiness check to use the filtered array (return false if filtered.length
=== 0); locate the logic around contactsId, WAPI.findChat, and the call to
addParticipants in add-participant.js to implement this filtering and adjusted
check (mirroring the pattern used in create-group.js).
In `@src/lib/wapi/functions/check-send-exist.js`:
- Around line 99-115: The findChat function is not awaiting async results: await
WAPI.sendCheckType(chatId) should be used so invalid IDs don't bypass
validation, and await window.Store.WidFactory.createWid(chatId) should be used
so findOrCreateLatestChat receives a Wid (not a Promise); update findChat to
await both WAPI.sendCheckType and WidFactory.createWid (keeping the try/catch
and returning WAPI.scope(...) on failure) to mirror the usage in get-chat.js.
In `@src/lib/wapi/functions/delete-all-message.js`:
- Around line 10-11: The error check after calling findChat uses "chat &&
chat.status != 404" which is inconsistent with the rest of the codebase that
checks for "!chat.erro"; update the check in the delete-all-message handler to
the standard pattern (e.g., if (chat && !chat.erro) or simply if (!chat.erro)
after ensuring chat is defined) so it matches send-contact-vcard-list.js and
send-seen.js; locate the findChat call and the "chat" variable in
delete-all-message.js and replace the status-based check with the erro-based
check, and run a quick grep for other findChat usages to ensure consistency
across files.
In `@src/lib/wapi/functions/delete-messages.js`:
- Line 10: The call to WAPI.findChat can return falsy and the code later
dereferences chat (e.g., accessing chat.erro), so add a null check immediately
after "const chat = await WAPI.findChat(chatId)" to handle missing chats: if
chat is falsy, return a scoped error result object (consistent with the
function's return shape) indicating the chatId was not found instead of
continuing; apply the same guard where chat is used later (the block around
lines 75-79) to prevent dereference errors.
In `@src/lib/wapi/functions/fix-chat.js`:
- Around line 8-9: The error check in fix-chat.js uses the nonstandard condition
"if (!chat.erro)"; update the validation to match the codebase pattern by
checking "chat.status !== 404" after calling WAPI.findChat(chatId), and also
ensure a valid chat id is present (e.g., verify chat.id) if pinning requires
it—mirror the checks used in pin.chat.js and other message functions to maintain
consistency and avoid the validation gap.
In `@src/lib/wapi/functions/get-new-message-id.js`:
- Around line 1-4: In getNewMessageId, add a null guard for the result of
WAPI.findChat by changing the conditional to check both chat and chat.id (e.g.,
if (chat && chat.id)) to avoid throwing when findChat returns falsy, and remove
the unused parameter checkNumber from the function signature (export async
function getNewMessageId(chatId)) as it is never used; update any internal
references within getNewMessageId (e.g., newMsgId creation/logic) accordingly
and run tests to ensure callers remain compatible.
In `@src/lib/wapi/functions/get-number-profile.js`:
- Line 5: The code calls WAPI.findChat(id) and later accesses chat.erro without
ensuring chat is not null; add a null guard after const chat = await
WAPI.findChat(id) (e.g., check if chat is truthy before any chat.erro access)
and handle the falsy case by returning or throwing an appropriate error/result
from get-number-profile so subsequent lines never access properties on a
null/undefined chat.
In `@src/lib/wapi/functions/mark-unseen-message.js`:
- Line 7: WAPI.findChat(id) can return undefined, so update the
mark-unseen-message logic to guard against a falsy chat before accessing
chat.erro: after calling WAPI.findChat(id) check that the returned chat is
truthy (e.g., if (!chat) { handle/not-found path or return false }) and only
then read chat.erro and proceed with setting isUnseen; reference the
WAPI.findChat call and the chat.erro access in mark-unseen-message.js and ensure
the function returns or handles the missing-chat case gracefully.
In `@src/lib/wapi/functions/only-send-data-admin.js`:
- Around line 10-14: The code calls WAPI.findChat(chat) but then uses the
original chat variable for the group ID, which can be a string and lead to
undefined IDs; update the flow in only-send-data-admin.js to use the resolved
chatObj (from WAPI.findChat) for the ID passed to
Store.onlySendAdmin.sendSetGroupProperty (i.e., use chatObj.id), and add a guard
to handle when chatObj is falsy before calling sendSetGroupProperty and before
returning via WAPI.scope to avoid passing undefined IDs.
In `@test/index.js`:
- Line 48: Replace the hardcoded recipient in the test that calls
client.sendText(...) with a configurable value: stop committing PII by reading
the destination number from an environment variable (e.g.,
process.env.TEST_WHATSAPP_NUMBER) or a test-only constant/mock, and update the
test harness to validate the variable is set (or skip the integration send when
not present); locate the call to client.sendText in test/index.js and refactor
it to use the env variable or mock-number and document the required env var in
the test README.
🧹 Nitpick comments (16)
test/index.js (3)
2-2: Unused import after commenting out FFmpeg block.The
fluent-ffmpegimport is no longer used since the FFmpeg audio processing block is commented out. Consider removing it to keep the test script clean.Suggested fix
import venom from '../dist/index.mjs'; -import ffmpeg from 'fluent-ffmpeg';
19-21: Unused variablef.
getHostDevice()result is assigned tofbut is no longer used since the console.log is commented out. Consider either removing the assignment or uncommenting the log if it's needed for debugging.Suggested fix (if host device info is not needed)
async function start(client) { - const f = await client.getHostDevice(); console.log(await client.getWAVersion()); - //console.log(f);
26-47: Consider removing the commented-out FFmpeg block.Large blocks of commented-out code clutter the codebase and can become stale. If this functionality is no longer needed for the test script, consider removing it entirely. If it's needed for occasional debugging, consider keeping it in a separate file or behind a feature flag.
src/lib/wapi/functions/send-file.js (1)
128-128: WAPI.getMeUser integration looks good; remember to rebuild WAPI bundle.As per coding guidelines, run
npm run build:wapiafter modifying injected WAPI functions.src/lib/wapi/functions/set-group-image.js (1)
13-13: LGTM on the findChat swap; remember to rebuild the WAPI bundle.This aligns with the new lookup API. As per coding guidelines, please run
npm run build:wapiafter modifying WAPI function files.src/lib/wapi/functions/archive-chat.js (1)
2-2: Looks good; aligns with the findChat migration.No behavioral concerns with the lookup switch. Reminder: rebuild the injected WAPI bundle after modifying files under
src/lib/wapi/functions(runnpm run build:wapi). As per coding guidelines, please runnpm run build:wapiafter modifying WAPI functions.src/lib/wapi/functions/send-message.js (1)
46-46: Guard against a null/undefinedgetMeUser()result before building the message.If
WAPI.getMeUser()can ever resolve to a falsy value (e.g., during initialization),message.frombecomes invalid and send can fail unpredictably. Please confirm the helper’s guarantees, and consider a fail-fast guard if needed.✅ Suggested guard
- const fromwWid = await WAPI.getMeUser(); + const fromwWid = await WAPI.getMeUser(); + if (!fromwWid) { + return WAPI.scope(to, true, 404, 'Unable to resolve sender user'); + }src/lib/wapi/functions/send-seen.js (1)
3-14: Promise result is discarded; function always returnstrueon success path.The
WAPI.scope()return values from.then()and.catch()are never used. The function always returnstrue(line 11) regardless of whethermarkUnreadsucceeded or failed. This appears to be pre-existing behavior, but since this file is being touched, consider fixing it:Proposed fix to properly return the result
export async function sendSeen(id, done) { const chat = await WAPI.findChat(id); if (!chat.erro) { - await Store.ReadSeen.markUnread(chat, false) + return await Store.ReadSeen.markUnread(chat, false) .then(() => { return WAPI.scope(undefined, false, 'OK', null); }) .catch(() => { return WAPI.scope(undefined, true, 'Error', null); }); - return true; } else { - return false; + return WAPI.scope(undefined, true, 'Error', 'Chat not found'); } }Also note: the
doneparameter is unused and could be removed if it's not needed for a callback pattern.src/lib/wapi/functions/forward-messages.js (1)
65-68: Empty catch clause loses error context.The catch block discards the error, making debugging harder. Consider capturing and logging the error or including it in the thrown scope object.
♻️ Suggested improvement
- } catch { + } catch (error) { var obj = WAPI.scope(newMsgId, true, 404, null); Object.assign(obj, m); throw obj; }src/lib/wapi/functions/get-group-admins.js (1)
18-56: Consider using optional chaining to reduce verbosity.The repetitive
participant.contact && participant.contact.X ? participant.contact.X : nullpattern can be simplified.♻️ Suggested simplification
return { id: participant.id ? participant.id : null, - displayName: - participant.contact && participant.contact.displayName - ? participant.contact.displayName - : null, - mentionName: - participant.contact && participant.contact.mentionName - ? participant.contact.mentionName - : null, + displayName: participant.contact?.displayName ?? null, + mentionName: participant.contact?.mentionName ?? null, + notifyName: participant.contact?.notifyName ?? null, + isBusiness: participant.contact?.isBusiness ?? null, + pushname: participant.contact?.pushname ?? null, + isUser: participant.contact?.isUser ?? null, + isMyContact: participant.contact?.isMyContact ?? null, + isMe: participant.contact?.isMe ?? null // ... apply same pattern to remaining properties };src/lib/wapi/functions/send-type-buttons.js (1)
13-17: Dead code: redundant check is always false.Line 15 checks
if (!hButtons[index].urlButton)inside a block that's only entered whenhButtons[index].urlButtonis truthy (line 13). This condition can never be true.The same pattern appears at lines 48 and 85 for
callButtonandquickReplyButton.♻️ Remove unreachable checks
if (hButtons[index].urlButton) { b++; - if (!hButtons[index].urlButton) { - return WAPI.scope(to, true, 404, 'passed object urlButton'); - } if (typeof hButtons[index].urlButton !== 'object') {Apply similar removal at lines 48-50 and 85-87.
src/lib/wapi/functions/promote-participant.js (1)
1-29: Remember to rebuild the injected WAPI bundle after edits.
Runnpm run build:wapiafter modifyingsrc/lib/wapi/functions/**/*.js. As per coding guidelines, please rebuild the WAPI layer bundle.src/lib/wapi/functions/demote-participant.js (1)
8-8: Harden lookup failures when usingWAPI.findChat.If
WAPI.findChatcan reject (or return a different error shape thansendExist),Promise.allwill short‑circuit and the whole demotion fails. Consider normalizing failures so one bad ID doesn’t abort the batch, or confirmfindChatnever rejects.💡 Possible hardening
- contactsId = await Promise.all(contactsId.map((c) => WAPI.findChat(c))); + contactsId = await Promise.all( + contactsId.map((c) => + WAPI.findChat(c).catch(() => ({ erro: true, isUser: false })) + ) + );src/lib/wapi/functions/get-all-chats.js (1)
2-4: Guard forWAPI.getMeUser()return shape before_serialized.This assumes
getMeUser()returns an object with_serialized. If it ever returns a string or null, Line 4 will throw. Please confirm the contract or make it tolerant.💡 Compatibility guard
- const fromwWid = await WAPI.getMeUser(); + const me = await WAPI.getMeUser(); + const fromwWid = typeof me === 'string' ? me : me?._serialized; if (fromwWid) { - const idUser = await WAPI.findChat(fromwWid._serialized); + const idUser = await WAPI.findChat(fromwWid);src/lib/wapi/functions/remove-participant.js (1)
8-8: ConfirmfindChatrejection behavior in batch resolution.If
WAPI.findChatcan reject,Promise.allwill abort and skip removals entirely. Please confirm it never rejects, or consider normalizing failures to keep the batch resilient.src/lib/wapi/functions/send-list-menu.js (1)
98-103: LGTM on thefindChat/getMeUserswitch.This matches the updated WAPI usage pattern and keeps the existing guard intact.
As per coding guidelines, remember to runnpm run build:wapiafter changing WAPI injected functions.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
dist/cjs/api/layers/group.layer.jsis excluded by!**/dist/**dist/cjs/api/layers/group.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/cjs/api/layers/sender.layer.jsis excluded by!**/dist/**dist/cjs/api/layers/sender.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/esm/api/layers/group.layer.jsis excluded by!**/dist/**dist/esm/api/layers/group.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/esm/api/layers/sender.layer.jsis excluded by!**/dist/**dist/esm/api/layers/sender.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/lib/wapi/wapi.jsis excluded by!**/dist/**package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (58)
src/api/layers/group.layer.tssrc/api/layers/sender.layer.tssrc/lib/wapi/functions/add-participant.jssrc/lib/wapi/functions/archive-chat.jssrc/lib/wapi/functions/check-id-messagem.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/create-group.jssrc/lib/wapi/functions/delete-all-message.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/demote-participant.jssrc/lib/wapi/functions/fix-chat.jssrc/lib/wapi/functions/forward-messages.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/get-all-messages-in-chat.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/get-group-admins.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/get-number-profile.jssrc/lib/wapi/functions/index.jssrc/lib/wapi/functions/mark-markSeen-message.jssrc/lib/wapi/functions/mark-unseen-message.jssrc/lib/wapi/functions/only-send-admin.jssrc/lib/wapi/functions/only-send-data-admin.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/functions/pin.chat.jssrc/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/promote-participant.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/reply.jssrc/lib/wapi/functions/send-buttons.jssrc/lib/wapi/functions/send-contact-vcard-list.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/send-file.jssrc/lib/wapi/functions/send-link-preview.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/send-mute.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/send-seen.jssrc/lib/wapi/functions/send-sticker.jssrc/lib/wapi/functions/send-type-buttons.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/set-group-title.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/set-profile-pic.jssrc/lib/wapi/functions/simulate-status-chat.jssrc/lib/wapi/functions/test.jssrc/lib/wapi/helper/filter-object.jssrc/lib/wapi/helper/get-me-user.jssrc/lib/wapi/helper/index.jssrc/lib/wapi/wapi.jstest/index.js
🧰 Additional context used
📓 Path-based instructions (4)
src/lib/wapi/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI layer code is built with webpack and injected into the Puppeteer browser context
Files:
src/lib/wapi/helper/index.jssrc/lib/wapi/functions/send-mute.jssrc/lib/wapi/functions/get-all-messages-in-chat.jssrc/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/forward-messages.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/get-number-profile.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/test.jssrc/lib/wapi/functions/send-type-buttons.jssrc/lib/wapi/functions/get-group-admins.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/helper/get-me-user.jssrc/lib/wapi/functions/set-profile-pic.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/mark-markSeen-message.jssrc/lib/wapi/functions/send-link-preview.jssrc/lib/wapi/functions/check-id-messagem.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/delete-all-message.jssrc/lib/wapi/wapi.jssrc/lib/wapi/functions/fix-chat.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/simulate-status-chat.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/send-contact-vcard-list.jssrc/lib/wapi/functions/demote-participant.jssrc/lib/wapi/functions/create-group.jssrc/lib/wapi/helper/filter-object.jssrc/lib/wapi/functions/send-sticker.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/pin.chat.jssrc/lib/wapi/functions/send-buttons.jssrc/lib/wapi/functions/index.jssrc/lib/wapi/functions/add-participant.jssrc/lib/wapi/functions/promote-participant.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/send-seen.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/send-file.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/set-group-title.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/only-send-admin.jssrc/lib/wapi/functions/archive-chat.jssrc/lib/wapi/functions/only-send-data-admin.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/reply.jssrc/lib/wapi/functions/mark-unseen-message.js
src/lib/wapi/functions/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run
npm run build:wapito rebuild
Files:
src/lib/wapi/functions/send-mute.jssrc/lib/wapi/functions/get-all-messages-in-chat.jssrc/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/forward-messages.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/get-number-profile.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/test.jssrc/lib/wapi/functions/send-type-buttons.jssrc/lib/wapi/functions/get-group-admins.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/functions/set-profile-pic.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/mark-markSeen-message.jssrc/lib/wapi/functions/send-link-preview.jssrc/lib/wapi/functions/check-id-messagem.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/delete-all-message.jssrc/lib/wapi/functions/fix-chat.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/simulate-status-chat.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/send-contact-vcard-list.jssrc/lib/wapi/functions/demote-participant.jssrc/lib/wapi/functions/create-group.jssrc/lib/wapi/functions/send-sticker.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/pin.chat.jssrc/lib/wapi/functions/send-buttons.jssrc/lib/wapi/functions/index.jssrc/lib/wapi/functions/add-participant.jssrc/lib/wapi/functions/promote-participant.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/send-seen.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/send-file.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/set-group-title.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/only-send-admin.jssrc/lib/wapi/functions/archive-chat.jssrc/lib/wapi/functions/only-send-data-admin.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/reply.jssrc/lib/wapi/functions/mark-unseen-message.js
src/api/layers/*.layer.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Keep functionality layers in src/api/layers using the *.layer.ts naming (e.g., sender.layer.ts, listener.layer.ts, group.layer.ts, profile.layer.ts, controls.layer.ts, retriever.layer.ts)
Files:
src/api/layers/sender.layer.tssrc/api/layers/group.layer.ts
test/index.js
📄 CodeRabbit inference engine (CLAUDE.md)
Use test/index.js as the main test script; tests are basic scripts without a formal framework
Files:
test/index.js
🧠 Learnings (4)
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/lib/wapi/functions/**/*.js : WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run `npm run build:wapi` to rebuild
Applied to files:
src/lib/wapi/functions/forward-messages.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/test.jssrc/lib/wapi/functions/send-type-buttons.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/send-link-preview.jssrc/lib/wapi/functions/delete-all-message.jssrc/lib/wapi/wapi.jssrc/lib/wapi/functions/pin.chat.jssrc/lib/wapi/functions/index.jssrc/lib/wapi/functions/send-seen.jssrc/lib/wapi/functions/only-send-data-admin.jssrc/lib/wapi/functions/reply.js
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/api/layers/*.layer.ts : Keep functionality layers in src/api/layers using the *.layer.ts naming (e.g., sender.layer.ts, listener.layer.ts, group.layer.ts, profile.layer.ts, controls.layer.ts, retriever.layer.ts)
Applied to files:
src/api/layers/sender.layer.tssrc/api/layers/group.layer.ts
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/api/helpers/**/*.{ts,js} : Put utility helpers (e.g., encryption, QR code utilities) under src/api/helpers
Applied to files:
src/api/layers/sender.layer.tssrc/api/layers/group.layer.ts
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to test/index.js : Use test/index.js as the main test script; tests are basic scripts without a formal framework
Applied to files:
test/index.js
🧬 Code graph analysis (33)
src/lib/wapi/functions/get-all-messages-in-chat.js (1)
src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/poll-creation.js (13)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-all-chats.js (1)
idUser(4-4)
src/lib/wapi/functions/forward-messages.js (9)
src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/get-number-profile.js (2)
src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/set-group-description.js (12)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/send-list-menu.js (1)
chat(98-98)src/lib/wapi/functions/send-location.js (1)
chat(7-7)src/lib/wapi/functions/send-message-scope.js (1)
chat(39-39)src/lib/wapi/functions/set-group-image.js (1)
chat(13-13)src/lib/wapi/functions/set-group-settings.js (1)
chat(16-16)src/lib/wapi/functions/set-group-title.js (1)
chat(15-15)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)src/lib/wapi/business/send-message-with-buttons.js (1)
chatId(179-339)
src/lib/wapi/functions/test.js (6)
src/lib/wapi/functions/reply.js (3)
chat(26-26)newMsgId(59-59)fromwWid(60-60)src/lib/wapi/functions/send-message-scope.js (3)
chat(39-39)newMsgId(43-43)fromwWid(44-44)src/lib/wapi/functions/send-message.js (3)
chat(31-31)newMsgId(43-45)fromwWid(46-46)src/lib/wapi/functions/send-link-preview.js (2)
newMsgId(30-30)fromwWid(31-31)src/lib/wapi/functions/get-host.js (2)
window(6-6)fromwWid(2-2)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)
src/lib/wapi/functions/send-type-buttons.js (13)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/reply.js (2)
chat(26-26)fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (2)
chat(40-40)fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard.js (2)
chat(15-15)fromwWid(43-43)src/lib/wapi/functions/send-list-menu.js (2)
chat(98-98)fromwWid(102-102)src/lib/wapi/functions/send-location.js (2)
chat(7-7)fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (2)
chat(39-39)fromwWid(44-44)src/lib/wapi/functions/send-sticker.js (2)
chat(2-2)fromwWid(6-6)src/lib/wapi/functions/test.js (2)
chat(2-2)fromwWid(6-6)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)
src/lib/wapi/functions/get-group-admins.js (13)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/send-list-menu.js (1)
chat(98-98)src/lib/wapi/functions/send-location.js (1)
chat(7-7)src/lib/wapi/functions/set-group-description.js (1)
chat(15-15)src/lib/wapi/functions/set-group-settings.js (1)
chat(16-16)src/lib/wapi/functions/set-group-title.js (1)
chat(15-15)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/clear-chat.js (1)
chat(2-2)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/send-location.js (3)
src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-chat.js (2)
getChat(1-49)window(44-46)
src/lib/wapi/functions/set-profile-pic.js (2)
src/api/layers/retriever.layer.ts (1)
getProfilePicFromServer(236-241)src/api/layers/profile.layer.ts (1)
WAPI(104-104)
src/lib/wapi/functions/send-list-menu.js (6)
src/lib/wapi/functions/get-new-message-id.js (2)
chat(2-2)newMsgId(4-4)src/lib/wapi/functions/send-message.js (3)
chat(31-31)newMsgId(43-45)fromwWid(46-46)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/send-link-preview.js (2)
newMsgId(30-30)fromwWid(31-31)src/lib/wapi/functions/set-new-message.js (1)
newMsgId(12-12)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)
src/lib/wapi/functions/mark-markSeen-message.js (3)
src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)
src/lib/wapi/functions/send-link-preview.js (2)
src/lib/wapi/functions/send-contact-vcard-list.js (2)
chat(29-29)fromwWid(52-52)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)
src/lib/wapi/functions/get-all-chats.js (16)
src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/lib/wapi/functions/get-chat.js (1)
window(44-46)src/api/layers/retriever.layer.ts (1)
WAPI(349-354)
src/lib/wapi/functions/send-message-scope.js (4)
src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/reply.js (2)
chat(26-26)fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (2)
chat(40-40)fromwWid(44-44)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)
src/lib/wapi/functions/send-message.js (14)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)
src/lib/wapi/functions/get-host.js (4)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/send-message-scope.js (2)
fromwWid(44-44)chat(39-39)src/lib/wapi/functions/check-send-exist.js (2)
wid(106-106)window(107-107)src/lib/wapi/functions/send-file.js (2)
wid(59-59)chat(60-60)
src/lib/wapi/wapi.js (1)
src/lib/wapi/helper/get-me-user.js (1)
getMeUser(5-11)
src/lib/wapi/functions/get-new-message-id.js (3)
src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)src/api/layers/retriever.layer.ts (2)
chatId(62-62)getNewMessageId(44-70)
src/lib/wapi/functions/send-contact-vcard-list.js (7)
src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/reply.js (2)
chat(26-26)fromwWid(60-60)src/lib/wapi/functions/send-contact-vcard.js (2)
chat(15-15)fromwWid(43-43)src/lib/wapi/functions/send-list-menu.js (2)
chat(98-98)fromwWid(102-102)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/demote-participant.js (1)
dist/lib/wapi/wapi.js (5)
c(1-1)c(1-1)c(1-1)c(1-1)c(1-1)
src/lib/wapi/helper/filter-object.js (1)
src/lib/wapi/wapi.js (1)
module(166-166)
src/lib/wapi/functions/get-data-messages.js (18)
src/lib/wapi/functions/add-participant.js (1)
chat(2-2)src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/demote-participant.js (1)
chat(2-2)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)src/lib/wapi/functions/only-send-admin.js (1)
chat(9-9)src/lib/wapi/functions/send-message-scope.js (1)
chat(39-39)src/lib/wapi/functions/set-group-description.js (1)
chat(15-15)src/lib/wapi/functions/set-group-image.js (1)
chat(13-13)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)src/api/layers/retriever.layer.ts (3)
WAPI(330-331)WAPI(349-354)getAllMessagesInChat(324-334)
src/lib/wapi/functions/pin.chat.js (1)
src/lib/wapi/functions/get-chat.js (2)
getChat(1-49)window(44-46)
src/lib/wapi/functions/promote-participant.js (1)
dist/lib/wapi/wapi.js (5)
c(1-1)c(1-1)c(1-1)c(1-1)c(1-1)
src/lib/wapi/functions/sendMessageOptions.js (15)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/api/model/message.ts (1)
Sender(83-101)
src/lib/wapi/functions/send-file.js (17)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/api/whatsapp.ts (2)
WAPI(136-136)() => undefined(166-166)src/types/WAPI.d.ts (1)
WAPI(14-271)
src/lib/wapi/functions/check-send-exist.js (3)
src/lib/wapi/functions/get-host.js (2)
wid(4-4)window(6-6)src/lib/wapi/functions/load-earlier-chat-messages.js (1)
chat(2-2)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/set-group-title.js (3)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/send-list-menu.js (1)
chat(98-98)
src/lib/wapi/functions/set-new-message.js (5)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/archive-chat.js (14)
src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)src/lib/wapi/functions/only-send-admin.js (1)
chat(9-9)src/lib/wapi/functions/open-chat.js (3)
chat(7-7)chat(16-16)chat(18-18)src/lib/wapi/functions/get-all-chats.js (1)
idUser(4-4)src/api/layers/controls.layer.ts (2)
archiveChat(124-129)WAPI(126-126)
src/lib/wapi/functions/only-send-data-admin.js (16)
src/lib/wapi/functions/add-participant.js (1)
chat(2-2)src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/demote-participant.js (1)
chat(2-2)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)src/lib/wapi/functions/only-send-admin.js (1)
chat(9-9)src/lib/wapi/functions/open-chat.js (2)
chat(7-7)chat(16-16)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/reply.js (4)
src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| contactsId = await Promise.all(contactsId.map((c) => WAPI.findChat(c))); | ||
| if (!contactsId.length) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Missing filter for failed chat lookups.
findChat returns an error scope object (with status === 404) when the contact isn't found. Unlike create-group.js which filters results with contactsId.filter((c) => !c.erro && c.isUser), this code passes all results directly to addParticipants, including failed lookups. Additionally, the check !contactsId.length on line 9 will never be true since Promise.all preserves the input array length.
Proposed fix to filter invalid results
contactsId = await Promise.all(contactsId.map((c) => WAPI.findChat(c)));
+ contactsId = contactsId.filter((c) => c && !c.erro && c.id);
if (!contactsId.length) {
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.
| contactsId = await Promise.all(contactsId.map((c) => WAPI.findChat(c))); | |
| if (!contactsId.length) { | |
| return false; | |
| } | |
| contactsId = await Promise.all(contactsId.map((c) => WAPI.findChat(c))); | |
| contactsId = contactsId.filter((c) => c && !c.erro && c.id); | |
| if (!contactsId.length) { | |
| return false; | |
| } |
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/add-participant.js` around lines 8 - 11, The code maps
contactsId via WAPI.findChat then immediately checks length and passes results
to addParticipants, but Promise.all preserves input length and findChat can
return error objects (status === 404); update the flow to filter the Promise.all
results (for example filter out entries where c.erro is truthy or c.isUser is
false) before calling addParticipants and change the emptiness check to use the
filtered array (return false if filtered.length === 0); locate the logic around
contactsId, WAPI.findChat, and the call to addParticipants in add-participant.js
to implement this filtering and adjusted check (mirroring the pattern used in
create-group.js).
| export async function findChat(chatId) { | ||
| const checkType = WAPI.sendCheckType(chatId); | ||
| if (!!checkType && checkType.status === 404) { | ||
| if (checkType && checkType.status === 404) { | ||
| return checkType; | ||
| } | ||
|
|
||
| let chat = await WAPI.getChat(chatId); | ||
| if (!chat) { | ||
| var idUser = new Store.UserConstructor(chatId, { | ||
| intentionallyUsePrivateConstructor: true | ||
| }); | ||
| const chatWid = new Store.WidFactory.createWid(chatId); | ||
| await Store.Chat.add( | ||
| { | ||
| createdLocally: true, | ||
| id: chatWid | ||
| }, | ||
| { | ||
| merge: true | ||
| } | ||
| ); | ||
| chat = await Store.Chat.find(idUser); | ||
| } | ||
|
|
||
| if (chat === undefined) { | ||
| const chatWid = new Store.WidFactory.createWid(chatId); | ||
| await Store.Chat.add( | ||
| { | ||
| createdLocally: true, | ||
| id: chatWid | ||
| }, | ||
| { | ||
| merge: true | ||
| } | ||
| ); | ||
| const storeChat = await Store.Chat.find(chatId); | ||
| if (storeChat) { | ||
| chat = | ||
| storeChat && storeChat.id && storeChat.id._serialized | ||
| ? await WAPI.getChat(storeChat.id._serialized) | ||
| : undefined; | ||
| } | ||
| } | ||
|
|
||
| if (!chat) { | ||
| return WAPI.scope(chatId, true, 404); | ||
| } | ||
|
|
||
| if (Send) { | ||
| await window.Store.ReadSeen.sendSeen(chat, false); | ||
| } | ||
|
|
||
| if (returnChat) { | ||
| return chat; | ||
| } | ||
|
|
||
| return WAPI.scope(chatId, false, 200); | ||
| } | ||
|
|
||
| export async function sendExist(chatId, returnChat = true, Send = true) { | ||
| const checkType = await WAPI.sendCheckType(chatId); | ||
| if (!!checkType && checkType.status === 404) { | ||
| return checkType; | ||
| } | ||
|
|
||
| let ck = await window.WAPI.checkNumberStatus(chatId, false); | ||
|
|
||
| if ( | ||
| (ck.status === 404 && | ||
| !chatId.includes('@g.us') && | ||
| !chatId.includes('@broadcast')) || | ||
| (ck && | ||
| ck.text && | ||
| typeof ck.text.includes === 'function' && | ||
| ck.text.includes('XmppParsingFailure')) | ||
| ) { | ||
| return WAPI.scope(chatId, true, ck.status, 'The number does not exist'); | ||
| } | ||
|
|
||
| const chatWid = new Store.WidFactory.createWid(chatId); | ||
|
|
||
| let chat = | ||
| ck && ck.id && ck.id._serialized | ||
| ? await WAPI.getChat(ck.id._serialized) | ||
| : undefined; | ||
|
|
||
| if (ck.numberExists && chat === undefined) { | ||
| var idUser = new Store.UserConstructor(chatId, { | ||
| intentionallyUsePrivateConstructor: true | ||
| }); | ||
| const chatWid = new Store.WidFactory.createWid(chatId); | ||
| await Store.Chat.add( | ||
| { | ||
| createdLocally: true, | ||
| id: chatWid | ||
| }, | ||
| { | ||
| merge: true | ||
| } | ||
| ); | ||
| chat = await Store.Chat.find(idUser); | ||
| } | ||
|
|
||
| if (!chat) { | ||
| const storeChat = await Store.Chat.find(chatWid); | ||
| if (storeChat) { | ||
| chat = | ||
| storeChat && storeChat.id && storeChat.id._serialized | ||
| ? await WAPI.getChat(storeChat.id._serialized) | ||
| : undefined; | ||
| try { | ||
| const wid = window.Store.WidFactory.createWid(chatId); | ||
| const { chat } = await window.Store.FindOrCreateChat.findOrCreateLatestChat(wid); | ||
| if (chat) { | ||
| return chat; | ||
| } | ||
| } catch (err) { | ||
| window.onLog(`findChat error for ${chatId}: ${err?.message || err}`); | ||
| } | ||
|
|
||
| if (!chat) { | ||
| return WAPI.scope(chatId, true, 404); | ||
| } | ||
|
|
||
| if (!ck.numberExists && !chat.t && chat.isUser) { | ||
| return WAPI.scope(chatId, true, ck.status, 'The number does not exist'); | ||
| } | ||
|
|
||
| if (!ck.numberExists && !chat.t && chat.isGroup) { | ||
| return WAPI.scope( | ||
| chatId, | ||
| true, | ||
| ck.status, | ||
| 'The group number does not exist on your chat list, or it does not exist at all!' | ||
| ); | ||
| } | ||
|
|
||
| if ( | ||
| !ck.numberExists && | ||
| !chat.t && | ||
| chat.id && | ||
| chat.id.user != 'status' && | ||
| chat.isBroadcast | ||
| ) { | ||
| return WAPI.scope( | ||
| chatId, | ||
| true, | ||
| ck.status, | ||
| 'The transmission list number does not exist on your chat list, or it does not exist at all!' | ||
| ); | ||
| } | ||
|
|
||
| if (Send) { | ||
| await window.Store.ReadSeen.sendSeen(chat, false); | ||
| } | ||
|
|
||
| if (returnChat) { | ||
| return chat; | ||
| } | ||
|
|
||
| return WAPI.scope(chatId, false, 200); | ||
| return WAPI.scope(chatId, true, 404, 'Chat not found'); |
There was a problem hiding this comment.
Await validation and WID creation in findChat.
Line 100 calls WAPI.sendCheckType which returns a Promise (via async WAPI.scope), so without await invalid IDs can skip validation. Line 106 should await WidFactory.createWid to match usage in src/lib/wapi/functions/get-chat.js and avoid passing a Promise into findOrCreateLatestChat.
🛠️ Proposed fix
-export async function findChat(chatId) {
- const checkType = WAPI.sendCheckType(chatId);
+export async function findChat(chatId) {
+ const checkType = await WAPI.sendCheckType(chatId);
if (checkType && checkType.status === 404) {
return checkType;
}
try {
- const wid = window.Store.WidFactory.createWid(chatId);
+ const wid = await window.Store.WidFactory.createWid(chatId);
const { chat } = await window.Store.FindOrCreateChat.findOrCreateLatestChat(wid);
if (chat) {
return chat;
}
} catch (err) {Also, since this file lives under src/lib/wapi/functions, remember to run npm run build:wapi after changes. Based on learnings, this is required for WAPI injection rebuilds.
📝 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 findChat(chatId) { | |
| const checkType = WAPI.sendCheckType(chatId); | |
| if (!!checkType && checkType.status === 404) { | |
| if (checkType && checkType.status === 404) { | |
| return checkType; | |
| } | |
| let chat = await WAPI.getChat(chatId); | |
| if (!chat) { | |
| var idUser = new Store.UserConstructor(chatId, { | |
| intentionallyUsePrivateConstructor: true | |
| }); | |
| const chatWid = new Store.WidFactory.createWid(chatId); | |
| await Store.Chat.add( | |
| { | |
| createdLocally: true, | |
| id: chatWid | |
| }, | |
| { | |
| merge: true | |
| } | |
| ); | |
| chat = await Store.Chat.find(idUser); | |
| } | |
| if (chat === undefined) { | |
| const chatWid = new Store.WidFactory.createWid(chatId); | |
| await Store.Chat.add( | |
| { | |
| createdLocally: true, | |
| id: chatWid | |
| }, | |
| { | |
| merge: true | |
| } | |
| ); | |
| const storeChat = await Store.Chat.find(chatId); | |
| if (storeChat) { | |
| chat = | |
| storeChat && storeChat.id && storeChat.id._serialized | |
| ? await WAPI.getChat(storeChat.id._serialized) | |
| : undefined; | |
| } | |
| } | |
| if (!chat) { | |
| return WAPI.scope(chatId, true, 404); | |
| } | |
| if (Send) { | |
| await window.Store.ReadSeen.sendSeen(chat, false); | |
| } | |
| if (returnChat) { | |
| return chat; | |
| } | |
| return WAPI.scope(chatId, false, 200); | |
| } | |
| export async function sendExist(chatId, returnChat = true, Send = true) { | |
| const checkType = await WAPI.sendCheckType(chatId); | |
| if (!!checkType && checkType.status === 404) { | |
| return checkType; | |
| } | |
| let ck = await window.WAPI.checkNumberStatus(chatId, false); | |
| if ( | |
| (ck.status === 404 && | |
| !chatId.includes('@g.us') && | |
| !chatId.includes('@broadcast')) || | |
| (ck && | |
| ck.text && | |
| typeof ck.text.includes === 'function' && | |
| ck.text.includes('XmppParsingFailure')) | |
| ) { | |
| return WAPI.scope(chatId, true, ck.status, 'The number does not exist'); | |
| } | |
| const chatWid = new Store.WidFactory.createWid(chatId); | |
| let chat = | |
| ck && ck.id && ck.id._serialized | |
| ? await WAPI.getChat(ck.id._serialized) | |
| : undefined; | |
| if (ck.numberExists && chat === undefined) { | |
| var idUser = new Store.UserConstructor(chatId, { | |
| intentionallyUsePrivateConstructor: true | |
| }); | |
| const chatWid = new Store.WidFactory.createWid(chatId); | |
| await Store.Chat.add( | |
| { | |
| createdLocally: true, | |
| id: chatWid | |
| }, | |
| { | |
| merge: true | |
| } | |
| ); | |
| chat = await Store.Chat.find(idUser); | |
| } | |
| if (!chat) { | |
| const storeChat = await Store.Chat.find(chatWid); | |
| if (storeChat) { | |
| chat = | |
| storeChat && storeChat.id && storeChat.id._serialized | |
| ? await WAPI.getChat(storeChat.id._serialized) | |
| : undefined; | |
| try { | |
| const wid = window.Store.WidFactory.createWid(chatId); | |
| const { chat } = await window.Store.FindOrCreateChat.findOrCreateLatestChat(wid); | |
| if (chat) { | |
| return chat; | |
| } | |
| } catch (err) { | |
| window.onLog(`findChat error for ${chatId}: ${err?.message || err}`); | |
| } | |
| if (!chat) { | |
| return WAPI.scope(chatId, true, 404); | |
| } | |
| if (!ck.numberExists && !chat.t && chat.isUser) { | |
| return WAPI.scope(chatId, true, ck.status, 'The number does not exist'); | |
| } | |
| if (!ck.numberExists && !chat.t && chat.isGroup) { | |
| return WAPI.scope( | |
| chatId, | |
| true, | |
| ck.status, | |
| 'The group number does not exist on your chat list, or it does not exist at all!' | |
| ); | |
| } | |
| if ( | |
| !ck.numberExists && | |
| !chat.t && | |
| chat.id && | |
| chat.id.user != 'status' && | |
| chat.isBroadcast | |
| ) { | |
| return WAPI.scope( | |
| chatId, | |
| true, | |
| ck.status, | |
| 'The transmission list number does not exist on your chat list, or it does not exist at all!' | |
| ); | |
| } | |
| if (Send) { | |
| await window.Store.ReadSeen.sendSeen(chat, false); | |
| } | |
| if (returnChat) { | |
| return chat; | |
| } | |
| return WAPI.scope(chatId, false, 200); | |
| return WAPI.scope(chatId, true, 404, 'Chat not found'); | |
| export async function findChat(chatId) { | |
| const checkType = await WAPI.sendCheckType(chatId); | |
| if (checkType && checkType.status === 404) { | |
| return checkType; | |
| } | |
| try { | |
| const wid = await window.Store.WidFactory.createWid(chatId); | |
| const { chat } = await window.Store.FindOrCreateChat.findOrCreateLatestChat(wid); | |
| if (chat) { | |
| return chat; | |
| } | |
| } catch (err) { | |
| window.onLog(`findChat error for ${chatId}: ${err?.message || err}`); | |
| } | |
| return WAPI.scope(chatId, true, 404, 'Chat not found'); |
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/check-send-exist.js` around lines 99 - 115, The
findChat function is not awaiting async results: await
WAPI.sendCheckType(chatId) should be used so invalid IDs don't bypass
validation, and await window.Store.WidFactory.createWid(chatId) should be used
so findOrCreateLatestChat receives a Wid (not a Promise); update findChat to
await both WAPI.sendCheckType and WidFactory.createWid (keeping the try/catch
and returning WAPI.scope(...) on failure) to mirror the usage in get-chat.js.
| const chat = await WAPI.findChat(chatId); | ||
| if (chat && chat.status != 404) { |
There was a problem hiding this comment.
Inconsistent error handling pattern with findChat.
This file uses chat && chat.status != 404 for error checking, while other files in this PR (e.g., send-contact-vcard-list.js, send-seen.js) use !chat.erro. This inconsistency suggests that either:
findChatreturns different error structures in different scenarios, or- Some files haven't been fully migrated to the correct error handling pattern
Consider standardizing the error check across all files to ensure consistent behavior.
Suggested verification
#!/bin/bash
# Find all error handling patterns after findChat calls
rg -n "findChat" --type js -A 2 src/lib/wapi/functions/ | rg -A 1 "findChat"🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/delete-all-message.js` around lines 10 - 11, The error
check after calling findChat uses "chat && chat.status != 404" which is
inconsistent with the rest of the codebase that checks for "!chat.erro"; update
the check in the delete-all-message handler to the standard pattern (e.g., if
(chat && !chat.erro) or simply if (!chat.erro) after ensuring chat is defined)
so it matches send-contact-vcard-list.js and send-seen.js; locate the findChat
call and the "chat" variable in delete-all-message.js and replace the
status-based check with the erro-based check, and run a quick grep for other
findChat usages to ensure consistency across files.
| ); | ||
| } | ||
| const chat = await WAPI.sendExist(chatId); | ||
| const chat = await WAPI.findChat(chatId); |
There was a problem hiding this comment.
Guard against falsy chat from findChat before dereferencing.
findChat can return a falsy value for invalid IDs; the current else branch will throw when accessing chat.erro. Add a null check and return a scoped error instead.
🛠️ Proposed fix
- } else {
- if (!chat.erro) {
- chat.erro = true;
- }
- return chat;
- }
+ } else {
+ if (!chat || typeof chat !== 'object') {
+ return WAPI.scope(chatId, true, 404, 'Chat not found');
+ }
+ if (!chat.erro) {
+ chat.erro = true;
+ }
+ return chat;
+ }Also applies to: 75-79
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/delete-messages.js` at line 10, The call to
WAPI.findChat can return falsy and the code later dereferences chat (e.g.,
accessing chat.erro), so add a null check immediately after "const chat = await
WAPI.findChat(chatId)" to handle missing chats: if chat is falsy, return a
scoped error result object (consistent with the function's return shape)
indicating the chatId was not found instead of continuing; apply the same guard
where chat is used later (the block around lines 75-79) to prevent dereference
errors.
| var chat = await WAPI.findChat(chatId); | ||
| if (!chat.erro) { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd src/lib/wapi/functions && find . -name "fix-chat.js" -type fRepository: venomlib/venom
Length of output: 71
🏁 Script executed:
cat -n src/lib/wapi/functions/fix-chat.jsRepository: venomlib/venom
Length of output: 1165
🏁 Script executed:
rg -A 5 -B 5 "findChat" src/lib/wapi/functions/ --type js | head -100Repository: venomlib/venom
Length of output: 7271
🏁 Script executed:
rg "status.*404|404.*status" src/lib/wapi/ --type js | head -30Repository: venomlib/venom
Length of output: 2568
🏁 Script executed:
rg "\.erro" src/lib/wapi/functions/ --type js -A 2 -B 2 | head -50Repository: venomlib/venom
Length of output: 2842
Standardize error check to match codebase pattern.
fix-chat.js uses if (!chat.erro) while the rest of the codebase checks chat.status !== 404 (present in 20+ functions). This inconsistency creates a validation gap. Replace with the standard pattern used elsewhere:
- if (!chat.erro) {
+ if (chat && chat.status != 404) {Or include chat.id check if pinning requires a valid chat ID, matching the pattern in pin.chat.js and other message functions.
📝 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.
| var chat = await WAPI.findChat(chatId); | |
| if (!chat.erro) { | |
| var chat = await WAPI.findChat(chatId); | |
| if (chat && chat.status != 404) { |
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/fix-chat.js` around lines 8 - 9, The error check in
fix-chat.js uses the nonstandard condition "if (!chat.erro)"; update the
validation to match the codebase pattern by checking "chat.status !== 404" after
calling WAPI.findChat(chatId), and also ensure a valid chat id is present (e.g.,
verify chat.id) if pinning requires it—mirror the checks used in pin.chat.js and
other message functions to maintain consistency and avoid the validation gap.
| export async function getNewMessageId(chatId, checkNumber = true) { | ||
| const chat = checkNumber | ||
| ? await WAPI.sendExist(chatId) | ||
| : await WAPI.returnChat(chatId); | ||
| const chat = await WAPI.findChat(chatId); | ||
| if (chat.id) { | ||
| const newMsgId = new Object(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/lib/wapi/functions/get-new-message-id.jsRepository: venomlib/venom
Length of output: 661
🏁 Script executed:
rg -nP --type=js --type=ts 'getNewMessageId' -C 3Repository: venomlib/venom
Length of output: 50371
🏁 Script executed:
rg -nP --type=js --type=ts -C 2 '\bgetNewMessageId\s*\([^)]*,\s*false\b'Repository: venomlib/venom
Length of output: 40
Add null guard and remove the unused checkNumber parameter.
Line 3 accesses chat.id without verifying chat exists—if findChat returns falsy, this throws. The checkNumber parameter is declared but never used in the function, and no callers pass checkNumber = false.
Fix: Change if (chat.id) to if (chat && chat.id) on line 3, and remove the unused checkNumber parameter from line 1.
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/get-new-message-id.js` around lines 1 - 4, In
getNewMessageId, add a null guard for the result of WAPI.findChat by changing
the conditional to check both chat and chat.id (e.g., if (chat && chat.id)) to
avoid throwing when findChat returns falsy, and remove the unused parameter
checkNumber from the function signature (export async function
getNewMessageId(chatId)) as it is never used; update any internal references
within getNewMessageId (e.g., newMsgId creation/logic) accordingly and run tests
to ensure callers remain compatible.
| */ | ||
| export async function markUnseenMessage(id) { | ||
| const chat = await WAPI.sendExist(id); | ||
| const chat = await WAPI.findChat(id); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/lib/wapi/functions/mark-unseen-message.jsRepository: venomlib/venom
Length of output: 507
🏁 Script executed:
# Search for findChat implementation in WAPI
rg -A 10 "findChat\s*[:=]" src/lib/wapiRepository: venomlib/venom
Length of output: 625
🏁 Script executed:
# Look for other files that use findChat to understand its return contract
rg "WAPI\.findChat|\.findChat" src/lib/wapi/functions -B 2 -A 5 | head -100Repository: venomlib/venom
Length of output: 7248
🏁 Script executed:
# Find the findChat function definition
rg -B 5 -A 15 "function findChat|const findChat" src/lib/wapi --type jsRepository: venomlib/venom
Length of output: 1436
Guard against falsy values returned by findChat.
WAPI.findChat(id) returns undefined on failure (when chat is not found or an error occurs). Accessing chat.erro without a null check will throw a TypeError.
🛠️ Proposed fix
export async function markUnseenMessage(id) {
const chat = await WAPI.findChat(id);
- if (!chat.erro) {
- await Store.ReadSeen.markUnread(chat, true);
- return WAPI.scope(undefined, false, 'OK', null);
- } else {
- return WAPI.scope(undefined, true, 'Error', null);
- }
+ if (!chat || chat.erro) {
+ return WAPI.scope(undefined, true, 'Error', null);
+ }
+ await Store.ReadSeen.markUnread(chat, true);
+ return WAPI.scope(undefined, false, 'OK', null);
}🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/mark-unseen-message.js` at line 7, WAPI.findChat(id)
can return undefined, so update the mark-unseen-message logic to guard against a
falsy chat before accessing chat.erro: after calling WAPI.findChat(id) check
that the returned chat is truthy (e.g., if (!chat) { handle/not-found path or
return false }) and only then read chat.erro and proceed with setting isUnseen;
reference the WAPI.findChat call and the chat.erro access in
mark-unseen-message.js and ensure the function returns or handles the
missing-chat case gracefully.
| if (chat && chat.status != 404 && chat.id) { | ||
| const chat = await WAPI.sendExist(chat); | ||
| const chatObj = await WAPI.findChat(chat); | ||
| try { | ||
| await Store.onlySendAdmin.sendSetGroupProperty(chat.id, `restrict`, type); | ||
| return WAPI.scope(chat, false, 200, 'successfully changed'); |
There was a problem hiding this comment.
Use the resolved chat object; current flow can pass undefined IDs.
chatObj is resolved but ignored; sendSetGroupProperty(chat.id, ...) can pass undefined when chat is a string. This is a functional regression.
🔧 Proposed fix
- if (chat && chat.status != 404 && chat.id) {
- const chatObj = await WAPI.findChat(chat);
+ const chatObj = await WAPI.findChat(chat);
+ if (chatObj && chatObj.status != 404 && chatObj.id) {
try {
- await Store.onlySendAdmin.sendSetGroupProperty(chat.id, `restrict`, type);
+ await Store.onlySendAdmin.sendSetGroupProperty(
+ chatObj.id,
+ `restrict`,
+ type
+ );
return WAPI.scope(chat, false, 200, 'successfully changed');🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/only-send-data-admin.js` around lines 10 - 14, The
code calls WAPI.findChat(chat) but then uses the original chat variable for the
group ID, which can be a string and lead to undefined IDs; update the flow in
only-send-data-admin.js to use the resolved chatObj (from WAPI.findChat) for the
ID passed to Store.onlySendAdmin.sendSetGroupProperty (i.e., use chatObj.id),
and add a guard to handle when chatObj is falsy before calling
sendSetGroupProperty and before returning via WAPI.scope to avoid passing
undefined IDs.
test/index.js
Outdated
| .run(); | ||
|
|
||
| .run(); */ | ||
| await client.sendText('16036627490@c.us', 'Hi there'); |
There was a problem hiding this comment.
Hardcoded phone number in test script poses privacy and operational risks.
This line will send a real WhatsApp message to what appears to be an actual phone number (16036627490) when the test runs. This raises concerns:
- PII in source code — The phone number should not be committed to the repository.
- Unintended messages — Running this test sends unsolicited messages to a real recipient.
Use an environment variable or a clearly documented test/mock number instead.
Suggested fix using environment variable
- await client.sendText('16036627490@c.us', 'Hi there');
+ const testNumber = process.env.TEST_PHONE_NUMBER;
+ if (testNumber) {
+ await client.sendText(`${testNumber}@c.us`, 'Hi there');
+ }📝 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 client.sendText('16036627490@c.us', 'Hi there'); | |
| const testNumber = process.env.TEST_PHONE_NUMBER; | |
| if (testNumber) { | |
| await client.sendText(`${testNumber}@c.us`, 'Hi there'); | |
| } |
🤖 Prompt for AI Agents
In `@test/index.js` at line 48, Replace the hardcoded recipient in the test that
calls client.sendText(...) with a configurable value: stop committing PII by
reading the destination number from an environment variable (e.g.,
process.env.TEST_WHATSAPP_NUMBER) or a test-only constant/mock, and update the
test harness to validate the variable is set (or skip the integration send when
not present); locate the call to client.sendText in test/index.js and refactor
it to use the env variable or mock-number and document the required env var in
the test README.
c5ec758 to
01fe8ad
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/lib/wapi/functions/remove-participant.js (1)
8-13: Verify thatfindChatreturns contact objects compatible with the filter and subsequent participant lookup.The change from
WAPI.sendExisttoWAPI.findChatintroduces a critical compatibility issue. ThefindChatfunction returns either:
- Error objects from
WAPI.scope(witherro: truebut noisUserproperty)- Chat objects from
Store.FindOrCreateChat.findOrCreateLatestChat(structure unclear)However, line 10 filters on
.filter((c) => !c.erro && c.isUser), which requires theisUserproperty on successfully returned objects. Error objects fromWAPI.scopedo not have this property.More critically, line 11 assumes the filtered objects are contact/user references:
.map((c) => chat.groupMetadata.participants.get(c.id)). This suggests the code expects contact objects with anidthat corresponds to participant IDs, butfindChatreturns chat objects, creating a semantic mismatch.Verify that:
- Chat objects returned by
findChathave anisUserproperty or alternative way to identify users- The
idproperty on returned objects maps correctly to participant IDs ingroupMetadata.participants- This change was tested with actual participant operations (add, remove, promote, demote)
Note: This pattern is also used identically in
promote-participant.js,demote-participant.js, andadd-participant.js, so the fix must be consistent across all these files.src/lib/wapi/functions/open-chat.js (1)
16-25: Guard against undefined chat before accessingchat.erro.
WAPI.findChat(chatId)can returnundefinedon failure. If the condition on line 17 is false andchatisundefined, accessingchat.erroon line 22 will throw aTypeError.Also, the variable shadowing on line 18 (
const chat = Store.Chat.get(chatId)) obscures the outerchatfromfindChat, which is confusing.🛠️ Proposed fix
const chat = await WAPI.findChat(chatId); - if (chat && chat.status != 404 && chat.id) { - const chat = Store.Chat.get(chatId); - const result = Store.Cmd.default.openChatBottom(chat); + if (chat && chat.status !== 404 && chat.id) { + const storeChat = Store.Chat.get(chatId); + const result = Store.Cmd.default.openChatBottom(storeChat); return WAPI.scope(undefined, false, result); } - if (!chat.erro) { + if (!chat || !chat.erro) { chat.erro = true; } return chat;src/lib/wapi/functions/poll-creation.js (1)
37-50: Add null guard in the else block to prevent potential TypeError.The refactor to
WAPI.findChatis correct, and line 38 properly guards the success path. However, the else block at lines 45-49 accesseschat.errorwithout checking ifchatis truthy. IffindChatreturnsnullorundefined, accessingchat.errorwill throw a TypeError.🐛 Proposed fix
} else { - if (!chat.error) { + if (chat && !chat.error) { chat.error = true; } return chat; }src/lib/wapi/functions/set-new-message.js (1)
1-1: Remove unusedcheckNumberparameter and update callers.The
checkNumberparameter is declared but never used in the function body. This requires updating the function signature and the two callers insend-file.jsandsend-ppt.jsthat pass this parameter.♻️ Proposed changes
src/lib/wapi/functions/set-new-message.js:
-export async function setNewMessageId(info, checkNumber = true) { +export async function setNewMessageId(info) {src/lib/wapi/functions/send-file.js (line 92):
- : await window.WAPI.setNewMessageId(passId, checkNumber); + : await window.WAPI.setNewMessageId(passId);src/lib/wapi/functions/send-ppt.js (line 54):
- : await window.WAPI.setNewMessageId(passId, checkNumber); + : await window.WAPI.setNewMessageId(passId);
🤖 Fix all issues with AI agents
In `@src/lib/wapi/functions/send-contact-vcard.js`:
- Around line 15-16: Replace the use of WAPI.findChat(contact) with
window.Store.Contact.get(contact) when retrieving the contact in
send-contact-vcard.js (currently using WAPI.findChat); ensure you pass the
actual contact model (with its __x_contact) into vcardFromContactModel, and add
a guard that validates the returned contact object has the __x_contact field
before dereferencing it (return or throw/log an error if missing) to mirror how
sendMessageOptions.js retrieves contacts.
In `@src/lib/wapi/functions/set-new-message.js`:
- Around line 9-11: The code calls WAPI.findChat(...) and directly checks
chat.id which can throw if chat is null/undefined; update the conditional in
set-new-message.js to guard the chat object (e.g., use if (chat && chat.id) or
if (chat?.id)) so you only access chat.id when chat is truthy; ensure you locate
the WAPI.findChat call and the subsequent if (chat.id) check and replace it with
the guarded form to match patterns used in poll-creation.js and
get-all-chats.js.
♻️ Duplicate comments (4)
src/lib/wapi/functions/mark-unseen-message.js (1)
7-8: Guard against falsy values returned byfindChat.
WAPI.findChat(id)returnsundefinedon failure. Accessingchat.errowithout a null check will throw aTypeError.src/lib/wapi/functions/get-new-message-id.js (1)
1-13: Missing null guard and unused parameter still present.The issues identified in the previous review remain unaddressed:
- Line 3 accesses
chat.idwithout verifyingchatexists—iffindChatreturns falsy, this throws a TypeError.- The
checkNumberparameter on line 1 is declared but never used after the refactor to always usefindChat.src/lib/wapi/functions/delete-messages.js (1)
10-79: Guard against falsychatbefore dereferencing.
WhenfindChatfails, the else branch can throw onchat.erro. Add a null/type guard and return a scoped error instead.🛠️ Proposed fix
} else { - if (!chat.erro) { - chat.erro = true; - } - return chat; + if (!chat || typeof chat !== 'object') { + return WAPI.scope(chatId, true, 404, 'Chat not found'); + } + if (!chat.erro) { + chat.erro = true; + } + return chat; }src/lib/wapi/functions/check-send-exist.js (1)
99-107: AwaitsendCheckTypeandcreateWidinfindChat.
sendCheckTypereturns an async scope object andcreateWidis awaited inget-chat.js; withoutawait, invalid IDs can bypass validation andfindOrCreateLatestChatmay receive a Promise.🛠️ Proposed fix
export async function findChat(chatId) { - const checkType = WAPI.sendCheckType(chatId); + const checkType = await WAPI.sendCheckType(chatId); if (checkType && checkType.status === 404) { return checkType; } try { - const wid = window.Store.WidFactory.createWid(chatId); + const wid = await window.Store.WidFactory.createWid(chatId); const { chat } = await window.Store.FindOrCreateChat.findOrCreateLatestChat(wid); if (chat) { return chat; }Also applies to: 111-115
🧹 Nitpick comments (4)
test/index.js (2)
19-21: Unused variablefafter commenting out the log.The
getHostDevice()result is assigned tofbut now goes unused. Either remove the assignment entirely or keep the log for debugging purposes.- const f = await client.getHostDevice(); console.log(await client.getWAVersion()); - //console.log(f); + // const f = await client.getHostDevice(); + // console.log(f);
2-2: Unused import and large commented code block.With the FFmpeg pipeline commented out, the
fluent-ffmpegimport at line 2 becomes dead code. Large commented blocks are generally discouraged—if this test path is deprecated in favor of the new Vitest unit tests, consider removing it entirely rather than leaving it commented.If this code is intentionally preserved for future reference or occasional manual testing, consider:
- Moving it to a separate file (e.g.,
test/ffmpeg-manual-test.js)- Adding a brief comment explaining why it's disabled
♻️ Suggested cleanup if FFmpeg test is no longer needed
import venom from '../dist/index.mjs'; -import ffmpeg from 'fluent-ffmpeg'; venom .create({And remove lines 26-47 entirely.
Also applies to: 26-47
src/lib/wapi/functions/remove-participant.js (1)
28-29: Pre-existing: Callback receivesfalseon success, inconsistent with return value.This wasn't introduced by the current change, but the callback
done(false)on line 28 contradicts thereturn trueon line 29. Typically you'd expectdone(true)for a successful operation to match the return value.♻️ Optional fix for callback consistency
- if (typeof done === 'function') done(false); + if (typeof done === 'function') done(true); return true;src/lib/wapi/functions/send-seen.js (1)
3-14: Pre-existing issue: Return values from Promise handlers are discarded.The
.then()and.catch()handlers returnWAPI.scope(...)values, but these are not captured. The function always returnstrue(line 11) regardless of whethermarkUnreadsucceeded or failed. Consider capturing and returning the result if the caller needs to distinguish success from failure.This is a pre-existing issue, not introduced by this PR.
Suggested fix
export async function sendSeen(id, done) { const chat = await WAPI.findChat(id); if (!chat.erro) { - await Store.ReadSeen.markUnread(chat, false) + return await Store.ReadSeen.markUnread(chat, false) .then(() => { - return WAPI.scope(undefined, false, 'OK', null); + return true; }) .catch(() => { - return WAPI.scope(undefined, true, 'Error', null); + return false; }); - return true; } else { return false; } }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
dist/cjs/api/layers/group.layer.jsis excluded by!**/dist/**dist/cjs/api/layers/group.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/cjs/api/layers/sender.layer.jsis excluded by!**/dist/**dist/cjs/api/layers/sender.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/esm/api/layers/group.layer.jsis excluded by!**/dist/**dist/esm/api/layers/group.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/esm/api/layers/sender.layer.jsis excluded by!**/dist/**dist/esm/api/layers/sender.layer.js.mapis excluded by!**/dist/**,!**/*.mapdist/lib/wapi/wapi.jsis excluded by!**/dist/**package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (58)
src/api/layers/group.layer.tssrc/api/layers/sender.layer.tssrc/lib/wapi/functions/add-participant.jssrc/lib/wapi/functions/archive-chat.jssrc/lib/wapi/functions/check-id-messagem.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/create-group.jssrc/lib/wapi/functions/delete-all-message.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/demote-participant.jssrc/lib/wapi/functions/fix-chat.jssrc/lib/wapi/functions/forward-messages.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/get-all-messages-in-chat.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/get-group-admins.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/get-number-profile.jssrc/lib/wapi/functions/index.jssrc/lib/wapi/functions/mark-markSeen-message.jssrc/lib/wapi/functions/mark-unseen-message.jssrc/lib/wapi/functions/only-send-admin.jssrc/lib/wapi/functions/only-send-data-admin.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/functions/pin.chat.jssrc/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/promote-participant.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/reply.jssrc/lib/wapi/functions/send-buttons.jssrc/lib/wapi/functions/send-contact-vcard-list.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/send-file.jssrc/lib/wapi/functions/send-link-preview.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/send-mute.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/send-seen.jssrc/lib/wapi/functions/send-sticker.jssrc/lib/wapi/functions/send-type-buttons.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/set-group-title.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/set-profile-pic.jssrc/lib/wapi/functions/simulate-status-chat.jssrc/lib/wapi/functions/test.jssrc/lib/wapi/helper/filter-object.jssrc/lib/wapi/helper/get-me-user.jssrc/lib/wapi/helper/index.jssrc/lib/wapi/wapi.jstest/index.js
🚧 Files skipped from review as they are similar to previous changes (34)
- src/lib/wapi/functions/send-mute.js
- src/api/layers/group.layer.ts
- src/lib/wapi/functions/send-sticker.js
- src/lib/wapi/functions/only-send-admin.js
- src/lib/wapi/functions/set-profile-pic.js
- src/lib/wapi/functions/forward-messages.js
- src/lib/wapi/functions/delete-all-message.js
- src/lib/wapi/functions/get-all-messages-in-chat.js
- src/lib/wapi/functions/promote-participant.js
- src/lib/wapi/functions/mark-markSeen-message.js
- src/lib/wapi/functions/send-contact-vcard-list.js
- src/lib/wapi/functions/reply.js
- src/lib/wapi/functions/set-group-title.js
- src/lib/wapi/helper/get-me-user.js
- src/lib/wapi/functions/test.js
- src/lib/wapi/functions/index.js
- src/lib/wapi/functions/send-type-buttons.js
- src/lib/wapi/functions/simulate-status-chat.js
- src/lib/wapi/functions/create-group.js
- src/api/layers/sender.layer.ts
- src/lib/wapi/functions/fix-chat.js
- src/lib/wapi/functions/only-send-data-admin.js
- src/lib/wapi/helper/index.js
- src/lib/wapi/functions/check-id-messagem.js
- src/lib/wapi/functions/send-file.js
- src/lib/wapi/functions/send-buttons.js
- src/lib/wapi/functions/get-group-admins.js
- src/lib/wapi/functions/add-participant.js
- src/lib/wapi/functions/get-number-profile.js
- src/lib/wapi/helper/filter-object.js
- src/lib/wapi/functions/archive-chat.js
- src/lib/wapi/functions/send-link-preview.js
- src/lib/wapi/functions/pin.chat.js
- src/lib/wapi/functions/demote-participant.js
🧰 Additional context used
📓 Path-based instructions (3)
src/lib/wapi/functions/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run
npm run build:wapito rebuild
Files:
src/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/mark-unseen-message.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/send-seen.js
src/lib/wapi/**/*.js
📄 CodeRabbit inference engine (CLAUDE.md)
WAPI layer code is built with webpack and injected into the Puppeteer browser context
Files:
src/lib/wapi/functions/poll-creation.jssrc/lib/wapi/functions/send-message.jssrc/lib/wapi/functions/send-ptt.jssrc/lib/wapi/functions/get-host.jssrc/lib/wapi/functions/send-contact-vcard.jssrc/lib/wapi/functions/remove-participant.jssrc/lib/wapi/functions/send-location.jssrc/lib/wapi/functions/send-message-scope.jssrc/lib/wapi/functions/set-new-message.jssrc/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/get-data-messages.jssrc/lib/wapi/functions/set-group-image.jssrc/lib/wapi/functions/set-group-description.jssrc/lib/wapi/functions/mark-unseen-message.jssrc/lib/wapi/functions/check-send-exist.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/functions/get-new-message-id.jssrc/lib/wapi/functions/get-all-chats.jssrc/lib/wapi/functions/open-chat.jssrc/lib/wapi/wapi.jssrc/lib/wapi/functions/sendMessageOptions.jssrc/lib/wapi/functions/send-seen.js
test/index.js
📄 CodeRabbit inference engine (CLAUDE.md)
Use test/index.js as the main test script; tests are basic scripts without a formal framework
Files:
test/index.js
🧠 Learnings (1)
📚 Learning: 2025-09-08T17:49:03.345Z
Learnt from: CR
Repo: venomlib/venom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T17:49:03.345Z
Learning: Applies to src/lib/wapi/functions/**/*.js : WAPI functions in src/lib/wapi/functions are JavaScript files injected into the browser; after changing them, run `npm run build:wapi` to rebuild
Applied to files:
src/lib/wapi/functions/delete-messages.jssrc/lib/wapi/functions/send-list-menu.jssrc/lib/wapi/functions/mark-unseen-message.jssrc/lib/wapi/functions/set-group-settings.jssrc/lib/wapi/wapi.js
🧬 Code graph analysis (19)
src/lib/wapi/functions/send-message.js (15)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/api/whatsapp.ts (5)
WAPI(136-136)WAPI(189-189)messageId(223-223)() => undefined(166-166)getMessageById(221-226)
src/lib/wapi/functions/send-ptt.js (16)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/api/model/message.ts (1)
Sender(83-101)
src/lib/wapi/functions/get-host.js (5)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-file.js (2)
wid(59-59)chat(60-60)src/lib/wapi/functions/send-ptt.js (2)
wid(20-20)chat(21-21)src/lib/wapi/functions/get-number-profile.js (1)
infoUser(7-7)
src/lib/wapi/functions/send-contact-vcard.js (8)
src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/send-contact-vcard-list.js (2)
chat(29-29)fromwWid(52-52)src/lib/wapi/functions/send-message.js (2)
chat(31-31)fromwWid(46-46)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)
src/lib/wapi/functions/send-location.js (2)
src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/send-message-scope.js (3)
src/lib/wapi/functions/send-buttons.js (2)
chat(40-40)fromwWid(44-44)src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)
src/lib/wapi/functions/set-new-message.js (5)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/delete-messages.js (10)
src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/reply.js (1)
chat(26-26)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/send-contact-vcard-list.js (1)
chat(29-29)src/lib/wapi/functions/send-contact-vcard.js (1)
chat(15-15)src/lib/wapi/functions/send-list-menu.js (1)
chat(98-98)src/lib/wapi/functions/send-message-scope.js (1)
chat(39-39)src/lib/wapi/functions/send-sticker.js (1)
chat(2-2)src/lib/wapi/functions/send-type-buttons.js (1)
chat(2-2)
src/lib/wapi/functions/get-data-messages.js (9)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)src/lib/wapi/functions/send-message-scope.js (1)
chat(39-39)src/lib/wapi/functions/set-group-description.js (1)
chat(15-15)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/set-group-image.js (13)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/mark-unseen-message.js (1)
chat(7-7)src/lib/wapi/functions/only-send-admin.js (1)
chat(9-9)src/lib/wapi/functions/send-message-scope.js (1)
chat(39-39)src/lib/wapi/functions/set-group-description.js (1)
chat(15-15)
src/lib/wapi/functions/set-group-description.js (4)
src/lib/wapi/functions/add-participant.js (1)
chat(2-2)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)src/lib/wapi/functions/get-chat.js (1)
getChat(1-49)
src/lib/wapi/functions/mark-unseen-message.js (13)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-all-messages-in-chat.js (1)
chat(7-7)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/mark-markSeen-message.js (1)
chat(7-7)src/lib/wapi/functions/only-send-admin.js (1)
chat(9-9)src/lib/wapi/functions/open-chat.js (2)
chat(7-7)chat(16-16)src/lib/wapi/functions/send-seen.js (1)
chat(2-2)
src/lib/wapi/functions/check-send-exist.js (2)
src/lib/wapi/functions/get-host.js (2)
wid(4-4)window(6-6)src/lib/wapi/functions/get-new-message-id.js (1)
chat(2-2)
src/lib/wapi/functions/set-group-settings.js (5)
src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/set-group-description.js (1)
chat(15-15)src/lib/wapi/functions/set-group-title.js (1)
chat(15-15)src/lib/wapi/wapi.js (3)
chat(443-443)chat(502-502)chat(511-511)
src/lib/wapi/functions/get-new-message-id.js (11)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-data-messages.js (1)
chat(42-42)src/lib/wapi/functions/get-group-admins.js (1)
chat(5-5)src/lib/wapi/functions/send-buttons.js (1)
chat(40-40)src/lib/wapi/functions/send-contact-vcard-list.js (1)
chat(29-29)src/lib/wapi/functions/send-contact-vcard.js (1)
chat(15-15)src/lib/wapi/functions/send-list-menu.js (1)
chat(98-98)src/lib/wapi/functions/send-location.js (1)
chat(7-7)
src/lib/wapi/functions/get-all-chats.js (14)
src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/sendMessageOptions.js (1)
fromwWid(104-104)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)
src/lib/wapi/functions/open-chat.js (10)
src/lib/wapi/functions/archive-chat.js (1)
chat(2-2)src/lib/wapi/functions/check-id-messagem.js (1)
chat(10-10)src/lib/wapi/functions/delete-all-message.js (1)
chat(10-10)src/lib/wapi/functions/delete-messages.js (1)
chat(10-10)src/lib/wapi/functions/get-number-profile.js (1)
chat(5-5)src/lib/wapi/functions/reply.js (1)
chat(26-26)src/lib/wapi/functions/send-contact-vcard-list.js (1)
chat(29-29)src/lib/wapi/functions/send-contact-vcard.js (1)
chat(15-15)src/lib/wapi/functions/send-location.js (1)
chat(7-7)src/lib/wapi/functions/send-sticker.js (1)
chat(2-2)
src/lib/wapi/wapi.js (3)
src/lib/wapi/functions/check-send-exist.js (2)
window(107-107)findChat(99-116)src/lib/wapi/functions/get-host.js (1)
window(6-6)src/lib/wapi/helper/get-me-user.js (1)
getMeUser(5-11)
src/lib/wapi/functions/sendMessageOptions.js (14)
src/lib/wapi/functions/get-all-chats.js (1)
fromwWid(2-2)src/lib/wapi/functions/get-host.js (1)
fromwWid(2-2)src/lib/wapi/functions/reply.js (1)
fromwWid(60-60)src/lib/wapi/functions/send-buttons.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-contact-vcard-list.js (1)
fromwWid(52-52)src/lib/wapi/functions/send-contact-vcard.js (1)
fromwWid(43-43)src/lib/wapi/functions/send-link-preview.js (1)
fromwWid(31-31)src/lib/wapi/functions/send-list-menu.js (1)
fromwWid(102-102)src/lib/wapi/functions/send-location.js (1)
fromwWid(19-19)src/lib/wapi/functions/send-message-scope.js (1)
fromwWid(44-44)src/lib/wapi/functions/send-message.js (1)
fromwWid(46-46)src/lib/wapi/functions/send-sticker.js (1)
fromwWid(6-6)src/lib/wapi/functions/send-type-buttons.js (1)
fromwWid(122-122)src/lib/wapi/functions/test.js (1)
fromwWid(6-6)
🔇 Additional comments (19)
src/lib/wapi/functions/send-location.js (2)
7-7: LGTM on chat lookup migration.The replacement of
WAPI.sendExist(chatId)withWAPI.findChat(chatId)aligns with the PR-wide refactor. The subsequent check onchat.erro(line 16) is consistent with the expected return structure.
19-19: LGTM on user retrieval migration.The migration from
Store.MaybeMeUser.getMaybeMePnUser()toWAPI.getMeUser()is consistent with the standardized approach used across other functions in this PR (e.g.,send-message.js,send-buttons.js,reply.js).src/lib/wapi/functions/send-ptt.js (1)
86-86: LGTM on user retrieval migration.The change from
Store.MaybeMeUser.getMaybeMePnUser()toWAPI.getMeUser()is consistent with the standardized approach across the codebase.src/lib/wapi/functions/send-seen.js (1)
2-2: LGTM on chat lookup migration.The replacement of
WAPI.sendExist(id)withWAPI.findChat(id)is consistent with the PR-wide refactor.src/lib/wapi/functions/send-message-scope.js (2)
39-39: LGTM on chat lookup migration.The replacement of
WAPI.sendExist(to)withWAPI.findChat(to)aligns with the PR-wide refactor. The subsequent validation logic onchat.statusandchat.idremains appropriate.
44-44: LGTM on user retrieval migration.The migration to
WAPI.getMeUser()is consistent with the standardized approach used across other functions in this PR.src/lib/wapi/functions/get-host.js (1)
1-18: LGTM on the refactored implementation.The changes appropriately:
- Use the standardized
WAPI.getMeUser()for user retrieval- Follow the same
WidFactory.createWid+FindOrCreateChat.findOrCreateLatestChatpattern seen in other files (e.g.,check-number-status.js)- Add proper try-catch error handling with logging
The implicit
undefinedreturns when conditions fail are acceptable for a getter function where callers can handle missing host info.src/lib/wapi/wapi.js (2)
91-91: LGTM!The import changes correctly add
findChatfrom functions andgetMeUserfrom helpers, aligning with the refactor to consolidate chat lookup and user retrieval APIs.Also applies to: 130-131
270-270: LGTM!Exposing
getMeUserandfindChaton thewindow.WAPIsurface is consistent with the new helper-based approach and replaces the previoussendExist/returnChatmappings.Also applies to: 280-280
src/lib/wapi/functions/send-message.js (1)
46-46: LGTM!The switch to
WAPI.getMeUser()aligns with the centralized helper approach used across other send functions in this PR.src/lib/wapi/functions/sendMessageOptions.js (1)
104-104: LGTM!The switch to
WAPI.getMeUser()is consistent with the helper-based approach applied across all send functions in this PR.src/lib/wapi/functions/get-data-messages.js (1)
42-43: LGTM!The refactor from
WAPI.sendExisttoWAPI.findChatis consistent with the broader PR changes, and the null guard on line 43 (chat && chat.status != 404) properly handles cases wherefindChatmay return a falsy value.src/lib/wapi/functions/get-all-chats.js (1)
2-5: LGTM!The refactor correctly replaces
Store.MaybeMeUser.getMaybeMePnUser()withWAPI.getMeUser()andWAPI.sendExistwithWAPI.findChat, consistent with the broader PR changes. Null guards are properly in place at lines 3 and 5.src/lib/wapi/functions/set-group-description.js (1)
15-16: LGTM:findChatswap is consistent with existing guard.
Line 15 integrates cleanly with the existingchat && chat.status != 404check.src/lib/wapi/functions/set-group-image.js (1)
13-14: LGTM:findChatfits the existing existence check.
Line 13 keeps the same gating logic and error flow.src/lib/wapi/functions/set-group-settings.js (1)
16-17: LGTM:findChatintegration is straightforward.
Line 16 preserves the same error gating and downstream logic.src/lib/wapi/functions/check-send-exist.js (1)
43-55: LGTM: allow@lidsuffix in ID validation.
This aligns with the expanded identifier support.src/lib/wapi/functions/send-contact-vcard.js (1)
43-43: The return type ofWAPI.getMeUser()is correct formessage.from. The function returns a WID object (or undefined), which matches the expected shape used consistently across all message-sending functions in the codebase. No type incompatibility exists.Likely an incorrect or invalid review comment.
src/lib/wapi/functions/send-list-menu.js (1)
98-102: Confirm rebuild after WAPI bundle changes.The changes maintain type compatibility:
findChat()returns a chat object withid(Wid), andgetMeUser()returns the expected Wid for thefromfield. The code properly guards against null values at line 100. Since this file matchessrc/lib/wapi/**/*.js, runnpm run build:wapito rebuild the webpack bundle after these changes.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| const chat = await WAPI.findChat(chatId); | ||
| const cont = await WAPI.findChat(contact); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, get the full context of send-contact-vcard.js to understand the code structure
cat -n src/lib/wapi/functions/send-contact-vcard.jsRepository: venomlib/venom
Length of output: 2728
🏁 Script executed:
# Search for findChat implementation
rg -n "^\s*findChat\s*[:=]|function\s+findChat|\.findChat\s*=" src/lib/wapi -g "*.js" -A 5Repository: venomlib/venom
Length of output: 821
🏁 Script executed:
# Search for vcardFromContactModel implementation
rg -n "vcardFromContactModel" src/lib/wapi -g "*.js" -B 2 -A 10Repository: venomlib/venom
Length of output: 4808
🏁 Script executed:
# Search for __x_contact usage to understand expectations
rg -n "__x_contact" src/lib/wapi -g "*.js" -B 2 -A 2Repository: venomlib/venom
Length of output: 827
🏁 Script executed:
# Get the full findChat implementation
cat -n src/lib/wapi/functions/check-send-exist.js | head -150Repository: venomlib/venom
Length of output: 4141
🏁 Script executed:
# Check for Store.Contact usage and patterns to understand the difference between findChat and Contact.get
rg -n "Store\.Contact\.get|findChat" src/lib/wapi/functions -g "*.js" -B 2 -A 8 | head -100Repository: venomlib/venom
Length of output: 7420
Use Store.Contact.get(contact) instead of findChat(contact) to fetch the contact object.
findChat is designed to return chat objects via the FindOrCreateChat API, which may not have the __x_contact field required by vcardFromContactModel. Line 16 should use window.Store.Contact.get(contact) to fetch the contact object directly, consistent with how sendMessageOptions.js retrieves contacts before calling vcardFromContactModel. Additionally, validate that the returned contact object has the required __x_contact field before dereferencing it at line 45.
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/send-contact-vcard.js` around lines 15 - 16, Replace
the use of WAPI.findChat(contact) with window.Store.Contact.get(contact) when
retrieving the contact in send-contact-vcard.js (currently using WAPI.findChat);
ensure you pass the actual contact model (with its __x_contact) into
vcardFromContactModel, and add a guard that validates the returned contact
object has the __x_contact field before dereferencing it (return or throw/log an
error if missing) to mirror how sendMessageOptions.js retrieves contacts.
| const chat = await WAPI.findChat(info.number); | ||
| delete info.number; | ||
| if (chat.id) { |
There was a problem hiding this comment.
Add null guard to prevent potential TypeError.
Line 11 accesses chat.id without verifying that chat is truthy. If WAPI.findChat returns null or undefined, this will throw a TypeError. Other files in this PR (e.g., poll-creation.js line 38, get-all-chats.js line 5) correctly use chat && guards.
🐛 Proposed fix
const chat = await WAPI.findChat(info.number);
delete info.number;
- if (chat.id) {
+ if (chat && chat.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 chat = await WAPI.findChat(info.number); | |
| delete info.number; | |
| if (chat.id) { | |
| const chat = await WAPI.findChat(info.number); | |
| delete info.number; | |
| if (chat && chat.id) { |
🤖 Prompt for AI Agents
In `@src/lib/wapi/functions/set-new-message.js` around lines 9 - 11, The code
calls WAPI.findChat(...) and directly checks chat.id which can throw if chat is
null/undefined; update the conditional in set-new-message.js to guard the chat
object (e.g., use if (chat && chat.id) or if (chat?.id)) so you only access
chat.id when chat is truthy; ensure you locate the WAPI.findChat call and the
subsequent if (chat.id) check and replace it with the guarded form to match
patterns used in poll-creation.js and get-all-chats.js.
Fixes # .
Changes proposed in this pull request
To test (it takes a while):
npm install github:<username>/venom#<branch>Summary by CodeRabbit
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.