Skip to content

Implement comprehensive Trustpilot webhooks and review management #17613

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

Merged

Conversation

seynadio
Copy link
Contributor

@seynadio seynadio commented Jul 14, 2025

Summary

  • Enhanced trustpilot.app.ts with full authentication and API methods supporting both API key and OAuth
  • Added comprehensive constants and utilities for proper error handling and validation
  • Implemented webhook sources: review.created, review.revised, review.deleted, reply.created, invitation.sent, invitation.failed
  • Implemented actions: fetch service reviews, fetch service review by ID, fetch product reviews, fetch product review by ID, reply to service review, reply to product review
  • Added proper filtering, pagination, business unit selection, and retry logic
  • Complete webhook infrastructure with base class

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive Trustpilot integration, enabling actions to fetch and reply to product and service reviews, manage conversations, and handle webhooks.
    • Added polling-based event sources for detecting new and updated reviews, new replies, and conversation activity, supporting real-time monitoring and automation.
    • Provided advanced filtering, sorting, and pagination options for retrieving reviews and conversations.
    • Enhanced input validation, error handling, and security for all actions and sources.
  • Chores

    • Updated package version and dependencies for improved compatibility.

Copy link

vercel bot commented Jul 14, 2025

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) Jul 28, 2025 3:21pm

Copy link

vercel bot commented Jul 14, 2025

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

A member of the Team first needs to authorize it.

@adolfo-pd adolfo-pd added the User submitted Submitted by a user label Jul 14, 2025
Copy link
Contributor

coderabbitai bot commented Jul 14, 2025

Warning

Rate limit exceeded

@Afstkla has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 12 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between bce521a and b770dea.

📒 Files selected for processing (1)
  • components/trustpilot/trustpilot.app.mjs (1 hunks)

Walkthrough

This update introduces a comprehensive Trustpilot integration, adding a full-featured app, utility modules, and a suite of action and source modules for interacting with Trustpilot’s API. The changes implement robust review, reply, conversation, and webhook management, with polling-based event sources for new and updated reviews, replies, and conversations. Supporting modules provide constants, utilities, and configuration.

Changes

File(s) Change Summary
components/trustpilot/app/trustpilot.app.ts
components/trustpilot/trustpilot.app.mjs
Full implementation of Trustpilot app with prop definitions, API methods for reviews, products, conversations, webhooks, and auth.
components/trustpilot/common/constants.mjs
components/trustpilot/common/utils.mjs
Added constants for API endpoints, events, enums, and utility functions for input sanitization, validation, and parsing.
components/trustpilot/actions/fetch-product-review-by-id/...
components/trustpilot/actions/fetch-product-reviews/...
components/trustpilot/actions/fetch-service-review-by-id/...
components/trustpilot/actions/fetch-service-reviews/...
components/trustpilot/actions/reply-to-product-review/...
components/trustpilot/actions/reply-to-service-review/...
Added new action modules for fetching and replying to service and product reviews by ID or with filters.
components/trustpilot/sources/common/polling.mjs Introduced a reusable polling base for Trustpilot sources, handling deduplication and state.
components/trustpilot/sources/new-conversations/...
components/trustpilot/sources/updated-conversations/...
Added sources for new and updated conversations, using polling to emit events.
components/trustpilot/sources/new-product-review-replies/...
components/trustpilot/sources/new-product-reviews/...
components/trustpilot/sources/updated-product-reviews/...
Added sources for new and updated product reviews and replies, using polling.
components/trustpilot/sources/new-service-review-replies/...
components/trustpilot/sources/new-service-reviews/...
components/trustpilot/sources/updated-service-reviews/...
Added sources for new and updated service reviews and replies, using polling.
components/trustpilot/package.json Updated version, entry point, and dependencies.
components/trustpilot/.gitignore Modified ignore rules, now only ignoring .js and dist/, not .mjs.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Action/Source
    participant TrustpilotApp
    participant TrustpilotAPI

    User->>Action/Source: Triggers action/source
    Action/Source->>TrustpilotApp: Calls method (e.g., getServiceReviews)
    TrustpilotApp->>TrustpilotAPI: Sends HTTP request
    TrustpilotAPI-->>TrustpilotApp: Returns data/response
    TrustpilotApp-->>Action/Source: Returns parsed result
    Action/Source-->>User: Emits event or returns action result
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~75–120 minutes

Suggested labels

ai-assisted

Poem

In burrows deep, this code now hops,
Trustpilot’s world, with polling stops.
Reviews and replies, both new and old,
Conversations tracked, their stories told.
With actions and sources, robust and bright,
This rabbit’s work will run all night!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a 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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this 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.

@pipedream-component-development
Copy link
Collaborator

Thank you so much for submitting this! We've added it to our backlog to review, and our team has been notified.

@pipedream-component-development
Copy link
Collaborator

Thanks for submitting this PR! When we review PRs, we follow the Pipedream component guidelines. If you're not familiar, here's a quick checklist:

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

🧹 Nitpick comments (3)
components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1)

30-48: Consider enhancing error context.

The error handling is functional but could provide more context about the specific failure mode.

    } catch (error) {
-      throw new Error(`Failed to fetch service review: ${error.message}`);
+      throw new Error(`Failed to fetch service review ${reviewId} for business unit ${businessUnitId}: ${error.message}`);
    }
components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1)

49-62: Consider adding message length validation.

While the empty message validation is good, consider adding a maximum length validation to prevent API errors from overly long messages.

    if (!message || message.trim().length === 0) {
      throw new Error("Reply message cannot be empty");
    }
+
+    if (message.trim().length > 1000) { // Adjust limit based on Trustpilot API
+      throw new Error("Reply message exceeds maximum length");
+    }
components/trustpilot/app/trustpilot.app.ts (1)

65-68: Consider improving the label formatting for better readability.

The current label generation produces labels like "created at desc". Consider enhancing the formatting for better user experience.

-        label: key.replace(/_/g, " ").toLowerCase(),
+        label: key.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, l => l.toUpperCase()).replace(/\s(asc|desc)$/i, (match, dir) => ` (${dir.toUpperCase()})`),

This would produce labels like "Created At (DESC)" which is more readable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e21d334 and 2b663f1.

📒 Files selected for processing (18)
  • components/trustpilot/.gitignore (0 hunks)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
  • components/trustpilot/common/constants.mjs (1 hunks)
  • components/trustpilot/common/utils.mjs (1 hunks)
  • components/trustpilot/package.json (1 hunks)
  • components/trustpilot/sources/common/webhook.mjs (1 hunks)
  • components/trustpilot/sources/invitation-failed/invitation-failed.mjs (1 hunks)
  • components/trustpilot/sources/invitation-sent/invitation-sent.mjs (1 hunks)
  • components/trustpilot/sources/reply-created/reply-created.mjs (1 hunks)
  • components/trustpilot/sources/review-created/review-created.mjs (1 hunks)
  • components/trustpilot/sources/review-deleted/review-deleted.mjs (1 hunks)
  • components/trustpilot/sources/review-revised/review-revised.mjs (1 hunks)
💤 Files with no reviewable changes (1)
  • components/trustpilot/.gitignore
