Skip to content

Conversation

@rodrigo-gmengue
Copy link
Collaborator

@rodrigo-gmengue rodrigo-gmengue commented Oct 24, 2025

Summary by CodeRabbit

  • New Features

    • Added endpoints to list accessible WhatsApp Business Accounts, inspect tokens, retrieve WABA info/phone numbers, and manage webhook subscriptions (get/create).
    • Added real-time messaging integration to support listener/contact workflows.
  • Chores

    • Introduced configurable business and WABA identifiers, persistent webhook storage, and runtime reload to apply subscription changes.

@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 2025

Walkthrough

Adds WABA and BUSINESS_ID compatibility routes and new Graph API–style endpoints (accounts, debug_token, waba, subscriptions); extends PhoneNumberController with new methods, persistence via setConfig, and a reload dependency; introduces BUSINESS_ID and WABA_ID defaults.

Changes

Cohort / File(s) Summary
Configuration Constants
src/defaults.ts
Added BUSINESS_ID (from process.env.FB_ID, default 'FB_UNOAPI') and WABA_ID (from process.env.WABA_ID, default 'WABA_UNOAPI').
PhoneNumberController & Config Integration
src/controllers/phone_number_controller.ts
Expanded imports (includes UNOAPI_AUTH_TOKEN, WABA_ID, BUSINESS_ID, setConfig, Reload); constructor now accepts reload: Reload and assigns this.reload. Added public methods: accounts(), debugToken(), waba(), getsubs(), addsubs() implementing account listing, token debugging, WABA/phone info, subscription retrieval, and subscription create/update. Uses setConfig to persist webhook config and calls reload.run(phone) after updates.
Router: New Compatibility Routes
src/router.ts
Imported WABA_ID and BUSINESS_ID; instantiates PhoneNumberController(getConfig, sessionStore, reload). Added BUSINESS_ID and WABA_ID compatibility endpoints and subscription/token routes: GET /:version/{BUSINESS_ID}/owned_whatsapp_business_accounts, GET /:version/{BUSINESS_ID}/, GET /:version/{WABA_ID}/, GET /:version/{WABA_ID}/phone_numbers, GET /debug_token, GET /:phone/subscriptions, POST /:phone/subscriptions.
Baileys Integration Wiring
src/web.ts
Introduced Baileys-related imports and initializations (ListenerBaileys, ContactBaileys, getClientBaileys, Contact, injectRouteDummy); wires listener/contact and passes dependencies into app initialization before broadcast startup.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Router
    participant Controller as PhoneNumberController
    participant Config as Config Store

    rect rgba(230,245,255,0.9)
      note right of Client: Token debug flow
      Client->>Router: GET /debug_token?input_token=...&access_token=...
      Router->>Controller: debugToken(req,res)
      Controller->>Config: getConfig()
      Controller->>Controller: compare tokens / lookup app metadata
      Controller-->>Client: Graph-format token/app metadata
    end

    rect rgba(235,255,235,0.9)
      note right of Client: Create or update subscription
      Client->>Router: POST /:phone/subscriptions
      Router->>Controller: addsubs(req,res)
      Controller->>Config: getConfig() -> find or create meta webhook entry
      Controller->>Config: setConfig(updated)
      Controller->>Controller: reload.run(phone)
      Controller-->>Client: webhook creation/update result (Graph-format)
    end

    rect rgba(255,250,235,0.9)
      note right of Client: Accounts / WABA listing
      Client->>Router: GET /:version/{BUSINESS_ID}/owned_whatsapp_business_accounts
      Router->>Controller: accounts(req,res)
      Controller->>Config: getConfig() -> gather accessible accounts/phones
      Controller-->>Client: Graph-format account/phone list
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Potential review focal points:

  • src/controllers/phone_number_controller.ts — new methods (addsubs, getsubs, debugToken, waba, accounts) and their side effects (setConfig, reload.run).
  • src/router.ts — route patterns for BUSINESS_ID/WABA_ID and parameter handling.
  • src/web.ts — new Baileys wiring and dependency injection points.

