Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Components]: heyy #14430

Merged
merged 1 commit into from
Oct 31, 2024
Merged

[Components]: heyy #14430

merged 1 commit into from
Oct 31, 2024

Conversation

jcortes
Copy link
Collaborator

@jcortes jcortes commented Oct 25, 2024

WHY

Resolves #14383

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced modules for creating, updating, and uploading contacts and files.
    • Added functionality to send WhatsApp messages with various types.
    • New source for handling incoming messages with webhook support.
    • Added constants for API configuration and message types.
    • Enhanced utility functions for JSON parsing and validation.
  • Bug Fixes

    • Enhanced error handling and response management in API interactions.
  • Documentation

    • Updated constants and utility functions for improved application structure.
  • Chores

    • Updated versioning in the package configuration and added new dependencies.

@jcortes jcortes added action New Action Request trigger / source New trigger / source request labels Oct 25, 2024
@jcortes jcortes self-assigned this Oct 25, 2024
Copy link

vercel bot commented Oct 25, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) Oct 30, 2024 2:04am

Copy link

vercel bot commented Oct 25, 2024

@jcortes is attempting to deploy a commit to the Pipedreamers Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Oct 25, 2024

Walkthrough

This pull request introduces several new modules and functionalities for managing contacts and messaging within the application. Key additions include modules for creating, updating, and sending messages to contacts, along with a file upload feature. Constants and utility functions have also been added to support these functionalities. The changes enhance the application's ability to handle contact-related data and messaging through structured API interactions.

Changes

File Path Change Summary
components/heyy/actions/create-contact/create-contact.mjs New module for creating contacts with methods for handling contact details and API requests.
components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs New module for sending WhatsApp messages, supporting various message types and dynamic properties.
components/heyy/actions/update-contact/update-contact.mjs New module for updating contact details, including methods for constructing PUT requests.
components/heyy/actions/upload-file/upload-file.mjs New module for uploading files with properties for file path and format, including methods for handling uploads.
components/heyy/common/constants.mjs New module defining constants for API interactions, including message types and base URL.
components/heyy/common/utils.mjs New utility functions for parsing JSON and validating structures.
components/heyy/heyy.app.mjs Enhanced propDefinitions and methods for managing contact-related data and API interactions.
components/heyy/package.json Updated to include a new dependency on the form-data package.
components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs New module for handling incoming messages, including lifecycle hooks and methods for webhook management.

Assessment against linked issues