🧰 Additional context used
🧠 Learnings (13)
components/trustpilot/package.json (1)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.
components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/trustpilot/sources/review-deleted/review-deleted.mjs (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/trustpilot/sources/review-created/review-created.mjs (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/sources/common/webhook.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common.mjs:97-98
Timestamp: 2024-07-24T02:05:59.531Z
Learning: The `processTimerEvent` method in the `components/salesforce_rest_api/sources/common.mjs` file is intentionally left unimplemented to enforce that subclasses must implement this method, similar to an abstract class in object-oriented programming.
components/trustpilot/sources/invitation-failed/invitation-failed.mjs (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
components/trustpilot/sources/review-revised/review-revised.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
components/trustpilot/sources/reply-created/reply-created.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/sources/invitation-sent/invitation-sent.mjs (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
components/trustpilot/common/constants.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/app/trustpilot.app.ts (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
🔇 Additional comments (30)
components/trustpilot/package.json (1)

15-15: LGTM! JSON structure fix is correct.

The missing closing brace for the publishConfig object has been properly added.

components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1)

1-23: LGTM! Action structure follows Pipedream conventions.

The import, property definitions, and overall structure are well-implemented and consistent with Pipedream action patterns.

components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (2)

36-38: Excellent input validation.

The validation for empty or whitespace-only messages is a good practice that prevents API errors and improves user experience.


40-48: Good implementation with proper message trimming.

The message trimming before sending the API request and the summary formatting are well-implemented.

components/trustpilot/sources/review-deleted/review-deleted.mjs (2)

1-16: LGTM! Webhook source follows proper patterns.

The extension of the common webhook base and event specification are correctly implemented.


17-22: Excellent defensive programming with fallback handling.

The fallback to "Anonymous" for missing consumer display names is a good practice that prevents summary generation errors.

components/trustpilot/sources/reply-created/reply-created.mjs (2)

1-16: LGTM! Consistent webhook source implementation.

The extension of the common webhook base and event specification follow the established pattern correctly.


17-24: Good text truncation logic for preview.

The 50-character truncation with ellipsis provides a good balance between preview content and summary length, improving readability in event streams.

components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (4)

29-31: Good validation logic for empty messages.

The validation correctly checks for both null/undefined and whitespace-only messages, preventing empty replies from being sent.


39-39: Summary format follows best practices.

The summary message format correctly follows the learned pattern: "Successfully [action] [details]" which provides clear feedback to users.


41-49: Comprehensive return object with useful metadata.

The returned object includes success flag, API response, and metadata with review ID, message length, and timestamp - all valuable for debugging and workflow integration.


50-52: Proper error handling with descriptive messages.

The error handling correctly wraps the original error message in a more descriptive context, making it easier to diagnose issues.

components/trustpilot/sources/review-revised/review-revised.mjs (2)

4-5: Proper extension of common webhook base.

The spread operator correctly extends the common webhook functionality, following the established pattern for webhook sources.


17-23: Good summary generation with fallback values.

The summary generation correctly extracts review data and provides appropriate fallback values ("N/A" for stars, "Anonymous" for consumer name) when data is missing, ensuring robust handling of incomplete webhook payloads.

components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1)

18-38: Well-structured fetch action with proper error handling.

The implementation correctly follows the standard pattern for fetch actions: extract parameters, call API method, export summary, and return data with metadata. The error handling provides descriptive messages and the summary format follows best practices.

components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (3)

53-60: Good validation constraints on custom offset prop.

The offset prop correctly includes validation constraints (min: 0) and a sensible default value (0), preventing invalid pagination parameters.


86-88: Proper response destructuring and summary format.

The response is correctly destructured into reviews and pagination, and the summary message follows the learned pattern by including the count of fetched reviews.


90-104: Comprehensive return object with filters metadata.

The returned object includes reviews, pagination, and detailed metadata with applied filters, providing excellent transparency for debugging and workflow integration.

components/trustpilot/sources/review-created/review-created.mjs (2)

4-8: Proper webhook source structure and naming.

The source correctly extends the common webhook base and uses an appropriate name "Review Created" for events about new items, following component guidelines.


17-23: Descriptive summary generation with robust fallback handling.

The summary generation creates a clear, informative message that includes star rating, consumer name, and business unit ID, with appropriate fallback values for missing data.

components/trustpilot/sources/invitation-sent/invitation-sent.mjs (3)

1-11: LGTM!

The module setup and metadata are properly configured for the invitation sent webhook source.


14-16: LGTM!

Correctly specifies the webhook event type this source handles.


17-23: LGTM!

Good use of optional chaining and fallback values for robust summary generation.

components/trustpilot/sources/invitation-failed/invitation-failed.mjs (1)

1-39: LGTM!

Well-structured webhook source with proper error message handling in the summary generation.

components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1)

62-108: LGTM!

Well-implemented action with proper error handling, structured response, and informative summary export.

components/trustpilot/common/utils.mjs (1)

25-51: LGTM!

The parsing functions are well-structured with good use of optional chaining and sensible defaults.

Also applies to: 58-74, 81-93

components/trustpilot/common/constants.mjs (1)

1-78: LGTM! Well-organized constants module.

This constants file provides a clean, centralized location for all Trustpilot integration constants. The structure is logical with proper categorization of endpoints, events, enums, and configuration values.

components/trustpilot/app/trustpilot.app.ts (3)

103-157: Excellent implementation of authentication and retry logic.

The authentication supports both API key and OAuth methods, and the retry mechanism with exponential backoff for rate-limited requests is well-implemented. The error handling provides clear, actionable error messages.


160-259: Well-structured API methods with comprehensive validation.

The business unit and service review methods are well-implemented with:

  • Proper input validation using utility functions
  • Comprehensive parameter support with sensible defaults
  • Correct pagination handling
  • Consistent error messages

262-392: Excellent comprehensive Trustpilot integration implementation.

The product review methods mirror the service review methods appropriately, maintaining consistency. The overall implementation demonstrates:

  • Consistent patterns across all method types
  • Proper error handling and validation throughout
  • Good use of shared utilities and constants
  • Clean, maintainable code structure

This is production-ready code (pending the webhook signature validation implementation).

this._setWebhookId(webhook.id);

// Generate and store a secret for signature validation
const secret = `tp_${Math.random().toString(36).substring(2, 15)}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Use cryptographically secure random generation for the secret.

Math.random() is not cryptographically secure and should not be used for generating secrets.

Use Node.js crypto module for secure random generation:

-const secret = `tp_${Math.random().toString(36).substring(2, 15)}`;
+const crypto = await import('crypto');
+const secret = `tp_${crypto.randomBytes(16).toString('hex')}`;

Add the import at the top of the file:

import { randomBytes } from "crypto";
🤖 Prompt for AI Agents
In components/trustpilot/sources/common/webhook.mjs at line 91, replace the use
of Math.random() for generating the secret with a cryptographically secure
method. Import randomBytes from the Node.js crypto module at the top of the
file, then generate the secret using randomBytes to create a secure random
string instead of Math.random().

Comment on lines 63 to 66
validateSignature(body, signature) {
// TODO: Implement signature validation when Trustpilot provides it
return true;
},
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

Implement proper signature validation.

The TODO indicates this critical security feature is not implemented. Webhook signature validation is essential to ensure requests are authentic.

Would you like me to help implement the signature validation logic or open an issue to track this security requirement?

🤖 Prompt for AI Agents
In components/trustpilot/sources/common/webhook.mjs at lines 63 to 66, the
validateSignature method currently returns true without performing any actual
validation, which is a security risk. Implement proper signature validation by
using the signature provided by Trustpilot to verify the authenticity of the
webhook payload, typically by computing a hash or HMAC of the body with a shared
secret and comparing it to the signature. If the exact validation method is
unknown, open an issue to track this security requirement and ensure it is
addressed once Trustpilot provides the necessary details.

## Overview
Complete Trustpilot integration using polling approach (webhooks not supported by Trustpilot API).

## Features Implemented

### Authentication & Core App
- Enhanced trustpilot.app.ts with OAuth and API key authentication
- Added comprehensive API methods for reviews, products, and conversations
- Support for both public and private endpoints
- Proper error handling, validation, and retry logic with rate limiting

### Actions (6 total)
- **fetch-service-reviews** - Get service reviews with filtering and pagination
- **fetch-service-review-by-id** - Get specific service review
- **fetch-product-reviews** - Get product reviews with filtering and pagination
- **fetch-product-review-by-id** - Get specific product review
- **reply-to-service-review** - Reply to service reviews
- **reply-to-product-review** - Reply to product reviews

### Polling Sources (8 total)
- **new-service-reviews** - New service reviews (public + private endpoints)
- **updated-service-reviews** - Updated/revised service reviews
- **new-product-reviews** - New product reviews
- **updated-product-reviews** - Updated/revised product reviews
- **new-service-review-replies** - New replies to service reviews
- **new-product-review-replies** - New replies to product reviews
- **new-conversations** - New conversations started
- **updated-conversations** - Updated conversations (new messages)

### Technical Implementation
- 15-minute polling intervals following Google Drive pattern
- Smart deduplication by reviewId + timestamp
- Business unit filtering (optional)
- 24-hour lookback on first run
- Comprehensive constants and utilities
- Proper pagination and error handling

## API Endpoints Used
- `/business-units/{businessUnitId}/reviews` (public)
- `/private/business-units/{businessUnitId}/reviews` (private service)
- `/private/product-reviews/business-units/{businessUnitId}/reviews` (products)
- `/private/conversations` (conversations)
- All reply endpoints for posting responses

Addresses all requirements from https://developers.trustpilot.com/introduction/
@seynadio seynadio force-pushed the trustpilot-webhooks-and-reviews branch from e7cee0f to 47cee75 Compare July 14, 2025 15:05
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: 2

♻️ Duplicate comments (1)
components/trustpilot/app/trustpilot.app.ts (1)

499-502: TODO: Implement webhook signature validation for security.

The validateWebhookSignature method currently always returns true, which could pose a security risk if webhook verification is required. This should be implemented before using webhooks in production.

Would you like me to help implement the webhook signature validation or create an issue to track this security-critical task?

🧹 Nitpick comments (4)
components/trustpilot/app/trustpilot.app.ts (4)

34-46: Consider logging errors in options function for better debugging.

The error handling in the businessUnitId options function returns an empty array on error, which provides a good user experience but may mask underlying issues that developers need to be aware of.

Consider adding more detailed logging:

} catch (error) {
- console.error("Error fetching business units:", error);
+ console.error("Error fetching business units:", error.message || error);
+ console.error("Full error details:", JSON.stringify(error, null, 2));
  return [];
}

140-143: Enhance error message with additional context.

The error handling could provide more debugging information by including the endpoint and method in the error message.

Add more context to error messages:

} catch (error) {
  const parsedError = parseApiError(error);
- throw new Error(`Trustpilot API Error: ${parsedError.message} (${parsedError.code})`);
+ throw new Error(`Trustpilot API Error [${method} ${endpoint}]: ${parsedError.message} (${parsedError.code})`);
}

146-157: Add exponential backoff jitter to prevent thundering herd.

The retry logic uses a predictable delay pattern which could cause multiple clients to retry simultaneously. Adding jitter would distribute the load more evenly.

Add jitter to the retry delay:

if (retries > 0 && error.response?.status === HTTP_STATUS.TOO_MANY_REQUESTS) {
- const delay = Math.min(RETRY_CONFIG.INITIAL_DELAY * (RETRY_CONFIG.MAX_RETRIES - retries + 1), RETRY_CONFIG.MAX_DELAY);
+ const baseDelay = Math.min(RETRY_CONFIG.INITIAL_DELAY * (RETRY_CONFIG.MAX_RETRIES - retries + 1), RETRY_CONFIG.MAX_DELAY);
+ const jitter = Math.random() * 0.5 * baseDelay; // Add up to 50% jitter
+ const delay = baseDelay + jitter;
  await sleep(delay);
  return this._makeRequestWithRetry(config, retries - 1);
}

505-508: Consider removing or improving the debugging method.

The authKeys method appears to be for debugging purposes. Consider either removing it from production code or improving its implementation with better error handling.

Either remove the method if it's not needed, or improve it:

- authKeys() {
-   console.log("Auth keys:", Object.keys(this.$auth || {}));
-   return Object.keys(this.$auth || {});
- },
+ // For debugging authentication configuration
+ debugAuthKeys() {
+   const keys = Object.keys(this.$auth || {});
+   console.log("Available auth keys:", keys);
+   console.log("Auth configuration status:", {
+     hasApiKey: !!this.$auth?.api_key,
+     hasOAuthToken: !!this.$auth?.oauth_access_token,
+   });
+   return keys;
+ },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7cee0f and 47cee75.

📒 Files selected for processing (20)
  • components/trustpilot/.gitignore (0 hunks)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
  • components/trustpilot/common/constants.mjs (1 hunks)
  • components/trustpilot/common/utils.mjs (1 hunks)
  • components/trustpilot/package.json (1 hunks)
  • components/trustpilot/sources/common/polling.mjs (1 hunks)
  • components/trustpilot/sources/new-conversations/new-conversations.mjs (1 hunks)
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1 hunks)
  • components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (1 hunks)
💤 Files with no reviewable changes (1)
  • components/trustpilot/.gitignore
✅ Files skipped from review due to trivial changes (1)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs
🚧 Files skipped from review as they are similar to previous changes (17)
  • components/trustpilot/package.json
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs
  • components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs
  • components/trustpilot/sources/updated-conversations/updated-conversations.mjs
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs
  • components/trustpilot/sources/new-conversations/new-conversations.mjs
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs
  • components/trustpilot/common/utils.mjs
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs
  • components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs
  • components/trustpilot/common/constants.mjs
  • components/trustpilot/sources/common/polling.mjs
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/app/trustpilot.app.ts (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
🔇 Additional comments (1)
components/trustpilot/app/trustpilot.app.ts (1)

2-12: Missing RATING_SCALE import from constants.

The RATING_SCALE constant is used on line 58 but is not imported from the constants file. This will cause a reference error.

Add RATING_SCALE to the imports:

import { 
  BASE_URL, 
  ENDPOINTS, 
  DEFAULT_LIMIT, 
  MAX_LIMIT, 
  SORT_OPTIONS,
+ RATING_SCALE,
  RETRY_CONFIG,
  HTTP_STATUS,
} from "../common/constants.mjs";
⛔ Skipped due to learnings
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.

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: 0

♻️ Duplicate comments (2)
components/trustpilot/app/trustpilot.app.ts (2)

105-120: Authentication header method needs validation.

The authentication method should validate that at least one authentication method is configured to provide clearer error messages.


242-284: Consider extracting common review fetching logic.

The getServiceReviews and getProductReviews methods share nearly identical logic with only the endpoint differing. This violates the DRY principle.

🧹 Nitpick comments (4)
components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (1)

9-9: Consider removing redundant "New" prefix from the name.

Based on Pipedream component guidelines, the "New" prefix is only required when emits are limited to new items. Since this source emits events for updated items, the name could be simplified to "Updated Product Reviews" to avoid redundancy.

-  name: "New Updated Product Reviews",
+  name: "Updated Product Reviews",
components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1)

9-9: Consider removing redundant "New" prefix from the name.

Similar to the product reviews source, this name could be simplified to "Updated Conversations" to avoid redundancy, following Pipedream guidelines for sources that emit updated items rather than new items.

-  name: "New Updated Conversations",
+  name: "Updated Conversations",
components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (1)

9-9: Consider removing redundant "New" prefix from the name.

Consistent with the other updated sources, this name could be simplified to "Updated Service Reviews" to follow Pipedream guidelines for sources that emit updated items.

-  name: "New Updated Service Reviews",
+  name: "Updated Service Reviews",
components/trustpilot/sources/common/polling.mjs (1)

116-137: Error handling in fetchItems could be improved.

The method handles different response formats well, but the error logging exposes potentially sensitive information and should be more generic in production.

Consider sanitizing error logs to avoid exposing sensitive information:

      } catch (error) {
-       console.error(`Error fetching items with ${method}:`, error);
+       console.error(`Error fetching items with ${method}:`, error.message);
        throw error;
      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47cee75 and 404d68f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
  • components/trustpilot/common/constants.mjs (1 hunks)
  • components/trustpilot/common/utils.mjs (1 hunks)
  • components/trustpilot/package.json (1 hunks)
  • components/trustpilot/sources/common/polling.mjs (1 hunks)
  • components/trustpilot/sources/new-conversations/new-conversations.mjs (1 hunks)
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1 hunks)
  • components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (12)
  • components/trustpilot/package.json
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs
  • components/trustpilot/sources/new-conversations/new-conversations.mjs
  • components/trustpilot/common/constants.mjs
🧰 Additional context used
🧠 Learnings (6)
components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/sources/updated-conversations/updated-conversations.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/common/utils.mjs (1)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14229
File: components/americommerce/actions/update-customer/update-customer.mjs:89-94
Timestamp: 2024-10-08T16:42:59.225Z
Learning: When defining boolean properties in AmeriCommerce components (e.g., in `update-customer.mjs`), ensure that the label and description are consistent and clearly indicate the intent, especially when using negations like "No Account", to avoid confusion.
components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/sources/common/polling.mjs (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common.mjs:97-98
Timestamp: 2024-07-24T02:05:59.531Z
Learning: The `processTimerEvent` method in the `components/salesforce_rest_api/sources/common.mjs` file is intentionally left unimplemented to enforce that subclasses must implement this method, similar to an abstract class in object-oriented programming.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
components/trustpilot/app/trustpilot.app.ts (4)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The `common-webhook-methods.mjs` object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like `generateWebhookMeta` and `getEventType` to enforce implementation in subclasses.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15436
File: components/printful/printful.app.mjs:55-63
Timestamp: 2025-01-29T22:59:38.825Z
Learning: Console.log statements should be removed before merging PRs to maintain code quality and prevent potential security risks from exposing sensitive information in logs.
🧬 Code Graph Analysis (2)
components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (8)
components/trustpilot/common/constants.mjs (4)
  • SOURCE_TYPES (102-108)
  • SOURCE_TYPES (102-108)
  • SORT_OPTIONS (58-65)
  • SORT_OPTIONS (58-65)
components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs (4)
  • stars (32-32)
  • consumerName (33-33)
  • productName (34-34)
  • businessUnit (35-35)
components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs (3)
  • stars (33-33)
  • consumerName (34-34)
  • businessUnit (35-35)
components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (3)
  • stars (32-32)
  • consumerName (33-33)
  • businessUnit (34-34)
components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs (2)
  • consumerName (63-63)
  • productName (62-62)
components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs (1)
  • consumerName (62-62)
components/trustpilot/sources/new-conversations/new-conversations.mjs (1)
  • businessUnit (36-36)
components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1)
  • businessUnit (36-36)
components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (2)
components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1)
  • review (32-35)
components/trustpilot/common/utils.mjs (1)
  • error (199-201)
🪛 Biome (1.9.4)
components/trustpilot/common/utils.mjs

[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 35-35: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)

🔇 Additional comments (31)
components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (2)

1-18: LGTM! Well-structured action component.

The action follows Pipedream component best practices with proper imports, metadata, and prop definitions. The use of propDefinition for reviewId ensures consistency with the app's prop definitions.


19-39: Good error handling and structured response.

The implementation properly handles errors with descriptive messages and returns well-structured data with both the review content and metadata. The metadata includes useful information like the reviewId and timestamp.

components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (1)

15-39: LGTM! Consistent implementation with proper fallbacks.

The source correctly implements the required methods and provides robust fallback values for missing data in the summary generation. The polling parameters and source type are appropriately configured.

components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1)

31-40: LGTM! Comprehensive fallback logic for summary generation.

The summary generation method handles various data structures with multiple fallback options for participant names, subjects, and message counts. This provides robust event summaries even when data is incomplete.

components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (1)

15-38: LGTM! Consistent implementation across review sources.

The source follows the same pattern as the product reviews source with appropriate method implementations and fallback handling in the summary generation.

components/trustpilot/common/utils.mjs (8)

6-18: LGTM! Comprehensive HTML escaping implementation.

The HTML escaping function properly handles all common XSS vectors including forward slashes and single quotes. The regex and replacement map are well-defined for security.


26-43: Good sanitization with appropriate control character handling.

The function properly removes harmful control characters while preserving newlines and tabs. The ESLint disable comment is appropriate here as the regex intentionally uses control characters for sanitization purposes.


51-65: LGTM! Previous review feedback has been addressed.

The URL building function now uses split/join instead of string replace to avoid regex issues and properly encodes parameter values with encodeURIComponent. This addresses the previous review concern about handling special characters.


72-100: Well-structured data parsing with security considerations.

The review parsing function properly applies HTML escaping to user-generated content fields while preserving structured data. The nested object handling is appropriate.


151-170: LGTM! ID validation addresses previous feedback.

The validation functions now properly enforce the 24-character hexadecimal format for MongoDB ObjectIDs, addressing the previous review comment about more specific validation requirements.


177-190: Good parameter filtering logic.

The function properly filters out null, undefined, and empty string values to clean up API requests.


197-216: Comprehensive error parsing with fallbacks.

The error parsing function handles both API response errors and general errors with appropriate fallback values and structured error information.


223-225: Simple and effective utility function.

The sleep function provides a clean promise-based delay mechanism for retry logic.

components/trustpilot/sources/common/polling.mjs (7)

1-17: Well-structured documentation and rationale.

The comprehensive documentation explaining the choice of polling over webhooks provides clear reasoning for the architectural decision. The rationale covers reliability, simplicity, data consistency, and authentication compatibility - all valid technical considerations for a Pipedream integration.


18-36: Props configuration follows Pipedream best practices.

The props structure correctly implements:

  • Trustpilot app dependency
  • Database service for state persistence
  • Timer with configurable intervals from constants
  • Optional business unit filtering with proper prop definition reference

37-64: State management methods are well-implemented.

The state management follows good patterns:

  • Clear separation of concerns with private methods
  • Proper cleanup mechanism for seen items to prevent memory bloat
  • Sensible default retention period (72 hours)
  • Efficient cleanup using timestamp-based filtering

65-80: Abstract method pattern correctly implemented.

The abstract methods follow the pattern seen in retrieved learnings where base classes intentionally leave methods unimplemented to enforce subclass implementation. The getPollingMethod() properly throws an error while getSourceType() and getPollingParams() provide sensible defaults.


81-115: Item processing logic is robust.

The deduplication and metadata generation logic correctly:

  • Handles different source types (new vs updated)
  • Uses appropriate timestamps for different event types
  • Generates unique keys combining ID and timestamp
  • Provides extensible summary generation

138-183: Core polling logic is well-architected.

The pollForItems method implements solid polling patterns:

  • Proper lookback handling for first runs
  • Comprehensive deduplication using seen items tracking
  • Chronological emission (oldest first) for proper event ordering
  • State persistence and cleanup
  • Good error handling and logging

184-188: Simple and effective run method.

The run method correctly delegates to the polling logic, keeping the interface clean and focused.

components/trustpilot/app/trustpilot.app.ts (11)

1-26: Comprehensive imports and dependencies.

The imports cover all necessary utilities and constants, showing good separation of concerns between the app file and utility modules.


30-102: Well-structured prop definitions with dynamic options.

The prop definitions are comprehensive and follow Pipedream best practices:

  • Proper type definitions and validation
  • Dynamic options for business units
  • Sensible defaults and optional flags
  • Good error handling in async options

122-146: Base request method is well-implemented.

The _makeRequest method correctly handles:

  • URL construction and header management
  • Parameter formatting using utility functions
  • Timeout configuration
  • Error parsing and meaningful error messages

148-159: Retry logic follows best practices.

The retry wrapper correctly implements exponential backoff for rate limiting (429 errors) with proper delay calculation and maximum retry limits.


161-183: Business unit methods are robust.

Both methods include proper validation using utility functions and handle pagination correctly. The search method safely handles missing response properties.


185-239: Public review methods are well-implemented.

The public methods correctly:

  • Validate input parameters
  • Handle pagination with proper offset-to-page conversion
  • Use retry logic for reliability
  • Parse responses consistently

286-326: Service review methods include proper validation.

The methods correctly validate inputs and implement message sanitization for replies. The warning about truncation is helpful for users.


328-407: Product review methods mirror service review patterns.

The product review methods follow the same patterns as service reviews, maintaining consistency across the API. The validation and sanitization logic is properly implemented.


409-476: Conversation methods are comprehensive.

The conversation methods provide full CRUD operations with proper validation, pagination, and message sanitization consistent with other reply methods.


478-521: Webhook management methods are complete.

The webhook methods provide comprehensive management capabilities with proper validation for URLs, events, and IDs. The optional business unit filtering is well-implemented.


523-547: Webhook signature validation is properly implemented.

The webhook signature validation correctly implements HMAC-SHA256 with constant-time comparison to prevent timing attacks. This addresses the security concern from previous reviews.

The implementation properly:

  • Validates required parameters
  • Handles both string and object payloads
  • Uses crypto.timingSafeEqual for security
  • Follows Trustpilot's webhook signature format

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: 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 404d68f and c79d7f3.

📒 Files selected for processing (2)
  • components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs (1 hunks)
  • components/freshdesk/freshdesk.app.mjs (1 hunks)
🔇 Additional comments (4)
components/freshdesk/freshdesk.app.mjs (1)

269-278: LGTM! Method follows established patterns.

The addNoteToTicket method is well-implemented and consistent with other methods in the file. It properly uses the internal _makeRequest method and follows the established parameter destructuring pattern.

components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs (3)

1-11: LGTM! Proper imports and metadata structure.

The imports are correct, the key follows the expected naming pattern, and the documentation link is helpful for users.


63-65: LGTM! Proper input validation.

The validation correctly checks for empty or whitespace-only content and throws an appropriate error with a clear message.


67-94: LGTM! Well-structured main logic.

The implementation properly handles optional parameters, performs appropriate type conversions, and provides good user feedback through the summary message.

Comment on lines 18 to 22
body: {
type: "string",
label: "Note Body",
description: "Content of the note in HTML format",
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mark the body prop as required.

The body prop should be marked as required since the validation logic treats it as mandatory.

     body: {
       type: "string",
       label: "Note Body",
       description: "Content of the note in HTML format",
+      required: true,
     },
📝 Committable suggestion

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

Suggested change
body: {
type: "string",
label: "Note Body",
description: "Content of the note in HTML format",
},
body: {
type: "string",
label: "Note Body",
description: "Content of the note in HTML format",
required: true,
},
🤖 Prompt for AI Agents
In components/freshdesk/actions/add-note-to-ticket/add-note-to-ticket.mjs
between lines 18 and 22, the body property is missing a required flag. Add a
required: true attribute to the body property definition to ensure it is treated
as mandatory in validation.

@Afstkla Afstkla force-pushed the trustpilot-webhooks-and-reviews branch from c79d7f3 to 404d68f Compare July 18, 2025 12:06
@GTFalcao GTFalcao self-assigned this Jul 18, 2025
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.

Hey @seynadio thanks for your contribution!

I've left a few comments that we need to adjust before moving forward. In some cases the same adjustment should be made in all components that behave in the same way.

},
};
} catch (error) {
throw new Error(`Failed to fetch product review: ${error.message}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ideally we shouldn't be try/catching here, because @pipedream/platform's axios already handles error responses and emits metadata for the request and response - this would make it harder to debug. The same applies for all components using a try/catch here in the request method

Afstkla and others added 2 commits July 21, 2025 08:59
…ollow best practices

- Update @pipedream/platform to ^3.1.0
- Add authentication validation in _getAuthHeaders
- Extract common review fetching logic to reduce duplication (DRY)
- Remove unnecessary try/catch from _makeRequest
- Use ConfigurationError for user input errors
- Remove publishedAt from all components
- Update polling descriptions to be more generic
- Improve code maintainability and error handling

Co-Authored-By: Claude <noreply@anthropic.com>
…Script errors

- Increment trustpilot component version from 0.0.1 to 0.1.0
- Update pnpm lockfile to sync @pipedream/platform dependency (^3.0.0 -> ^3.1.0)
- Fix TypeScript compilation errors by adding proper type annotations
- Fix crypto import to use ES module syntax

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c79d7f3 and a75316b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
  • components/trustpilot/package.json (2 hunks)
  • components/trustpilot/sources/new-conversations/new-conversations.mjs (1 hunks)
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs (1 hunks)
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-conversations/updated-conversations.mjs (1 hunks)
  • components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs (1 hunks)
  • components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs
🚧 Files skipped from review as they are similar to previous changes (14)
  • components/trustpilot/package.json
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs
  • components/trustpilot/sources/new-product-review-replies/new-product-review-replies.mjs
  • components/trustpilot/sources/updated-product-reviews/updated-product-reviews.mjs
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs
  • components/trustpilot/sources/new-conversations/new-conversations.mjs
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs
  • components/trustpilot/sources/updated-conversations/updated-conversations.mjs
  • components/trustpilot/sources/new-service-review-replies/new-service-review-replies.mjs
  • components/trustpilot/sources/new-product-reviews/new-product-reviews.mjs
  • components/trustpilot/sources/new-service-reviews/new-service-reviews.mjs
  • components/trustpilot/sources/updated-service-reviews/updated-service-reviews.mjs
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/app/trustpilot.app.ts (4)

Learnt from: GTFalcao
PR: #16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #15436
File: components/printful/printful.app.mjs:55-63
Timestamp: 2025-01-29T22:59:38.825Z
Learning: Console.log statements should be removed before merging PRs to maintain code quality and prevent potential security risks from exposing sensitive information in logs.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Lint Code Base
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (9)
components/trustpilot/app/trustpilot.app.ts (9)

1-25: LGTM! Well-structured imports.

The imports are comprehensive and properly organized, including all necessary platform modules, Node.js crypto for webhook validation, and utility functions from the common modules.


105-158: LGTM! Robust authentication and request handling.

Excellent implementation that addresses previous feedback:

  • Validates authentication configuration before making requests
  • Implements proper retry logic with exponential backoff for rate limiting
  • Includes appropriate timeouts and error handling
  • Uses utility functions for consistent parameter formatting

161-182: LGTM! Well-implemented business unit methods.

Good implementation with proper input validation, consistent utility usage, and clear error messages. The search method appropriately supports pagination parameters.


185-238: LGTM! Solid public review methods implementation.

Well-structured methods with proper validation, pagination handling, and consistent response formatting. The retry logic enhances reliability.


241-283: LGTM! Excellent DRY principle implementation.

Great refactoring that addresses the previous feedback about code duplication. The _getReviews helper method eliminates redundancy while maintaining clean, readable code.


334-347: LGTM! Consistent product review methods.

Good implementation that properly reuses the _getReviews helper method and handles product-specific API endpoints correctly.


376-430: LGTM! Well-structured conversation methods.

Consistent implementation with proper pagination, validation, and error handling that follows the established patterns throughout the app.


445-487: LGTM! Comprehensive webhook management methods.

Well-implemented webhook methods with proper validation, clean API interactions, and support for both business unit specific and global webhook configurations.


490-514: LGTM! Secure webhook utilities implementation.

Excellent implementation that addresses the previous security feedback:

  • Proper HMAC-SHA256 signature validation
  • Timing-safe comparison prevents timing attacks
  • Handles both string and object payloads correctly
  • Follows Trustpilot's webhook security standards

Afstkla and others added 3 commits July 21, 2025 13:40
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e53b455 and 5e68182.

📒 Files selected for processing (1)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/app/trustpilot.app.ts (4)

Learnt from: GTFalcao
PR: #16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #15436
File: components/printful/printful.app.mjs:55-63
Timestamp: 2025-01-29T22:59:38.825Z
Learning: Console.log statements should be removed before merging PRs to maintain code quality and prevent potential security risks from exposing sensitive information in logs.

🪛 GitHub Check: Lint Code Base
components/trustpilot/app/trustpilot.app.ts

[failure] 550-550:
Empty block statement


[failure] 472-472:
Empty block statement

🪛 GitHub Actions: Pull Request Checks
components/trustpilot/app/trustpilot.app.ts

[error] 472-472: ESLint: Empty block statement (no-empty).

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
🔇 Additional comments (12)
components/trustpilot/app/trustpilot.app.ts (12)

1-85: Well-structured imports and type definitions.

The imports are comprehensive and the TypeScript interfaces provide excellent type safety. The interface definitions are logically organized and properly typed.


90-165: Excellent propDefinitions implementation.

The prop definitions are comprehensive and well-structured with proper validation, dynamic options, and appropriate defaults. The error handling in the businessUnitId options function is handled correctly.


167-223: Robust authentication and request handling.

The authentication validation addresses previous review comments effectively, and the retry logic with exponential backoff for rate limiting is well-implemented. The error handling and timeout configuration follow best practices.


225-253: Clean business unit methods implementation.

The methods follow consistent patterns for validation, URL building, and error handling. The single-responsibility principle is well-maintained.


255-318: Well-implemented public review methods.

The methods properly handle public endpoints with consistent validation, parameter formatting, and pagination support. The implementation follows established patterns effectively.


320-363: Excellent DRY principle implementation.

This helper method successfully addresses the previous review feedback about extracting common review fetching logic. It effectively reduces code duplication between service and product review methods while maintaining clean parameter handling.


365-414: Good use of extracted helper method.

The service review methods effectively utilize the extracted _getReviews helper method, reducing code duplication. The validation and sanitization logic is properly implemented.


432-471: Consistent implementation with service review methods.

The product review methods follow the same excellent patterns as the service review methods and properly utilize the extracted helper method.


488-549: Well-structured conversation methods.

The conversation methods are properly implemented with good validation, parameter handling, and pagination support.


566-613: Comprehensive webhook management implementation.

The webhook methods provide complete CRUD functionality with proper validation and clean parameter handling. The implementation is robust and follows established patterns.


615-641: Excellent security implementation for webhook validation.

The webhook signature validation properly implements HMAC-SHA256 with constant-time comparison to prevent timing attacks. This addresses the previous security concern and provides robust webhook authentication.


415-416: Fix empty block statement.

The console.warn statement is incomplete, creating an empty block that fails linting.

      if (message.length > 5000) {
+        // Message was truncated to meet Trustpilot's 5000 character limit
      }
⛔ Skipped due to learnings
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15436
File: components/printful/printful.app.mjs:55-63
Timestamp: 2025-01-29T22:59:38.825Z
Learning: Console.log statements should be removed before merging PRs to maintain code quality and prevent potential security risks from exposing sensitive information in logs.

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: 0

♻️ Duplicate comments (1)
components/trustpilot/app/trustpilot.app.ts (1)

95-109: Consider improving error handling in options function.

While the try-catch block prevents crashes, silently returning an empty array might hide legitimate API issues from users. Consider logging the error through a proper logging mechanism rather than console.error, or providing a more user-friendly fallback.

Based on past review comments, the console.error statement was already addressed, but the underlying concern about silent error handling remains relevant.

🧹 Nitpick comments (1)
components/trustpilot/app/trustpilot.app.ts (1)

516-528: Consider strengthening conversationId validation.

The current validation only checks for truthiness. Consider adding format validation similar to reviewId and businessUnitId if Trustpilot conversation IDs follow a specific format.

If conversation IDs follow the same MongoDB ObjectID format as other IDs, you could use a similar validation pattern:

-      if (!conversationId) {
+      if (!conversationId || typeof conversationId !== "string") {
        throw new Error("Invalid conversation ID");
      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e68182 and c1c55f7.

📒 Files selected for processing (1)
  • components/trustpilot/app/trustpilot.app.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/app/trustpilot.app.ts (4)

Learnt from: GTFalcao
PR: #16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #15436
File: components/printful/printful.app.mjs:55-63
Timestamp: 2025-01-29T22:59:38.825Z
Learning: Console.log statements should be removed before merging PRs to maintain code quality and prevent potential security risks from exposing sensitive information in logs.

🧬 Code Graph Analysis (1)
components/trustpilot/app/trustpilot.app.ts (2)
components/trustpilot/common/utils.mjs (11)
  • url (52-52)
  • formatQueryParams (177-190)
  • sleep (223-225)
  • validateBusinessUnitId (151-157)
  • buildUrl (51-65)
  • parseBusinessUnit (107-123)
  • parseReview (72-100)
  • validateReviewId (164-170)
  • sanitizeInput (26-43)
  • payload (131-133)
  • parseWebhookPayload (130-144)
components/trustpilot/common/constants.mjs (16)
  • RATING_SCALE (67-73)
  • RATING_SCALE (67-73)
  • SORT_OPTIONS (58-65)
  • SORT_OPTIONS (58-65)
  • MAX_LIMIT (76-76)
  • MAX_LIMIT (76-76)
  • DEFAULT_LIMIT (75-75)
  • DEFAULT_LIMIT (75-75)
  • BASE_URL (1-1)
  • BASE_URL (1-1)
  • RETRY_CONFIG (90-94)
  • RETRY_CONFIG (90-94)
  • HTTP_STATUS (78-88)
  • HTTP_STATUS (78-88)
  • ENDPOINTS (12-46)
  • ENDPOINTS (12-46)
🔇 Additional comments (9)
components/trustpilot/app/trustpilot.app.ts (9)

1-85: LGTM! Well-structured imports and comprehensive type definitions.

The imports are clean and well-organized, bringing in all necessary dependencies from Pipedream platform, Node.js crypto, and the common utilities. The TypeScript interfaces provide excellent type safety coverage for all major operations including requests, reviews, conversations, and webhooks.


167-223: Excellent authentication and request handling implementation.

The authentication validation ensures proper configuration, the retry logic correctly handles rate limiting with exponential backoff, and the request methods are well-structured with proper error handling and parameter formatting.


225-253: Well-implemented business unit methods.

Both methods include proper input validation, URL building, and response parsing. The searchBusinessUnits method provides sensible defaults for pagination parameters.


255-318: Solid public review methods with comprehensive parameter handling.

Both methods include proper validation, handle optional parameters well (like tags with conditional joining), and return consistent response structures with pagination metadata.


320-363: Excellent DRY implementation addressing previous review feedback.

This shared helper method successfully consolidates the common review fetching logic, eliminating code duplication between service and product review methods while maintaining consistent parameter handling and response structure.


365-427: Well-implemented service review methods with proper validation and sanitization.

The methods correctly use the shared helper, include comprehensive input validation, and properly sanitize reply messages with appropriate length limits and empty message detection.


429-481: Consistent product review methods following established patterns.

The methods properly use the shared helper and maintain consistency with service review methods in terms of validation, sanitization, and error handling patterns.


559-606: Well-implemented webhook management methods.

The methods provide comprehensive CRUD operations for webhooks with proper validation, consistent error handling, and good parameter management for both required and optional fields.


608-634: Excellent webhook utility methods with proper security implementation.

The webhook signature validation correctly implements HMAC-SHA256 with constant-time comparison to prevent timing attacks, addressing the security concerns from previous reviews. The payload parsing delegation maintains clean separation of concerns.

@seynadio seynadio requested a review from GTFalcao July 24, 2025 15:23
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: 3

🧹 Nitpick comments (1)
components/trustpilot/app/trustpilot.app.mjs (1)

167-187: Authentication implementation looks good

The dual authentication support (API key and OAuth) is well-implemented. Consider making the error message more generic to avoid revealing authentication details.

-        throw new Error("Authentication required: Configure either API key or OAuth token");
+        throw new Error("Authentication required");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1c55f7 and e530686.

📒 Files selected for processing (8)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/app/trustpilot.app.mjs (1 hunks)
  • components/trustpilot/sources/common/polling.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs
  • components/trustpilot/sources/common/polling.mjs
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/app/trustpilot.app.mjs (3)

Learnt from: GTFalcao
PR: #16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

🪛 Biome (2.1.2)
components/trustpilot/app/trustpilot.app.mjs

[error] 26-33: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 34-45: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 46-55: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 56-66: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 67-73: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 74-79: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 80-85: interface are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 191-191: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 195-195: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 212-212: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 226-226: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 264-264: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 272-272: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 302-302: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 331-331: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 336-336: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 350-350: non-null assertions are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 366-366: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 378-378: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 398-398: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 430-430: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 440-440: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 456-456: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 489-489: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 490-490: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 516-516: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 532-532: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 562-562: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 570-570: type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 587-587: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 609-609: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 613-613: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 613-613: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)


[error] 613-613: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

TypeScript only syntax

(parse)

🪛 GitHub Actions: Pull Request Checks
components/trustpilot/app/trustpilot.app.mjs

[error] 27-27: Parsing error: The keyword 'interface' is reserved

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (6)
components/trustpilot/app/trustpilot.app.mjs (6)

212-223: Excellent retry implementation with exponential backoff

The retry logic correctly handles rate limiting (429 status) with exponential backoff. The implementation prevents retry storms and respects the API's rate limits.

However, remove the TypeScript syntax:

-    async _makeRequestWithRetry(config: RequestConfig, retries = RETRY_CONFIG.MAX_RETRIES) {
+    /**
+     * @param {RequestConfig} config
+     * @param {number} [retries]
+     */
+    async _makeRequestWithRetry(config, retries = RETRY_CONFIG.MAX_RETRIES) {

226-238: Good validation practice for business unit ID

The method correctly validates the business unit ID before making the API call.

Remove TypeScript syntax:

-    async getBusinessUnit(businessUnitId: string) {
+    /**
+     * @param {string} businessUnitId
+     */
+    async getBusinessUnit(businessUnitId) {

256-298: Well-implemented public review fetching with proper pagination

The method correctly handles pagination, filtering, and parameter validation. The pagination calculation Math.floor(offset / limit) + 1 properly converts offset-based to page-based pagination.

Remove TypeScript parameter type:

-    }: PublicReviewsOptions) {
+    }) {

396-427: Excellent input validation and sanitization for review replies

The method implements comprehensive security measures:

  • Validates business unit and review IDs
  • Checks message type and existence
  • Sanitizes input with proper length constraints
  • Prevents empty messages after sanitization

Remove TypeScript syntax:

-    }: { businessUnitId: string; reviewId: string; message: string }) {
+    }) {

559-585: Well-structured webhook creation with proper validation

The method correctly validates required parameters and constructs the webhook data appropriately.

Remove TypeScript syntax:

-    }: WebhookOptions) {
+    }) {
-      const data: WebhookData = {
+      /** @type {WebhookData} */
+      const data = {

613-634: Excellent security implementation for webhook signature validation

The method implements security best practices:

  • Uses HMAC-SHA256 for signature validation
  • Implements constant-time comparison with crypto.timingSafeEqual to prevent timing attacks
  • Properly handles different payload types

Remove TypeScript syntax:

-    validateWebhookSignature(payload: unknown, signature: string, secret: string) {
+    /**
+     * @param {unknown} payload
+     * @param {string} signature
+     * @param {string} secret
+     */
+    validateWebhookSignature(payload, signature, secret) {

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: 0

♻️ Duplicate comments (1)
components/trustpilot/trustpilot.app.mjs (1)

535-562: Another instance of duplicated reply message validation

This is the third occurrence of identical reply message validation and sanitization logic. This strengthens the case for extracting it into a shared helper method.

🧹 Nitpick comments (4)
components/trustpilot/trustpilot.app.mjs (4)

78-91: Clarify the distinction between WebhookOptions and WebhookData types

Both WebhookOptions and WebhookData types are nearly identical, with the only difference being the optionality syntax for businessUnitId. This could lead to confusion. Consider either consolidating them into a single type or documenting the intended use case difference.


459-486: Consider extracting common reply logic to reduce duplication

The reply logic for product reviews is identical to service reviews (lines 401-432). Consider extracting this into a shared helper method to follow DRY principles.

+    async _validateAndSanitizeReplyMessage(message) {
+      if (!message || typeof message !== "string") {
+        throw new Error("Reply message is required");
+      }
+      
+      const sanitizedMessage = sanitizeInput(message, 5000);
+      if (sanitizedMessage.length === 0) {
+        throw new Error("Reply message cannot be empty after sanitization");
+      }
+      
+      return sanitizedMessage;
+    },

     async replyToProductReview({ reviewId, message }) {
       if (!validateReviewId(reviewId)) {
         throw new Error("Invalid review ID");
       }
-      if (!message || typeof message !== "string") {
-        throw new Error("Reply message is required");
-      }
-      
-      const sanitizedMessage = sanitizeInput(message, 5000);
-      if (sanitizedMessage.length === 0) {
-        throw new Error("Reply message cannot be empty after sanitization");
-      }
+      const sanitizedMessage = await this._validateAndSanitizeReplyMessage(message);
       
       const endpoint = buildUrl(ENDPOINTS.REPLY_TO_PRODUCT_REVIEW, {
         reviewId,
       });

521-533: Enhance conversation ID validation

The current validation only checks if conversationId is truthy. Consider implementing a more robust validation similar to validateReviewId for consistency.

     async getConversationById({ conversationId }) {
-      if (!conversationId) {
-        throw new Error("Invalid conversation ID");
+      if (!conversationId || typeof conversationId !== "string" || conversationId.trim().length === 0) {
+        throw new Error("Invalid conversation ID");
       }

635-638: Ensure consistent encoding for buffer comparison

When comparing signatures using timingSafeEqual, both buffers must have the same length and encoding. Consider explicitly specifying the encoding to ensure consistency.

       return crypto.timingSafeEqual(
-        Buffer.from(signature),
-        Buffer.from(expectedSignature),
+        Buffer.from(signature, 'hex'),
+        Buffer.from(expectedSignature, 'hex'),
       );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e530686 and bce521a.

📒 Files selected for processing (9)
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs (1 hunks)
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs (1 hunks)
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs (1 hunks)
  • components/trustpilot/package.json (2 hunks)
  • components/trustpilot/sources/common/polling.mjs (1 hunks)
  • components/trustpilot/trustpilot.app.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • components/trustpilot/package.json
  • components/trustpilot/actions/reply-to-service-review/reply-to-service-review.mjs
  • components/trustpilot/actions/fetch-service-reviews/fetch-service-reviews.mjs
  • components/trustpilot/actions/fetch-service-review-by-id/fetch-service-review-by-id.mjs
  • components/trustpilot/actions/reply-to-product-review/reply-to-product-review.mjs
  • components/trustpilot/actions/fetch-product-review-by-id/fetch-product-review-by-id.mjs
  • components/trustpilot/actions/fetch-product-reviews/fetch-product-reviews.mjs
  • components/trustpilot/sources/common/polling.mjs
🧰 Additional context used
🧠 Learnings (1)
components/trustpilot/trustpilot.app.mjs (3)

Learnt from: GTFalcao
PR: #16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-07-24T02:06:47.016Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

Learnt from: GTFalcao
PR: #12697
File: components/salesforce_rest_api/sources/common-webhook-methods.mjs:1-71
Timestamp: 2024-10-08T15:33:38.240Z
Learning: The common-webhook-methods.mjs object is designed to be extended, similar to an abstract class, and intentionally does not implement certain methods like generateWebhookMeta and getEventType to enforce implementation in subclasses.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (9)
components/trustpilot/trustpilot.app.mjs (9)

1-24: Well-structured imports with proper organization

The imports follow a logical order with external dependencies first, followed by local modules. All imported items are utilized throughout the code.


92-170: Excellent prop definitions with user-friendly async options

The prop definitions are comprehensive with proper validation, sensible defaults, and helpful descriptions. The async options for businessUnitId enhances user experience by dynamically fetching available business units.


172-192: Robust authentication implementation with proper validation

The authentication method correctly handles both API key and OAuth token authentication with appropriate error handling when neither is configured.


230-258: Well-implemented business unit methods with proper validation

Both methods follow consistent patterns with proper input validation and safe data handling. The use of optional chaining and fallback values demonstrates good defensive programming.


260-323: Comprehensive public review methods with robust error handling

The implementation correctly handles pagination, filtering, and validation. The use of retry logic for public endpoints enhances reliability.


325-432: Excellent implementation of service review methods with proper sanitization

The code demonstrates good practices including:

  • DRY principle with the _getReviews helper method
  • Comprehensive input validation
  • Security-conscious message sanitization with appropriate length limits
  • Clear error messages

564-611: Well-structured webhook management implementation

The webhook methods provide comprehensive CRUD operations with proper validation and error handling. The defensive programming with fallback values is commendable.


618-639: Excellent security implementation for webhook validation

The webhook signature validation correctly implements HMAC-SHA256 with timing-safe comparison to prevent timing attacks. This is a security best practice.


217-228: No change needed: retry delay correctly based on attempts made
The formula RETRY_CONFIG.INITIAL_DELAY * (RETRY_CONFIG.MAX_RETRIES - retries + 1) yields multipliers 1, 2, 3… for each retry, mapping directly to attempts made (not remaining). The implementation and capping at MAX_DELAY behave as intended.

Likely an incorrect or invalid review comment.

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.

Thanks for the adjustments @seynadio ! I'll mark this as ready for QA.

Regarding the one pending comment on the try/catch blocks within the components' run methods: I think it's best to let @pipedream/platform's axios handle them instead of throwing an error with the message. But the error responses from Trustpilot may warrant different treatment - if you believe that is the case, please let me know.

@GTFalcao GTFalcao moved this from Changes Required to Ready for QA in Component (Source and Action) Backlog Jul 25, 2025
@vunguyenhung vunguyenhung moved this from Ready for QA to In QA in Component (Source and Action) Backlog Jul 28, 2025
@vunguyenhung vunguyenhung moved this from In QA to Ready for QA in Component (Source and Action) Backlog Jul 28, 2025
@vunguyenhung vunguyenhung moved this from Ready for QA to In QA in Component (Source and Action) Backlog Jul 28, 2025
@vunguyenhung vunguyenhung moved this from In QA to Ready for Release in Component (Source and Action) Backlog Jul 28, 2025
@vunguyenhung
Copy link
Collaborator

@michelle0927 michelle0927 dismissed GTFalcao’s stale review July 28, 2025 15:48

Dismissing previous review

@michelle0927 michelle0927 merged commit 28e91bb into PipedreamHQ:master Jul 28, 2025
10 of 11 checks passed
@github-project-automation github-project-automation bot moved this from Ready for Release to Done in Component (Source and Action) Backlog Jul 28, 2025
@seynadio seynadio mentioned this pull request Jul 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
User submitted Submitted by a user
Development

Successfully merging this pull request may close these issues.

7 participants