Poem

🐇 I hop through configs with a twitching nose,
I stitch webhooks where the warm wind blows,
I check the token, list WABA lights,
I save and call reload on busy nights,
A little rabbit dances — code in tow.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'add WABA support' accurately reflects the main changes: adding WABA ID support, new WABA-compatible routes, and related infrastructure throughout the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1573440 and f738a38.

📒 Files selected for processing (1)
  • src/web.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/web.ts (5)
src/services/listener_baileys.ts (1)
  • ListenerBaileys (45-212)
src/services/client.ts (1)
  • Contact (10-14)
src/services/contact_baileys.ts (1)
  • ContactBaileys (8-53)
src/services/client_baileys.ts (2)
  • getClientBaileys (49-85)
  • logout (408-412)
src/app.ts (1)
  • App (21-101)
🪛 Biome (2.1.2)
src/web.ts

[error] 31-31: Unexpected token

(parse)


[error] 31-32: Unexpected token

(parse)


[error] 32-32: Unexpected token

(parse)


[error] 33-33: Unexpected token

(parse)


[error] 33-33: Unexpected token

(parse)


[error] 34-34: Unexpected token

(parse)


[error] 34-34: Unexpected token

(parse)


[error] 35-35: Unexpected token

(parse)


[error] 35-35: Unexpected token

(parse)

🔇 Additional comments (3)
src/web.ts (3)

31-35: Static analysis errors are false positives.

The Biome parser is reporting unexpected token errors on these import statements, but the syntax is correct. These are false positives that can be safely ignored.


51-52: LGTM! Baileys integration wired correctly.

The listener and contact instantiations match their respective constructor signatures and properly wire the new Baileys functionality into the application.


62-62: The original review comment is incorrect.

ReloadAmqp extends Reload (as shown in src/services/reload_amqp.ts:6), making it type-compatible with the App constructor's reload: Reload parameter. Passing a subclass instance where the parent type is expected is valid TypeScript. No changes are needed.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (3)
src/router.ts (1)

32-32: Fix spacing in import statement.

The import has inconsistent spacing around the comma.

Apply this diff:

-import { WABA_ID ,BUSINESS_ID } from './defaults'
+import { WABA_ID, BUSINESS_ID } from './defaults'
src/controllers/phone_number_controller.ts (2)

6-6: Fix spacing in import statement.

The import has inconsistent spacing around commas.

Apply this diff:

-import { UNOAPI_AUTH_TOKEN , WABA_ID , BUSINESS_ID } from '../defaults'
+import { UNOAPI_AUTH_TOKEN, WABA_ID, BUSINESS_ID } from '../defaults'

285-285: Extract 'metaId' magic string to a constant.

The string 'metaId' appears in multiple methods (getsubs, addsubs). Extract it to a constant at the top of the file for maintainability.

At the top of the class:

private static readonly META_WEBHOOK_ID = 'metaId'

Then use PhoneNumberController.META_WEBHOOK_ID throughout.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05714ed and 8e0cbee.

📒 Files selected for processing (3)
  • src/controllers/phone_number_controller.ts (2 hunks)
  • src/defaults.ts (1 hunks)
  • src/router.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/controllers/phone_number_controller.ts (5)
src/services/redis.ts (2)
  • getConfig (283-290)
  • setConfig (293-315)
src/services/config.ts (1)
  • getConfig (163-165)
src/services/reload.ts (1)
  • Reload (8-17)
src/services/security.ts (1)
  • getAuthHeaderToken (62-74)
src/defaults.ts (2)
  • UNOAPI_AUTH_TOKEN (8-8)
  • WABA_ID (71-71)
src/router.ts (4)
src/controllers/phone_number_controller.ts (1)
  • PhoneNumberController (10-409)