Objective Addressed Explanation
Emit new event when the business gets a new incoming message. (#14383)
Sends a WhatsApp message to a contact. Requires 'contact_id' and 'message'. (#14383)
Creates a new contact for the business. Required props are 'name' and 'phone_number'. (#14383)
Updates the details of a contact under the business. 'contact_id' is required. (#14383)

Possibly related PRs

  • New Components - peach #12856: The main PR introduces a new module for creating contacts, which is directly related to the action of creating a contact in the Peach application.
  • New Components - hullo #14271: The main PR introduces actions for adding or updating members in the Hullo application, which aligns with the contact management functionalities in the main PR.
  • New Components - wati #14276: The main PR's introduction of actions for managing contacts and sending messages is related to the actions in the WATI platform, which also focuses on SMS and WhatsApp communications.
  • New Components - smstools #14378: The main PR introduces actions for managing contacts and sending messages, which are related to the SMS functionalities in the smstools application.
  • [Components] liveswitch #13859 #14427: The main PR introduces actions for creating and updating conversations, which are relevant to the contact management functionalities in the LiveSwitch application.

Suggested reviewers

  • michelle0927

Poem

🐇 In the garden of code, new blooms arise,
Creating, updating, under bright skies.
With messages sent and files uploaded,
Our heyy app grows, all bugs corroded.
So hop along, let’s celebrate the cheer,
For every new feature brings us near! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link
Contributor

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

🧹 Outside diff range and nitpick comments (11)
components/heyy/package.json (1)

14-17: Consider adding a lock file for dependency version consistency.

To ensure consistent installations across different environments, consider adding either package-lock.json or yarn.lock to lock down exact versions of all dependencies.

components/heyy/common/utils.mjs (2)

52-54: Add documentation and simplify export

The export could benefit from JSDoc documentation and simpler implementation.

Consider this improvement:

+/**
+ * @typedef {Object} Utils
+ * @property {function(any): any[]} parseArray - Parses and validates an array input, then maps parse over its elements
+ */
+
+/** @type {Utils} */
 export default {
-  parseArray: (value) => parseArray(value)?.map(parse),
+  parseArray: value => parseArray(value)?.map(parse),
 };

1-54: Consider adding domain-specific validation

While the utility functions provide good general-purpose JSON parsing, consider adding specific validation for the WhatsApp message and contact properties mentioned in the PR objectives (contact_id, message, name, phone_number, etc.).

This could help catch configuration errors earlier and provide more meaningful error messages. For example:

// Example domain-specific validator
function validateContactProperties(obj) {
  if (!obj.name || typeof obj.name !== 'string') {
    throw new ConfigurationError("Contact must have a valid name");
  }
  if (!obj.phone_number || !/^\+?[\d\s-]+$/.test(obj.phone_number)) {
    throw new ConfigurationError("Contact must have a valid phone number");
  }
  // ... other validations
}
components/heyy/actions/upload-file/upload-file.mjs (2)

13-17: Add file size limit information in the description.

The description should inform users about any file size limitations to prevent upload failures.

-      description: "The file to be uploaded, please provide a file from `/tmp`. To upload a file to `/tmp` folder, please follow the doc [here](https://pipedream.com/docs/code/nodejs/working-with-files/#writing-a-file-to-tmp)",
+      description: "The file to be uploaded, please provide a file from `/tmp`. Maximum file size: [specify size]. To upload a file to `/tmp` folder, please follow the doc [here](https://pipedream.com/docs/code/nodejs/working-with-files/#writing-a-file-to-tmp)",

59-59: Fix typo in success message.

There's a typo in "Succesfully".

-    $.export("$summary", `Succesfully uploaded file with ID \`${response.id}\`.`);
+    $.export("$summary", `Successfully uploaded file with ID \`${response.id}\`.`);
components/heyy/actions/create-contact/create-contact.mjs (2)

1-47: LGTM! Consider enhancing property documentation.

The module structure is well-organized with clear metadata and proper property definitions. All required properties from the specifications are included.

Consider adding JSDoc comments for the props object to document the expected format of labels and attributes, as these have special handling in the implementation.

+ /**
+  * @typedef {Object} Props
+  * @property {string[]} labels - Array of label names to assign to the contact
+  * @property {Object.<string, string>} attributes - Key-value pairs of contact attributes
+  */
 props: {

1-96: Consider adding integration tests.

While the implementation satisfies the requirements, it would benefit from integration tests to verify the interaction with the API endpoint.

Would you like me to help create integration tests that cover:

  • Successful contact creation with minimum required fields
  • Contact creation with all optional fields
  • Error handling scenarios
🧰 Tools
🪛 Biome

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs (1)

86-90: Simplify labels transformation

The conditional spread with labels could be simplified for better readability.

Consider this alternative:

-        ...(labels?.length && {
-          labels: labels.map((name) => ({
-            name,
-          })),
-        }),
+        labels: labels?.length 
+          ? labels.map((name) => ({ name }))
+          : undefined,
components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1)

23-38: Offer assistance with error handling improvements.

Adding comprehensive error handling can improve the robustness of the webhook setup process.

Would you like help implementing a retry mechanism or more detailed logging for the webhook creation process?

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (2)

101-101: Correct the spelling of "formatted" in the description

In the description of the buttons property, "formated" should be "formatted":

"Each row should have a JSON formatted string. Eg. { "id": "STRING", "title": "STRING" }."


158-158: Correct the spelling of "Successfully" in the summary message

In the $summary export, "Succesfully" is misspelled. It should be "Successfully":

- $.export("$summary", "Succesfully sent WhatsApp message.");
+ $.export("$summary", "Successfully sent WhatsApp message.");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 505a6d2 and 43767e0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (1 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 97-97: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

🔇 Additional comments (6)
components/heyy/actions/upload-file/upload-file.mjs (2)

1-4: LGTM! Imports are appropriate for file upload functionality.

The imports are minimal and correctly chosen for handling file uploads with multipart/form-data.


1-62: Verify integration with WhatsApp messaging feature.

This upload functionality appears to support the attachment feature mentioned in the PR objectives for WhatsApp messaging. However, we should verify the integration.

#!/bin/bash
# Check how the upload functionality is integrated with WhatsApp messaging
rg -g '*.{js,mjs}' 'send-whatsapp-message.*attachment'
components/heyy/actions/create-contact/create-contact.mjs (1)

48-55: ⚠️ Potential issue

Add input validation for API parameters.

The current implementation allows arbitrary parameters to be passed to the API endpoint, which could pose security risks.

Consider validating the args before passing them to the API:

 methods: {
   createContact(args = {}) {
+    const allowedKeys = ['$', 'data'];
+    const invalidKeys = Object.keys(args).filter(key => !allowedKeys.includes(key));
+    if (invalidKeys.length > 0) {
+      throw new Error(`Invalid parameters: ${invalidKeys.join(', ')}`);
+    }
     return this.app.post({
       path: "/contacts",
       ...args,
     });
   },
 },
components/heyy/actions/update-contact/update-contact.mjs (1)

60-62: Verify API endpoint format

Let's ensure the API endpoint format matches the expected pattern.

✅ Verification successful

API endpoint format is consistent with codebase patterns

The /contacts/${contactId} endpoint format in the update-contact action aligns perfectly with REST conventions and matches the pattern used across the codebase:

  • GET /contacts for listing contacts
  • POST /contacts for creating contacts
  • PUT /contacts/${contactId} for updating specific contacts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other API endpoint usages to verify consistency
rg -g '*.{js,mjs}' '/contacts/\$\{.*\}' ./components/heyy/

Length of output: 160


Script:

#!/bin/bash
# Let's search for all contact-related API endpoints to verify consistency
rg -g '*.{js,mjs}' '/contacts' -B 2 -A 2 ./components/heyy/

Length of output: 1159

components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1)

67-71: ⚠️ Potential issue

Review the use of debug mode in API requests.

The createWebhook and deleteWebhook methods have debug: true set in their request options. Leaving debug mode enabled in production can expose sensitive information and affect performance.

Apply this diff to disable debug mode or make it configurable:

return this.app.post({
- debug: true,
  path: "/api_webhooks",
  ...args,
});

return this.app.delete({
- debug: true,
  path: `/api_webhooks/${webhookId}`,
  ...args,
});

Alternatively, make the debug option configurable through environment variables or a separate configuration setting.

Ensure that removing or configuring the debug option does not impact the functionality of API requests.

Also applies to: 76-80

components/heyy/heyy.app.mjs (1)

87-89: Confirm that constants are correctly defined and imported

The getUrl method uses constants.BASE_URL and constants.VERSION_PATH. Ensure that these constants are correctly defined in ./common/constants.mjs and imported properly.

Please verify that constants.BASE_URL and constants.VERSION_PATH are defined and have the expected values. If not, it may result in incorrect or undefined URLs.

components/heyy/package.json Outdated Show resolved Hide resolved
components/heyy/common/utils.mjs Show resolved Hide resolved
components/heyy/heyy.app.mjs Outdated Show resolved Hide resolved
components/heyy/heyy.app.mjs Show resolved Hide resolved
components/heyy/heyy.app.mjs Show resolved Hide resolved
components/heyy/heyy.app.mjs Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🧹 Outside diff range and nitpick comments (5)
components/heyy/actions/create-contact/create-contact.mjs (1)

1-8: LGTM! Consider enhancing the documentation.

The module definition and metadata are well-structured. However, the description could be more detailed about the required and optional properties.

Consider expanding the description to:

-  description: "Creates a new contact for the business. [See the documentation](https://documenter.getpostman.com/view/27408936/2sA2r3a6DW#a1249b8d-10cf-446a-be35-eb8793ffa967).",
+  description: "Creates a new contact for the business with required properties (phoneNumber, firstName) and optional properties (lastName, email, labels, attributes). [See the documentation](https://documenter.getpostman.com/view/27408936/2sA2r3a6DW#a1249b8d-10cf-446a-be35-eb8793ffa967).",
components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1)

4-20: Consider incrementing the version number for production readiness.

The component version is set to "0.0.2" which typically indicates early development. Since this is implementing core messaging functionality, consider using a more production-ready version number (e.g., "1.0.0").

components/heyy/heyy.app.mjs (1)

87-89: Consider implementing rate limiting.

WhatsApp APIs often have rate limits. Consider implementing rate limiting logic to prevent hitting API limits.

 getUrl(path) {
+  if (!this.rateLimiter) {
+    this.rateLimiter = {
+      lastRequest: 0,
+      minInterval: 1000, // 1 second between requests
+    };
+  }
   return `${constants.BASE_URL}${constants.VERSION_PATH}${path}`;
 },
components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (2)

1-10: Consider starting with version 1.0.0

The module setup and imports look good. However, since this is a production-ready feature implementing requirements from issue #14383, consider starting with version 1.0.0 instead of 0.0.1 to indicate a stable initial release.


144-159: Enhance success message and fix typo

The success message could be more informative and contains a typo.

-    $.export("$summary", "Succesfully sent WhatsApp message.");
+    $.export("$summary", `Successfully sent WhatsApp message to ${phoneNumber}`);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 43767e0 and 2e44081.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (2 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/heyy/actions/upload-file/upload-file.mjs
  • components/heyy/package.json
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 97-97: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

🔇 Additional comments (10)
components/heyy/common/utils.mjs (1)

13-27: Ensure proper handling of special characters in message content

Given this utility will parse WhatsApp messages and contact information, ensure proper handling of special characters and emojis in JSON strings.

components/heyy/actions/create-contact/create-contact.mjs (1)

1-96: Implementation matches PR objectives.

The create-contact action implementation aligns with the requirements specified in issue #14383, supporting all required properties (name, phone_number) and optional properties (email, address, notes).

🧰 Tools
🪛 Biome

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1)

1-90: Implementation aligns well with PR objectives.

The component successfully implements the webhook source for new incoming messages as specified in the requirements. The implementation includes proper webhook lifecycle management and event emission.

components/heyy/actions/update-contact/update-contact.mjs (2)

1-8: LGTM: Action configuration is well-structured.

The module setup and action configuration follow best practices with clear naming and versioning.


9-55: Skip: Props configuration issue already reported.

A previous review has already identified that lastName and email fields should be optional as per PR requirements.

components/heyy/heyy.app.mjs (2)

1-3: LGTM! Appropriate imports for API integration.

The imports are well-structured, bringing in axios for HTTP requests and constants for configuration.


142-147: Verify message template retrieval aligns with WhatsApp requirements.

The getMessageTemplates method should ensure compliance with WhatsApp's template message requirements.

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (3)

19-34: Refactor phoneNumber property definition

The phoneNumber property is still using the contactId propDefinition, which could cause confusion. Consider creating a dedicated phoneNumber propDefinition in the app.


121-128: Add error handling to sendWhatsappMessage method

The method should include proper error handling to manage API failures gracefully.


11-42: Implement missing required properties from specifications

The PR objectives specify that this action requires 'contact_id' and 'message' properties, with an optional 'attachment' property. Currently:

  • The 'message' property is missing from the base props (it's handled differently in additionalProps)
  • The optional 'attachment' property is not implemented

Let's verify if the attachment functionality is implemented elsewhere:

components/heyy/common/utils.mjs Outdated Show resolved Hide resolved
components/heyy/actions/create-contact/create-contact.mjs Outdated Show resolved Hide resolved
components/heyy/heyy.app.mjs Outdated Show resolved Hide resolved
components/heyy/heyy.app.mjs Show resolved Hide resolved
components/heyy/heyy.app.mjs Outdated Show resolved Hide resolved
Copy link
Contributor

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

🧹 Outside diff range and nitpick comments (2)
components/heyy/actions/update-contact/update-contact.mjs (1)

7-7: Consider using semantic versioning starting from 1.0.0

Since this is a new component being introduced with complete functionality as per requirements, consider starting with version "1.0.0" instead of "0.0.1".

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1)

158-158: Fix typo in success message.

The word "Successfully" is misspelled in the success message.

-    $.export("$summary", "Succesfully sent WhatsApp message.");
+    $.export("$summary", "Successfully sent WhatsApp message.");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2e44081 and e5d56ac.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (2 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (4)
  • components/heyy/actions/upload-file/upload-file.mjs
  • components/heyy/common/utils.mjs
  • components/heyy/package.json
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 97-97: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

🔇 Additional comments (14)
components/heyy/actions/create-contact/create-contact.mjs (3)

1-8: LGTM! Well-structured module definition with clear documentation.

The module metadata is well-defined with proper versioning and documentation link.


9-47: Verify property requirements and missing fields.

  1. The PR objectives specify 'address' and 'notes' as optional properties, but they are not implemented.
  2. The required fields ('name' and 'phone_number') should be marked as required in the props definition.

Let's verify the property definitions in the app file:

#!/bin/bash
# Description: Check property definitions in app file
# Expected: Find address and notes properties, and required field definitions

rg -A 2 "propDefinition.*address|propDefinition.*notes" "components/heyy/"

56-95: Verify API response format alignment with documentation.

The code assumes the response contains data.id, but we should verify this matches the API documentation referenced in the description.

Let's verify the API response format:

#!/bin/bash
# Description: Check API documentation for response format
# Expected: Find response schema definition showing data.id field

rg -A 5 "response.*schema.*contacts" "components/heyy/"
🧰 Tools
🪛 Biome

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/heyy.app.mjs (8)

1-6: LGTM: Basic structure and imports are well-organized.

The file follows the standard app module pattern with proper imports.


24-29: Add email validation.

The existing review comment about email validation is still valid. Please add the suggested pattern validation.


35-38: Add error handling in labels options method.

The existing review comment about error handling in the labels options method is still valid. Please add the suggested validation.


50-67: Add validation in contactId options method.

The existing review comment about validation in the contactId options method is still valid. Please add the suggested validation.


73-83: Add error handling in channelId options method.

The existing review comment about error handling in the channelId options method is still valid. Please add the suggested validation.


96-105: Add request validation and error handling.

The existing review comments about parameter validation and error handling in the _makeRequest method are still valid. Please add the suggested validation and error handling.


8-12: ⚠️ Potential issue

Add phone number validation and formatting requirements.

Since this is a WhatsApp integration (based on PR objectives), the phone number should be properly validated.

Apply this diff to add validation:

 phoneNumber: {
   type: "string",
   label: "Phone Number",
-  description: "The phone number of the contact.",
+  description: "The phone number of the contact in E.164 format (e.g., +1234567890).",
+  pattern: "^\\+[1-9]\\d{1,14}$",
 },

Likely invalid or redundant comment.


1-155: Verify alignment with PR objectives.

The implementation aligns with most PR objectives but seems to be missing:

  1. Webhook source for incoming messages
  2. Implementation for the send-whatsapp-message action

Let's verify if these are implemented in other files:

✅ Verification successful

Both webhook source and WhatsApp message action are implemented

The implementation is complete and aligns with the PR objectives:

  • Webhook source: components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
  • WhatsApp message action: components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for webhook and message sending implementations
echo "Searching for webhook source implementation..."
rg -l "new-message|incoming-message|webhook" --type js

echo "Searching for WhatsApp message sending implementation..."
rg -l "send-whatsapp-message" --type js

Length of output: 460


Script:

#!/bin/bash
# Let's search more thoroughly using different patterns and check the components directory structure

# Check for files in the heyy component directory
echo "Files in heyy component directory:"
fd . components/heyy/

# Search for any message or WhatsApp related files/patterns
echo "\nSearching for message-related files:"
rg -l "message|whatsapp" --type js components/heyy/

# Search for source implementations
echo "\nSearching for source implementations:"
fd "sources?" components/heyy/

# Search for action implementations
echo "\nSearching for action implementations:"
fd "actions?" components/heyy/

Length of output: 1283

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (3)

1-11: LGTM! Well-structured module definition with proper documentation.

The imports are appropriate and the module metadata is well-defined with version control and documentation link.


19-34: Consider renaming the prop to match its purpose.

While the mapper function correctly formats the contact's name and phone number, using contactId propDefinition for a property named phoneNumber is confusing. Consider either:

  1. Renaming the prop to contactId to match its underlying definition, or
  2. Creating a dedicated propDefinition for phone numbers

19-34: Implementation differs from PR objectives.

The PR objectives specify that the action should use contact_id as a property, but the implementation uses phoneNumber. While the current implementation works through the contactId propDefinition, it should be aligned with the documented objectives for consistency.

@jcortes jcortes force-pushed the heyy-new-components branch 2 times, most recently from b1563dd to dffe261 Compare October 25, 2024 20:13
Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (5)
components/heyy/actions/create-contact/create-contact.mjs (2)

3-8: Enhance module documentation.

While the documentation link is helpful, consider adding:

  1. Example usage with sample payload
  2. Description of required vs optional fields
  3. Expected response format

56-95: Consider implementing rate limiting.

The action might be subject to API rate limits. Consider implementing retry logic with exponential backoff.

Example implementation:

const retry = async (fn, retries = 3, delay = 1000) => {
  try {
    return await fn();
  } catch (error) {
    if (error.response?.status === 429 && retries > 0) {
      await new Promise(resolve => setTimeout(resolve, delay));
      return retry(fn, retries - 1, delay * 2);
    }
    throw error;
  }
};
🧰 Tools
🪛 Biome

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (3)

5-11: Consider starting with version 1.0.0

Since this is a new component implementing core messaging functionality as outlined in the PR objectives, it might be more appropriate to start with version 1.0.0 instead of 0.0.1.

-  version: "0.0.1",
+  version: "1.0.0",

46-50: Add length validation for text fields

Consider adding maximum length validation for bodyText, headerText, and footerText to prevent potential API errors.

   bodyText: {
     type: "string",
     label: "Body Text",
     description: "The text of the message to send.",
+    validate: (value) => value.length <= 4096 || "Message text cannot exceed 4096 characters",
   },
   // ... similar changes for headerText and footerText

Also applies to: 103-114


158-158: Fix typo in success message

There's a typo in the success message.

-    $.export("$summary", "Succesfully sent WhatsApp message.");
+    $.export("$summary", "Successfully sent WhatsApp message.");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e5d56ac and dffe261.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (2 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (4)
  • components/heyy/actions/upload-file/upload-file.mjs
  • components/heyy/common/utils.mjs
  • components/heyy/package.json
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 97-97: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

🔇 Additional comments (13)
components/heyy/actions/create-contact/create-contact.mjs (3)

9-47: LGTM with existing review comments.

The props are well-structured but please address the validation concerns raised in the previous review comments.


48-54: LGTM with existing review comments.

Please address the security concerns about args spreading raised in the previous review comments.


67-92: ⚠️ Potential issue

Add type validation for attributes values.

The attributes values are passed directly without type validation, which could lead to API errors if invalid types are provided.

Consider adding type validation:

 attributes:
   attributes && Object.entries(attributes)
     .map(([externalId, value]) => {
+      if (typeof value !== 'string' && typeof value !== 'number') {
+        throw new Error(`Invalid type for attribute ${externalId}. Expected string or number.`);
+      }
       return {
         externalId,
         value,
       };
     }),
🧰 Tools
🪛 Biome

[error] 85-85: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/heyy.app.mjs (8)

1-6: LGTM: Basic app setup is correct.

The imports and app configuration are properly structured.


30-39: Add error handling in labels options method.

The options method for labels needs proper error handling for API responses and data validation.


46-68: Add error handling and pagination metadata in contactId options.

The options method for contactId should:

  1. Handle API errors
  2. Return pagination metadata for proper UI handling

69-84: Add error handling in channelId options.

The options method for channelId needs proper error handling for API responses and data validation.


96-104: Add request validation and error handling.

The _makeRequest method needs proper validation and error handling.


123-151: Add pagination support for list endpoints.

The GET endpoints need proper pagination support.


8-29: ⚠️ Potential issue

Add validation for contact properties.

Several properties need additional validation:

  1. The phoneNumber property should validate WhatsApp number format
  2. The email property should validate email format
  3. The firstName property should have a minimum length requirement

Apply these improvements:

 phoneNumber: {
   type: "string",
   label: "Phone Number",
   description: "The phone number of the contact.",
+  pattern: "^\\+[1-9]\\d{1,14}$",
+  description: "The phone number in E.164 format (e.g., +1234567890).",
 },
 firstName: {
   type: "string",
   label: "First Name",
   description: "The first name of the contact.",
+  minLength: 1,
 },
 email: {
   type: "string",
   label: "Email",
   description: "The email address of the contact.",
   optional: true,
+  pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
 },

Likely invalid or redundant comment.


1-154: Verify alignment with PR objectives.

The implementation aligns with most PR objectives but is missing:

  1. Webhook source implementation for incoming messages
  2. Implementation for sending WhatsApp messages with attachments

Let's check for any related implementations:

✅ Verification successful

Let me search more specifically for files related to this PR and the Heyy integration:


Let me check the implementation details of the message sending functionality to verify attachment support:


The PR implementation is complete and includes all required functionality

The review comment's concerns have been addressed as both missing implementations are present:

  1. Webhook source implementation exists in components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
  2. WhatsApp messages with attachments are supported through:
    • upload-file action to upload files
    • send-whatsapp-message action supports various message types including images (MSG_TYPE.IMAGE) with file attachments via fileId
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for webhook and message sending implementations
echo "Searching for webhook implementations..."
rg -l "webhook|incoming.*message" --type js

echo "Searching for message sending implementations..."
rg -l "send.*message|attachment" --type js

Length of output: 464


Script:

#!/bin/bash
# Search for all files related to Heyy integration
echo "Files in heyy directory:"
fd . components/heyy/

echo -e "\nSearching for message sending in heyy files:"
rg "send.*message|attachment" components/heyy/

echo -e "\nSearching for webhook/source implementations in heyy files:"
rg "webhook|source|incoming.*message" components/heyy/

Length of output: 3506


Script:

#!/bin/bash
# Check send message implementation
echo "Content of send-whatsapp-message.mjs:"
cat components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs

echo -e "\nContent of upload-file.mjs:"
cat components/heyy/actions/upload-file/upload-file.mjs

Length of output: 5791

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (2)

1-4: LGTM! Imports are well-organized and necessary.

The imports provide access to required app configuration, constants, and utility functions.


61-65: Add validation for fileId

Consider adding validation to ensure the fileId exists and is accessible before attempting to send the message.

GTFalcao
GTFalcao previously approved these changes Oct 28, 2024
Copy link
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Contributor

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

🧹 Outside diff range and nitpick comments (1)
components/heyy/actions/update-contact/update-contact.mjs (1)

80-82: Improve error message for phone number validation

The current error message could be more helpful by including the expected format.

Apply this diff:

-      throw new ConfigurationError(`The phone number \`${phoneNumber}\` is invalid. Please provide a valid phone number.`);
+      throw new ConfigurationError(
+        `The phone number \`${phoneNumber}\` is invalid. Please provide a phone number in E.164 format (e.g., +1234567890).`
+      );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dffe261 and 38d2441.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (2 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/heyy/actions/upload-file/upload-file.mjs
  • components/heyy/package.json
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 91-91: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 103-103: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/common/utils.mjs

[error] 53-53: Use a regular expression literal instead of the RegExp constructor.

Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.

(lint/complexity/useRegexLiterals)

🔇 Additional comments (11)
components/heyy/common/utils.mjs (2)

13-27: Past review comment is still applicable

The validation issues identified in the previous review need to be addressed.


57-60: Past review comment is still applicable

The error handling improvements suggested in the previous review need to be addressed.

components/heyy/actions/update-contact/update-contact.mjs (3)

1-10: LGTM!

The imports and action configuration are well-structured with proper documentation link.


58-67: Previous review comments are still applicable

The following past review comments for this method are still valid and should be addressed:

  1. Add rate limit handling
  2. Add input validation for contactId
  3. Sanitize path parameters to prevent path traversal attacks

84-114: Previous review comments are still applicable

The following past review comments for this method are still valid and should be addressed:

  1. Add validation that at least one field is being updated
  2. Add error handling and input validation
  3. Optimize attributes transformation for better performance
  4. Add response validation
🧰 Tools
🪛 Biome

[error] 103-103: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/heyy.app.mjs (3)

1-6: LGTM! Basic app setup is correct.

The imports and app configuration are properly structured for a Pipedream integration.


96-104: ⚠️ Potential issue

Remove debug mode from production code

The _makeRequest method has debug: true hardcoded, which might expose sensitive information in logs. This should be configurable or disabled in production.

 _makeRequest({
   $ = this, path, headers, ...args
 } = {}) {
   return axios($, {
     ...args,
-    debug: true,
     url: this.getUrl(path),
     headers: this.getHeaders(headers),
   });
 },

Likely invalid or redundant comment.


1-154: Implement webhook source for incoming messages

The PR objectives mention a webhook source for incoming messages, but this functionality is not implemented in the app. Consider adding methods to handle webhook verification and payload processing.

Would you like me to help implement the webhook source functionality?

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (3)

1-4: LGTM! Imports are well-organized.

The necessary dependencies are properly imported with clear relative paths.


5-11: LGTM! Component metadata is well-defined.

The component is properly configured with a clear name, description, and documentation link.


120-129: LGTM! Method implementation is clean and focused.

The sendWhatsappMessage method correctly handles the API request structure.

@jcortes
Copy link
Collaborator Author

jcortes commented Oct 30, 2024

/approve

Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (6)
components/heyy/actions/create-contact/create-contact.mjs (1)

5-10: Consider starting with version 1.0.0.

Since this is a new component being introduced as part of a feature release, consider starting with version 1.0.0 instead of 0.0.1 to indicate it's ready for production use.

components/heyy/heyy.app.mjs (4)

13-17: Add length validation for firstName

Since this is a required field used for contact identification, it should have a maximum length constraint to prevent potential issues with extremely long names.

 firstName: {
   type: "string",
   label: "First Name",
   description: "The first name of the contact.",
+  maxLength: 100,
 },

30-39: Add size limits for labels array

The labels property accepts an array of strings but doesn't limit the number of labels that can be assigned to a contact. This could lead to performance issues if too many labels are assigned.

 labels: {
   type: "string[]",
   label: "Labels",
   description: "The labels associated with the contact.",
   optional: true,
+  max: 20, // Limit to 20 labels per contact
   async options() {
     const { data } = await this.getLabels();
     return data.map(({ name }) => name);
   },
 },

96-104: Add timeout and debug configuration

The _makeRequest method should include timeout settings to prevent hanging requests and debug configuration for better troubleshooting.

 _makeRequest({
-  $ = this, path, headers, ...args
+  $ = this, path, headers, debug = true, timeout = 10000, ...args
 } = {}) {
   return axios($, {
     ...args,
-    url: this.getUrl(path),
-    headers: this.getHeaders(headers),
+    url: this.getUrl(path),
+    headers: this.getHeaders(headers),
+    timeout,
+    debug,
   });
 },

135-140: Consider implementing rate limiting

The API methods, especially getContacts, could benefit from rate limiting to prevent hitting API quotas. Consider implementing a rate limiter using a library like bottleneck.

Example implementation:

import Bottleneck from "bottleneck";

const limiter = new Bottleneck({
  minTime: 100, // Minimum time between requests
  maxConcurrent: 5 // Maximum concurrent requests
});

// Then wrap the request:
getContacts(args = {}) {
  return limiter.schedule(() => this._makeRequest({
    path: "/contacts",
    ...args,
  }));
},
components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1)

5-11: Enhance component documentation with supported message types

While the documentation link is helpful, consider adding examples of each supported message type (TEXT, IMAGE, TEMPLATE, INTERACTIVE) in the description for better clarity.

-  description: "Sends a WhatsApp message to a contact. [See the documentation](https://documenter.getpostman.com/view/27408936/2sa2r3a6dw)",
+  description: "Sends a WhatsApp message to a contact. Supports text, image, template, and interactive message types. [See the documentation](https://documenter.getpostman.com/view/27408936/2sa2r3a6dw)",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 38d2441 and 079c9b8.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/heyy/actions/create-contact/create-contact.mjs (1 hunks)
  • components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (1 hunks)
  • components/heyy/actions/update-contact/update-contact.mjs (1 hunks)
  • components/heyy/actions/upload-file/upload-file.mjs (1 hunks)
  • components/heyy/common/constants.mjs (1 hunks)
  • components/heyy/common/utils.mjs (1 hunks)
  • components/heyy/heyy.app.mjs (1 hunks)
  • components/heyy/package.json (2 hunks)
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/heyy/common/constants.mjs
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/heyy/actions/upload-file/upload-file.mjs
  • components/heyy/package.json
  • components/heyy/sources/new-incoming-message-instant/new-incoming-message-instant.mjs
🧰 Additional context used
🪛 Biome
components/heyy/actions/create-contact/create-contact.mjs

[error] 91-91: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/actions/update-contact/update-contact.mjs

[error] 103-103: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

components/heyy/common/utils.mjs

[error] 53-53: Use a regular expression literal instead of the RegExp constructor.

Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.

(lint/complexity/useRegexLiterals)

🔇 Additional comments (10)
components/heyy/actions/create-contact/create-contact.mjs (1)

1-4: LGTM! Imports are properly structured.

The necessary dependencies are correctly imported.

components/heyy/actions/update-contact/update-contact.mjs (6)

1-10: LGTM! Well-structured module setup with proper documentation.

The imports are appropriate and the action metadata is well-defined with a helpful documentation link.


112-114: ⚠️ Potential issue

Add response validation

The code assumes the response will always contain data.id. Add validation to handle potential errors gracefully.

Apply this diff:

-    $.export("$summary", `Successfully updated contact with ID \`${response.data.id}\`.`);
+    if (!response?.data?.id) {
+      throw new Error("Invalid response: missing contact ID");
+    }
+    $.export("$summary", `Successfully updated contact with ID \`${response.data.id}\`.`);
     return response;

Likely invalid or redundant comment.


97-108: ⚠️ Potential issue

Optimize attributes transformation

The current implementation has O(n²) complexity due to spread operator usage in reduce. This can be improved using map.

Apply this diff:

-        attributes:
-          attributes && Object.entries(attributes)
-            .reduce((acc, [
-              externalId,
-              value,
-            ]) => ([
-              ...acc,
-              {
-                externalId,
-                value,
-              },
-            ]), []),
+        attributes: attributes && Object.entries(attributes)
+          .map(([externalId, value]) => ({
+            externalId,
+            value,
+          })),

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome

[error] 103-103: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)


69-83: ⚠️ Potential issue

Validate that at least one update field is provided

According to the PR objectives, at least one optional property must be provided for updates. Currently, the code doesn't validate this requirement.

Add validation after the destructuring:

    } = this;

+   // Ensure at least one field is being updated
+   if (!phoneNumber && !firstName && !lastName && !email && 
+       !labels?.length && !attributes) {
+     throw new Error(
+       "At least one field (phoneNumber, firstName, lastName, email, " +
+       "labels, or attributes) must be provided for update"
+     );
+   }

    if (phoneNumber && !utils.isPhoneNumberValid(phoneNumber)) {

Likely invalid or redundant comment.


58-67: ⚠️ Potential issue

Add input validation and path parameter sanitization

The updateContact method needs two security improvements:

  1. Input validation for contactId
  2. Path parameter sanitization to prevent path traversal attacks

Apply this diff:

 updateContact({
   contactId, ...args
 } = {}) {
+  if (!contactId) {
+    throw new Error("contactId is required");
+  }
   return this.app.put({
-    path: `/contacts/${contactId}`,
+    path: `/contacts/${encodeURIComponent(contactId)}`,
     ...args,
   });
 },

Likely invalid or redundant comment.


11-57: ⚠️ Potential issue

Make all fields except contactId optional to match requirements

According to the PR objectives, all fields except contactId should be optional for the update-contact action. Currently, lastName, email, labels, and attributes are configured as required fields.

Apply this diff:

    lastName: {
+     optional: true,
      propDefinition: [
        app,
        "lastName",
      ],
    },
    email: {
+     optional: true,
      propDefinition: [
        app,
        "email",
      ],
    },
    labels: {
+     optional: true,
      propDefinition: [
        app,
        "labels",
      ],
    },
    attributes: {
+     optional: true,
      propDefinition: [
        app,
        "attributes",
      ],
    },

Likely invalid or redundant comment.

components/heyy/heyy.app.mjs (1)

1-154: Implementation aligns with PR objectives

The code provides a solid foundation for the requirements outlined in issue #14383:

  • Contact management through getContacts, prop definitions for contact fields
  • WhatsApp messaging support through channelId and related methods
  • API infrastructure for webhook implementation

The implementation looks good overall, with proper separation of concerns and reusable components.

components/heyy/actions/send-whatsapp-message/send-whatsapp-message.mjs (2)

1-4: LGTM!

The imports are well-organized and all are actively used in the component.


19-34: LGTM with existing validation suggestion

The phoneNumber property implementation is correct, and the previous review comment about adding phone number validation is still applicable.

Comment on lines +52 to +55
function isPhoneNumberValid(phoneNumber) {
const pattern = new RegExp("^\\+[1-9]{1}[0-9]{0,2}[2-9]{1}[0-9]{2}[2-9]{1}[0-9]{2}[0-9]{4}$");
return pattern.test(phoneNumber);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider WhatsApp's specific phone number format requirements

Since this function will be used for validating WhatsApp contact numbers (as per PR objectives), the current regex pattern might be too restrictive. WhatsApp numbers:

  • Must include country code
  • Can have different lengths based on country
  • Should not include spaces or special characters except for the '+' prefix

Consider using the following WhatsApp-compliant pattern:

 function isPhoneNumberValid(phoneNumber) {
-  const pattern = new RegExp("^\\+[1-9]{1}[0-9]{0,2}[2-9]{1}[0-9]{2}[2-9]{1}[0-9]{2}[0-9]{4}$");
+  const pattern = /^\+[1-9]\d{6,14}$/;
   return pattern.test(phoneNumber);
 }

This pattern allows:

  • Numbers starting with '+'
  • Country codes (1-9 first digit)
  • Total length between 7-15 digits (standard for international numbers)
📝 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
function isPhoneNumberValid(phoneNumber) {
const pattern = new RegExp("^\\+[1-9]{1}[0-9]{0,2}[2-9]{1}[0-9]{2}[2-9]{1}[0-9]{2}[0-9]{4}$");
return pattern.test(phoneNumber);
}
function isPhoneNumberValid(phoneNumber) {
const pattern = /^\+[1-9]\d{6,14}$/;
return pattern.test(phoneNumber);
}
🧰 Tools
🪛 Biome

[error] 53-53: Use a regular expression literal instead of the RegExp constructor.

Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.

(lint/complexity/useRegexLiterals)

Comment on lines +57 to +60
export default {
parseArray: (value) => parseArray(value)?.map(parse),
isPhoneNumberValid,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent potential undefined behavior in parseArray export

The optional chaining operator (?.) in the parseArray export could silently skip processing when parseArray(value) returns undefined, which might mask configuration errors.

Consider making the behavior more explicit:

 export default {
-  parseArray: (value) => parseArray(value)?.map(parse),
+  parseArray: (value) => {
+    const array = parseArray(value);
+    if (!array) {
+      return [];  // or throw new ConfigurationError("Invalid input: empty or undefined array")
+    }
+    return array.map(parse);
+  },
   isPhoneNumberValid,
 };
📝 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
export default {
parseArray: (value) => parseArray(value)?.map(parse),
isPhoneNumberValid,
};
export default {
parseArray: (value) => {
const array = parseArray(value);
if (!array) {
return []; // or throw new ConfigurationError("Invalid input: empty or undefined array")
}
return array.map(parse);
},
isPhoneNumberValid,
};

Comment on lines +11 to +49
props: {
app,
phoneNumber: {
propDefinition: [
app,
"phoneNumber",
],
},
firstName: {
propDefinition: [
app,
"firstName",
],
},
lastName: {
propDefinition: [
app,
"lastName",
],
},
email: {
propDefinition: [
app,
"email",
],
},
labels: {
propDefinition: [
app,
"labels",
],
},
attributes: {
propDefinition: [
app,
"attributes",
],
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing address field from PR objectives.

The PR objectives mention 'address' as an optional property, but it's not implemented in the props definition.

Add the address field to the props:

    attributes: {
      propDefinition: [
        app,
        "attributes",
      ],
    },
+   address: {
+     type: "string",
+     label: "Address",
+     description: "Contact's address",
+     optional: true,
+   },

Don't forget to include it in the data object when making the API call:

    data: {
      phoneNumber,
      firstName,
      lastName,
      email,
+     address,
      ...(labels?.length && {
📝 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
props: {
app,
phoneNumber: {
propDefinition: [
app,
"phoneNumber",
],
},
firstName: {
propDefinition: [
app,
"firstName",
],
},
lastName: {
propDefinition: [
app,
"lastName",
],
},
email: {
propDefinition: [
app,
"email",
],
},
labels: {
propDefinition: [
app,
"labels",
],
},
attributes: {
propDefinition: [
app,
"attributes",
],
},
},
props: {
app,
phoneNumber: {
propDefinition: [
app,
"phoneNumber",
],
},
firstName: {
propDefinition: [
app,
"firstName",
],
},
lastName: {
propDefinition: [
app,
"lastName",
],
},
email: {
propDefinition: [
app,
"email",
],
},
labels: {
propDefinition: [
app,
"labels",
],
},
attributes: {
propDefinition: [
app,
"attributes",
],
},
address: {
type: "string",
label: "Address",
description: "Contact's address",
optional: true,
},
},

⚠️ Potential issue

Add missing notes field from PR objectives.

The PR objectives mention 'notes' as an optional property, but it's not implemented in the props definition.

Add the notes field to the props:

    attributes: {
      propDefinition: [
        app,
        "attributes",
      ],
    },
+   notes: {
+     type: "string",
+     label: "Notes",
+     description: "Additional notes about the contact",
+     optional: true,
+   },

Don't forget to include it in the data object when making the API call:

    data: {
      phoneNumber,
      firstName,
      lastName,
      email,
+     notes,
      ...(labels?.length && {

Committable suggestion was skipped due to low confidence.

Comment on lines +43 to +119
additionalProps() {
const { msgType } = this;

const bodyText = {
type: "string",
label: "Body Text",
description: "The text of the message to send.",
};

if (msgType === constants.MSG_TYPE.TEXT) {
return {
bodyText,
};
}

if (msgType === constants.MSG_TYPE.IMAGE) {
return {
bodyText,
fileId: {
type: "string",
label: "File ID",
description: "The ID of the file to attach to the message.",
},
};
}

if (msgType === constants.MSG_TYPE.TEMPLATE) {
return {
messageTemplateId: {
type: "string",
label: "Message Template ID",
description: "The ID of the message template to use.",
optional: true,
options: async ({ page }) => {
const { data: { messageTemplates } } = await this.app.getMessageTemplates({
params: {
page,
sortBy: "updatedAt",
order: "DESC",
},
});
return messageTemplates.map(({
id: value, name: label,
}) => ({
label,
value,
}));
},
},
};
}

if (msgType === constants.MSG_TYPE.INTERACTIVE) {
return {
bodyText,
buttons: {
type: "string[]",
label: "Buttons",
description: "The buttons to include in the message. Each row should have a JSON formated string. Eg. `{ \"id\": \"STRING\", \"title\": \"STRING\" }`.",
},
headerText: {
type: "string",
label: "Header Text",
description: "The header text of the message to send.",
optional: true,
},
footerText: {
type: "string",
label: "Footer Text",
description: "The footer text of the message to send.",
optional: true,
},
};
}

return {};
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for missing required props based on message type

While the code handles different message types, it doesn't validate that required properties are provided before they're used. For example, IMAGE type requires fileId but there's no validation.

 additionalProps() {
   const { msgType } = this;
+  
+  const requiredError = (field) => `${field} is required for ${msgType} messages`;
 
   const bodyText = {
     type: "string",
     label: "Body Text",
     description: "The text of the message to send.",
+    validate: (value, { msgType }) => {
+      if (msgType === constants.MSG_TYPE.TEXT && !value) {
+        return requiredError("Body text");
+      }
+      return true;
+    },
   };

Committable suggestion was skipped due to low confidence.

Comment on lines +120 to +129
methods: {
sendWhatsappMessage({
channelId, ...args
} = {}) {
return this.app.post({
path: `/${channelId}/whatsapp_messages/send`,
...args,
});
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling in sendWhatsappMessage method

The method should handle potential API errors gracefully and provide meaningful error messages.

 sendWhatsappMessage({
   channelId, ...args
 } = {}) {
+  if (!channelId) {
+    throw new Error("Channel ID is required");
+  }
   return this.app.post({
     path: `/${channelId}/whatsapp_messages/send`,
     ...args,
+  }).catch(error => {
+    throw new Error(`Failed to send WhatsApp message: ${error.message}`);
   });
 },
📝 Committable suggestion

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

Suggested change
methods: {
sendWhatsappMessage({
channelId, ...args
} = {}) {
return this.app.post({
path: `/${channelId}/whatsapp_messages/send`,
...args,
});
},
},
methods: {
sendWhatsappMessage({
channelId, ...args
} = {}) {
if (!channelId) {
throw new Error("Channel ID is required");
}
return this.app.post({
path: `/${channelId}/whatsapp_messages/send`,
...args,
}).catch(error => {
throw new Error(`Failed to send WhatsApp message: ${error.message}`);
});
},
},

Comment on lines +130 to +160
async run({ $ }) {
const {
sendWhatsappMessage,
channelId,
phoneNumber,
msgType,
bodyText,
fileId,
messageTemplateId,
headerText,
footerText,
buttons,
} = this;

const response = await sendWhatsappMessage({
$,
channelId,
data: {
phoneNumber,
type: msgType,
bodyText,
fileId,
messageTemplateId,
headerText,
footerText,
buttons: utils.parseArray(buttons),
},
});
$.export("$summary", "Succesfully sent WhatsApp message.");
return response;
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add safe handling of optional properties in the request payload

The current implementation sends all properties to the API, including undefined ones. This should be cleaned up to only send defined values.

-    const response = await sendWhatsappMessage({
-      $,
-      channelId,
-      data: {
-        phoneNumber,
-        type: msgType,
-        bodyText,
-        fileId,
-        messageTemplateId,
-        headerText,
-        footerText,
-        buttons: utils.parseArray(buttons),
-      },
-    });
+    const data = {
+      phoneNumber,
+      type: msgType,
+    };
+
+    if (bodyText) data.bodyText = bodyText;
+    if (fileId) data.fileId = fileId;
+    if (messageTemplateId) data.messageTemplateId = messageTemplateId;
+    if (headerText) data.headerText = headerText;
+    if (footerText) data.footerText = footerText;
+    if (buttons) data.buttons = utils.parseArray(buttons);
+
+    const response = await sendWhatsappMessage({
+      $,
+      channelId,
+      data,
+    });
📝 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
async run({ $ }) {
const {
sendWhatsappMessage,
channelId,
phoneNumber,
msgType,
bodyText,
fileId,
messageTemplateId,
headerText,
footerText,
buttons,
} = this;
const response = await sendWhatsappMessage({
$,
channelId,
data: {
phoneNumber,
type: msgType,
bodyText,
fileId,
messageTemplateId,
headerText,
footerText,
buttons: utils.parseArray(buttons),
},
});
$.export("$summary", "Succesfully sent WhatsApp message.");
return response;
},
async run({ $ }) {
const {
sendWhatsappMessage,
channelId,
phoneNumber,
msgType,
bodyText,
fileId,
messageTemplateId,
headerText,
footerText,
buttons,
} = this;
const data = {
phoneNumber,
type: msgType,
};
if (bodyText) data.bodyText = bodyText;
if (fileId) data.fileId = fileId;
if (messageTemplateId) data.messageTemplateId = messageTemplateId;
if (headerText) data.headerText = headerText;
if (footerText) data.footerText = footerText;
if (buttons) data.buttons = utils.parseArray(buttons);
const response = await sendWhatsappMessage({
$,
channelId,
data,
});
$.export("$summary", "Succesfully sent WhatsApp message.");
return response;
},

@jcortes jcortes merged commit 9037ee3 into PipedreamHQ:master Oct 31, 2024
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
action New Action Request trigger / source New trigger / source request
Development

Successfully merging this pull request may close these issues.

[Components] heyy
2 participants