src/services/config.ts (1)
  • getConfig (163-165)
src/app.ts (1)
  • router (69-100)
src/defaults.ts (2)
  • BUSINESS_ID (70-70)
  • WABA_ID (71-71)
🔇 Additional comments (7)
src/defaults.ts (1)

70-71: LGTM!

The new constants follow the established pattern in this file and provide sensible defaults for WABA integration.

src/router.ts (2)

56-56: LGTM!

The controller instantiation correctly passes the reload parameter, aligning with the updated constructor signature.


73-82: LGTM!

The new WABA and Business ID compatibility routes are properly configured with middleware and follow the Graph API conventions.

src/controllers/phone_number_controller.ts (4)

15-18: LGTM!

The constructor correctly accepts and stores the reload parameter, which is used by the addsubs method to refresh configuration after updates.


89-97: Early break prevents listing multiple accounts.

The loop breaks after finding the first authorized phone (line 95), which means if multiple phone numbers are configured with valid tokens, only one WABA account entry is returned. This may be intentional for a single-WABA setup, but could be problematic if the system should support multiple accounts.

Verify whether this behavior is correct for your use case. If multiple WABAs should be supported, remove the break statement and adjust the logic to track unique WABA IDs.


140-146: Verify token validation requirements.

The validation requires both inputToken and accessToken to be identical and equal to config.authToken. This differs from typical OAuth debug_token flows where input_token is the token being validated and access_token is used to authorize the validation request. Confirm this matches your Graph API compatibility requirements.


389-390: LGTM!

The configuration persistence and reload logic correctly saves the updated webhook configuration and triggers a reload to apply the changes immediately.

const token = getAuthHeaderToken(req)
const { fields } = req.query

if (fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts') || req.path.endsWith('/owned_whatsapp_business_accounts')) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix operator precedence in condition.

The condition has a precedence issue. The || operator has lower precedence than the method call, so the current logic evaluates as (fields && fields.split(...).includes(...)) || (req.path.endsWith(...)), but the split could fail if fields is not a string.

Apply this diff:

-      if (fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts') || req.path.endsWith('/owned_whatsapp_business_accounts')) {
+      if ((fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts')) || req.path.endsWith('/owned_whatsapp_business_accounts')) {
📝 Committable suggestion

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

Suggested change
if (fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts') || req.path.endsWith('/owned_whatsapp_business_accounts')) {
if ((fields && (fields as string).split(',').includes('owned_whatsapp_business_accounts')) || req.path.endsWith('/owned_whatsapp_business_accounts')) {
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around line 84, the conditional
suffers from operator precedence and a potential runtime error when calling
split on a non-string; update it to explicitly check that fields is a string
before calling split and group the left side with parentheses so the overall
expression is ((typeof fields === 'string' && (fields as
string).split(',').includes('owned_whatsapp_business_accounts')) ||
req.path.endsWith('/owned_whatsapp_business_accounts')). Ensure the typeof check
comes first to prevent split on non-strings and add parentheses to make the
intended precedence explicit.

Comment on lines +173 to +194
public async waba(req: Request, res: Response) {
logger.debug('headers %s', JSON.stringify(req.headers))
logger.debug('params %s', JSON.stringify(req.params))
logger.debug('query %s', JSON.stringify(req.query))
logger.debug('path %s', req.path)

try {
const token = getAuthHeaderToken(req)
const { waba_id } = req.params
const phones = await this.sessionStore.getPhones()
const foundConfigs: any[] = []

for (const number of phones) {
const config = await this.getConfig(number)
if (token === config.authToken) {
foundConfigs.push({ ...config, number })
}
}

if (foundConfigs.length === 0) {
return res.status(403).json({ error: 'Invalid or unauthorized token' })
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate waba_id parameter against WABA_ID constant.

The method extracts waba_id from req.params (line 181) but never validates that it matches the expected WABA_ID constant. This could allow requests to arbitrary WABA IDs to succeed as long as the token is valid.

Consider adding validation after line 181:

if (waba_id !== WABA_ID) {
  return res.status(404).json({ error: 'WABA ID not found' })
}
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around lines 173 to 194, after
extracting waba_id from req.params (line ~181) add a validation that compares
waba_id to the WABA_ID constant and if they don't match return a 404 JSON
response; specifically, insert a check that if (waba_id !== WABA_ID) then return
res.status(404).json({ error: 'WABA ID not found' }) so only requests for the
expected WABA ID proceed.

Comment on lines +227 to +241
else {
logger.debug('Processing generic WABA info request')
const firstCfg = foundConfigs[0]

response = {
id: waba_id,
name: String(firstCfg.label || 'UNOAPI WABA ACCOUNT').toUpperCase(),
currency: 'BRL',
timezone_id: 42,
message_template_namespace: firstCfg.label.slice(0, 10),
primary_business_location: { country: 'BR' },
creation_time: new Date().toISOString(),
tier: 'TIER_1',
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add null safety for label access.

Line 236 accesses firstCfg.label.slice(0, 10) which could throw if label is undefined or null, even though line 233 has a fallback.

Apply this diff:

-          message_template_namespace: firstCfg.label.slice(0, 10),
+          message_template_namespace: (firstCfg.label || 'UNOAPI').slice(0, 10),
📝 Committable suggestion

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

Suggested change
else {
logger.debug('Processing generic WABA info request')
const firstCfg = foundConfigs[0]
response = {
id: waba_id,
name: String(firstCfg.label || 'UNOAPI WABA ACCOUNT').toUpperCase(),
currency: 'BRL',
timezone_id: 42,
message_template_namespace: firstCfg.label.slice(0, 10),
primary_business_location: { country: 'BR' },
creation_time: new Date().toISOString(),
tier: 'TIER_1',
}
}
else {
logger.debug('Processing generic WABA info request')
const firstCfg = foundConfigs[0]
response = {
id: waba_id,
name: String(firstCfg.label || 'UNOAPI WABA ACCOUNT').toUpperCase(),
currency: 'BRL',
timezone_id: 42,
message_template_namespace: (firstCfg.label || 'UNOAPI').slice(0, 10),
primary_business_location: { country: 'BR' },
creation_time: new Date().toISOString(),
tier: 'TIER_1',
}
}
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around lines 227 to 241, the code
uses firstCfg.label.slice(0, 10) which can throw if label is null/undefined;
change it to safely derive the namespace by coercing label to string with a
fallback before slicing (e.g., use (String(firstCfg.label || 'UNOAPI WABA
ACCOUNT')).slice(0, 10) or optional chaining with a default) so the slice call
never receives null/undefined and preserves the existing fallback behavior.

Comment on lines +262 to +270
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}

const [appId, userToken] = accessToken.split('|')

if (appId !== phone) {
return res.status(403).json({ error: 'appId não corresponde ao número de telefone' })
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add safer token parsing with error handling.

The token split at line 266 assumes exactly two parts, but doesn't handle cases where the token might contain multiple pipe characters or be malformed in other ways.

Apply this diff:

       // Verificação básica
       if (!accessToken || !accessToken.includes('|')) {
         return res.status(400).json({ error: 'Access token inválido ou ausente' })
       }
 
       const [appId, userToken] = accessToken.split('|')
+      
+      if (!appId || !userToken) {
+        return res.status(400).json({ error: 'Access token mal formatado' })
+      }
 
       if (appId !== phone) {
📝 Committable suggestion

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

Suggested change
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}
const [appId, userToken] = accessToken.split('|')
if (appId !== phone) {
return res.status(403).json({ error: 'appId não corresponde ao número de telefone' })
}
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}
const [appId, userToken] = accessToken.split('|')
if (!appId || !userToken) {
return res.status(400).json({ error: 'Access token mal formatado' })
}
if (appId !== phone) {
return res.status(403).json({ error: 'appId não corresponde ao número de telefone' })
}
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around lines 262 to 270, the
current accessToken parsing assumes exactly one '|' and does a blind split;
change it to robustly validate and extract the two parts: first check
accessToken exists and contains a '|' then split with a limit of 2 (or use
indexOf to split into left/right only), trim both parts, verify neither part is
empty, and only then assign appId and userToken; if any validation fails return
a 400 with a clear error; keep the existing appId !== phone check and return 403
as before.

Comment on lines +326 to +339
const accessToken = req.query.access_token as string
const body = req.body || {}
const [appId, userToken] = accessToken.split('|')

// --- Validações ---
if (!config) {
return res.status(404).json({ error: 'Número não encontrado' })
}
if (!accessToken || !accessToken.includes('|')) {
return res.status(400).json({ error: 'Access token inválido ou ausente' })
}
if (appId !== phone || userToken !== config.authToken) {
return res.status(403).json({ error: 'appId ou Token não corresponde' })
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add safer token parsing and align validation with getsubs.

Two issues:

  1. The token split at line 328 lacks validation (same issue as in getsubs).
  2. The token validation at line 337 is stricter than in getsubs (line 279), which also accepts UNOAPI_AUTH_TOKEN. This inconsistency could cause unexpected behavior.

Apply this diff:

       const accessToken = req.query.access_token as string
       const body = req.body || {}
-      const [appId, userToken] = accessToken.split('|')
 
       // --- Validações ---
       if (!config) {
         return res.status(404).json({ error: 'Número não encontrado' })
       }
       if (!accessToken || !accessToken.includes('|')) {
         return res.status(400).json({ error: 'Access token inválido ou ausente' })
       }
-      if (appId !== phone || userToken !== config.authToken) {
+      
+      const [appId, userToken] = accessToken.split('|')
+      if (!appId || !userToken) {
+        return res.status(400).json({ error: 'Access token mal formatado' })
+      }
+      if (appId !== phone || (userToken !== config.authToken && userToken !== UNOAPI_AUTH_TOKEN)) {
         return res.status(403).json({ error: 'appId ou Token não corresponde' })
       }
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around lines 326 to 339, the
access token is split without checking it first and the validation rejects
tokens that would be accepted by getsubs; first ensure access_token exists and
contains '|' before calling split, parse into two parts safely (limit split to
two parts), and validate that appId matches phone and that userToken equals
either config.authToken or process.env.UNOAPI_AUTH_TOKEN to match getsubs
behavior; return the same error codes/messages already used, keeping the config
existence check and token-format check ordered so you never split undefined.

Comment on lines +353 to +368
const newWebhook = {
sendNewMessages: true,
id: 'metaId',
urlAbsolute: callback_url,
token: verify_token,
header: 'Authorization',
sendGroupMessages: false,
sendNewsletterMessages: false,
sendOutgoingMessages: true,
sendUpdateMessages: true,
sendIncomingMessages: true,
sendTranscribeAudio: false,
url:"http://localhost:9876/webhooks/fake",
addToBlackListOnOutgoingMessageWithTtl:0,
timeoutMs:360000
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove hard-coded localhost URL and make webhook configuration more flexible.

Line 365 contains a hard-coded url: "http://localhost:9876/webhooks/fake" which appears incorrect for a production webhook subscription. Additionally, many webhook settings are hard-coded and might need to be configurable based on the subscription request.

At minimum, apply this diff to remove the hard-coded URL:

       const newWebhook = {
         sendNewMessages: true,
         id: 'metaId',
         urlAbsolute: callback_url,
         token: verify_token,
         header: 'Authorization',
         sendGroupMessages: false,
         sendNewsletterMessages: false,
         sendOutgoingMessages: true,
         sendUpdateMessages: true,
         sendIncomingMessages: true,
         sendTranscribeAudio: false,
-        url:"http://localhost:9876/webhooks/fake",
         addToBlackListOnOutgoingMessageWithTtl:0,
         timeoutMs:360000
       }

Consider whether other hard-coded boolean flags should be derived from the fields parameter in the request body.

📝 Committable suggestion

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

Suggested change
const newWebhook = {
sendNewMessages: true,
id: 'metaId',
urlAbsolute: callback_url,
token: verify_token,
header: 'Authorization',
sendGroupMessages: false,
sendNewsletterMessages: false,
sendOutgoingMessages: true,
sendUpdateMessages: true,
sendIncomingMessages: true,
sendTranscribeAudio: false,
url:"http://localhost:9876/webhooks/fake",
addToBlackListOnOutgoingMessageWithTtl:0,
timeoutMs:360000
}
const newWebhook = {
sendNewMessages: true,
id: 'metaId',
urlAbsolute: callback_url,
token: verify_token,
header: 'Authorization',
sendGroupMessages: false,
sendNewsletterMessages: false,
sendOutgoingMessages: true,
sendUpdateMessages: true,
sendIncomingMessages: true,
sendTranscribeAudio: false,
addToBlackListOnOutgoingMessageWithTtl:0,
timeoutMs:360000
}
🤖 Prompt for AI Agents
In src/controllers/phone_number_controller.ts around lines 353 to 368, remove
the hard-coded url ("http://localhost:9876/webhooks/fake") and replace it with
the incoming callback_url (already present) so the webhook points to the
request-supplied endpoint; also stop hard-coding boolean flags and timeout by
reading them from the request body (e.g., a fields or options object) with
sensible default fallbacks (keep current true/false values if the request does
not supply them) so webhook configuration is flexible for production and tests.
Ensure id/token/header remain set from existing variables, validate/normalize
the incoming values (types and allowed ranges like timeoutMs), and keep backward
compatibility by defaulting to the current values when fields are absent.

Comment on lines +84 to +85
router.get(`/:phone/subscriptions`, phoneNumberController.getsubs.bind(phoneNumberController))
router.post(`/:phone/subscriptions`, phoneNumberController.addsubs.bind(phoneNumberController))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add middleware to subscription routes for consistency and security.

The subscription routes (lines 84-85) don't use the middleware parameter, unlike most other routes in this file. The POST route at line 85 modifies webhook configuration, so it should be protected by authentication middleware to prevent unauthorized changes.

Apply this diff:

-  router.get(`/:phone/subscriptions`, phoneNumberController.getsubs.bind(phoneNumberController))
-  router.post(`/:phone/subscriptions`, phoneNumberController.addsubs.bind(phoneNumberController))
+  router.get(`/:phone/subscriptions`, middleware, phoneNumberController.getsubs.bind(phoneNumberController))
+  router.post(`/:phone/subscriptions`, middleware, phoneNumberController.addsubs.bind(phoneNumberController))
📝 Committable suggestion

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

Suggested change
router.get(`/:phone/subscriptions`, phoneNumberController.getsubs.bind(phoneNumberController))
router.post(`/:phone/subscriptions`, phoneNumberController.addsubs.bind(phoneNumberController))
router.get(`/:phone/subscriptions`, middleware, phoneNumberController.getsubs.bind(phoneNumberController))
router.post(`/:phone/subscriptions`, middleware, phoneNumberController.addsubs.bind(phoneNumberController))
🤖 Prompt for AI Agents
In src/router.ts around lines 84 to 85, the subscription GET and POST routes
currently omit the shared authentication/authorization middleware; update both
route declarations to include the existing middleware parameter as the second
argument (i.e., router.get('/:phone/subscriptions', middleware,
phoneNumberController.getsubs.bind(phoneNumberController)) and
router.post('/:phone/subscriptions', middleware,
phoneNumberController.addsubs.bind(phoneNumberController))) so the endpoints are
protected and consistent with other routes; ensure the middleware variable is in
scope where the routes are defined.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e0cbee and 1573440.

📒 Files selected for processing (1)
  • src/defaults.ts (1 hunks)
🔇 Additional comments (1)
src/defaults.ts (1)

71-71: The default value is appropriate—no action needed.

The WABA_ID default ('WABA_UNOAPI') is used consistently as a compatibility identifier for fallback WABA account routes. It's referenced in route patterns (router.ts lines 79-80) and API responses (phone_number_controller.ts lines 94, 101) with clear, intentional naming. Production deployments can override this via the WABA_ID environment variable as designed.

export const AMQP_URL = process.env.AMQP_URL || 'amqp://guest:guest@localhost:5672'
export const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379'
export const PROXY_URL = process.env.PROXY_URL
export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Consider aligning the environment variable name with the constant name.

The environment variable FB_ID maps to the constant BUSINESS_ID, which could confuse developers during configuration. Additionally, the default value 'FB_UNOAPI' appears to be a placeholder. Since this constant is used in route patterns (per the PR summary), ensure that either:

  • The default is appropriate for development/testing, or
  • Validation is added to require this environment variable in production

Consider renaming the environment variable to BUSINESS_ID for consistency, or add a comment explaining the naming:

-export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
+// Maps to FB_ID environment variable for backward compatibility
+export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'

To verify whether this default value is validated elsewhere in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for validation or usage of BUSINESS_ID to confirm if the default is safe
rg -n --type=ts -C3 'BUSINESS_ID' -g '!src/defaults.ts'

Length of output: 1666




🏁 Script executed:

#!/bin/bash
# Search for validation of these environment variables or constants
rg -n --type=ts 'FB_ID|validate|process.env' src/defaults.ts -A 2 -B 2

Length of output: 13763


🏁 Script executed:

#!/bin/bash
# Search for any validation or checks on BUSINESS_ID or WABA_ID values in the entire codebase
rg -n --type=ts '(BUSINESS_ID|WABA_ID|FB_ID)' -C 2 | rg -i 'validate|check|if.*BUSINESS_ID|if.*WABA_ID|if.*FB_ID' -C 3

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there's a config validation file or startup validation
fd -e ts -g '*valid*' -g '*config*' -g '*startup*' -g '*init*' | head -20

Length of output: 204


🏁 Script executed:

#!/bin/bash
# Look for comments explaining BUSINESS_ID usage
rg -n --type=ts 'BUSINESS_ID.*COMPATIBILITY|BUSINESS.*ID' -B 3 -A 3

Length of output: 4612


🏁 Script executed:

#!/bin/bash
# Check the entire defaults.ts file to understand the context and patterns
cat src/defaults.ts

Length of output: 15456


Add a comment explaining the naming mismatch and compatibility route purpose.

The environment variable FB_ID maps to the constant BUSINESS_ID due to a naming inconsistency, which could confuse developers during configuration. The defaults are used as literal route identifiers in compatibility routes (per the router comments), so they serve a functional purpose—but this design should be documented.

Suggested change:

-export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
-export const WABA_ID = process.env.WABA_ID || 'WABA_UNOAPI'
+// Routes identifiers for backward compatibility; FB_ID env var controls BUSINESS_ID for legacy naming reasons
+export const BUSINESS_ID = process.env.FB_ID || 'FB_UNOAPI'
+export const WABA_ID = process.env.WABA_ID || 'WABA_UNOAPI'
🤖 Prompt for AI Agents
In src/defaults.ts around line 70, add an inline comment above the BUSINESS_ID
export that explains the naming mismatch (the environment var FB_ID is mapped to
the BUSINESS_ID constant for backwards compatibility) and state that this
constant is used as a literal route identifier in compatibility routes; mention
the expected env var name (FB_ID) and the default value ('FB_UNOAPI') so future
developers understand why the mapping exists and that changing the constant
affects route behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant