Skip to content

Conversation

@SokolovskyiK
Copy link
Contributor

@SokolovskyiK SokolovskyiK commented Apr 27, 2025

Fixes #15127

Polling Sources

new-post
new-follower
new-comment

Actions

create-post
upload-media
delete-post

Summary by CodeRabbit

  • New Features
    • Introduced actions to create posts, upload media, and delete posts on WordPress.com sites.
    • Added event sources to emit events for new posts, new comments, and new followers.
    • Enhanced WordPress.com integration with new API methods for managing posts, media, comments, followers, and sites.
  • Documentation
    • Expanded documentation with detailed descriptions of available event sources and actions, including required and optional properties.
  • Chores
    • Updated dependencies and incremented the component version.

@adolfo-pd adolfo-pd added the User submitted Submitted by a user label Apr 27, 2025
@vercel
Copy link

vercel bot commented Apr 27, 2025

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

A member of the Team first needs to authorize it.

@vercel
Copy link

vercel bot commented Apr 27, 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) Apr 28, 2025 5:03pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 27, 2025

Walkthrough

This update introduces comprehensive WordPress.com integration, adding new polling sources for new posts, comments, and followers, along with actions to create posts, upload media, and delete posts. Core utility and validation modules are added to support robust input handling and error management. The WordPress.com app methods are expanded to include API interactions for posts, media, comments, and followers. Documentation is updated to reflect all new features, and the package version is incremented with a new dependency for form-data handling.

Changes

File(s) Change Summary
components/wordpress_com/README.md Expanded documentation with detailed sections on event sources and actions, outlining triggers, actions, required/optional properties, and component capabilities.
components/wordpress_com/common/methods.mjs Introduced a utility module for type checking, validation, and error handling, exporting multiple helper methods.
components/wordpress_com/common/utils.mjs Added utility functions for media upload preparation and object property filtering, including HTTP stream fetching for media.
components/wordpress_com/package.json Bumped version to 0.7.0 and added form-data as a dependency.
components/wordpress_com/wordpress_com.app.mjs Removed placeholder, added comprehensive API methods for posts, media, comments, and followers, and standardized request handling.
components/wordpress_com/actions/create-post/create-post.mjs
components/wordpress_com/actions/delete-post/delete-post.mjs
components/wordpress_com/actions/upload-media/upload-media.mjs
Added new actions: create post, delete post, and upload media, each with input validation, error handling, and API interaction logic.
components/wordpress_com/sources/new-comment/new-comment.mjs
components/wordpress_com/sources/new-follower/new-follower.mjs
components/wordpress_com/sources/new-post/new-post.mjs
Added new polling sources for new comments, followers, and posts, each with cursor management, event emission, and input validation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Action/Source
    participant WordPressApp
    participant WordPressAPI

    User->>Action/Source: Triggers action/source (e.g., Create Post, Poll New Post)
    Action/Source->>WordPressApp: Validate input, prepare request
    WordPressApp->>WordPressAPI: Make REST API call (create, fetch, upload, delete)
    WordPressAPI-->>WordPressApp: Return API response
    WordPressApp-->>Action/Source: Return result or data
    Action/Source-->>User: Emit event or return action result
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement sources: new-post, new-comment, new-follower with required/optional props and event emission (#15127)
Implement actions: create-post, upload-media, delete-post with required/optional props and API calls (#15127)
Input validation, error handling, and documentation for all sources/actions (#15127)

Suggested reviewers

  • jcortes

Poem

In the warren of code, a new patch appears,
With posts, comments, and followers—cheers!
Uploads and deletions, all handled with care,
Validation and actions, robust and aware.
The burrow now bustles with WordPress delight,
As rabbits and devs hop through features so bright.
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

components/wordpress_com/actions/upload-media/upload-media.mjs

Oops! Something went wrong! :(

ESLint: 8.57.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f62e918 and 7ed271c.

📒 Files selected for processing (1)
  • components/wordpress_com/actions/upload-media/upload-media.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/wordpress_com/actions/upload-media/upload-media.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
✨ Finishing Touches
  • 📝 Generate Docstrings

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

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

CodeRabbit Commands (Invoked using PR comments)

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

🧹 Nitpick comments (11)
components/wordpress_com/actions/delete-post.mjs (2)

7-7: Improve action description.

The current description "Delete post" is too brief and doesn't provide enough context.

-  description: "Delete post",
+  description: "Deletes an existing post or page from your WordPress.com site.",

33-35: Remove unnecessary blank line.

The blank line at line 33 is not needed and should be removed for consistent code style.

     } =  this;
-

     warnings.push(...wordpress.checkDomainOrId(site)); 
components/wordpress_com/actions/create-post.mjs (2)

60-60: Remove testing comment.

The comment "// TEST" should be removed as it appears to be leftover debugging code.

-    warnings.push(...wordpress.checkDomainOrId(site)); // TEST
+    warnings.push(...wordpress.checkDomainOrId(site));

65-65: Remove testing comment.

Another "// TEST" comment should be removed.

-        response = await wordpress.createWordpressPost({ //TEST
+        response = await wordpress.createWordpressPost({
components/wordpress_com/actions/upload-media.mjs (2)

59-72: isFormData branch always logs a warning

Both branches push a warning ("Media was received as multipart/form-data" vs "Media was received as URL").
Warnings are concatenated into the $summary; if the user supplied correct input they still get a warning, which is misleading.

Consider pushing these messages only when the condition may indicate unexpected input, or label them as info logs instead of warnings.


85-88: Avoid undefined summary pieces when no warnings or title

media.title and warnings can be undefined / empty.
Guard them to keep the exported summary tidy.

-$.export("$summary", `Media "${media.title}" uploaded successfully (ID: ${media.ID})` + "\n- " + warnings.join("\n- "));
+const summaryLines = [
+  `Media "${media?.title ?? "untitled"}" uploaded successfully (ID: ${media?.ID})`,
+  ...(warnings.length ? ["Warnings:\n- " + warnings.join("\n- ")] : []),
+];
+$.export("$summary", summaryLines.join("\n"));
components/wordpress_com/wordpress_com.app.mjs (1)

60-63: Comment states POST is used instead of DELETE in a GET request

The comment appears copy-pasted and confuses readers:

method: "GET", // use POST instead of DELETE. Wordpress does not allow DELETE methods on free accounts.

Update or remove the misleading comment.

components/wordpress_com/sources/new-comment.mjs (1)

85-92: Be cautious with array mutation in the filtering logic.

The code is using .reverse() which mutates the original comments array. This could have unexpected side effects if the array is used elsewhere after this operation.

Consider creating a separate array:

-for (const comment of comments.reverse()) {
+const reversedComments = [...comments].reverse();
+for (const comment of reversedComments) {
components/wordpress_com/common/methods.mjs (3)

89-90: Fix typo in variable name.

The variable is misspelled as "warings" instead of "warnings".

-    const warings = [];
+    const warnings = [];

297-300: Remove incomplete comment.

There's an incomplete comment at the end of the file.

-/* ===================================================================================================
-   If 
-====================================================================================================== */
-

152-153: Fix typo in comment.

The comment contains a typo: "Warnin" instead of "Warning".

-    // Warnin accumulator
+    // Warning accumulator
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 50d817c and b780b29.

📒 Files selected for processing (11)
  • components/wordpress_com/README.md (1 hunks)
  • components/wordpress_com/actions/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media.mjs (1 hunks)
  • components/wordpress_com/common/methods.mjs (1 hunks)
  • components/wordpress_com/common/utils.mjs (1 hunks)
  • components/wordpress_com/package.json (1 hunks)
  • components/wordpress_com/sources/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post.mjs (1 hunks)
  • components/wordpress_com/wordpress_com.app.mjs (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Components Checks
components/wordpress_com/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Specifically, lockfile specifiers ({"@pipedream/platform":"^3.0.0"}) do not match package.json specs ({"@pipedream/platform":"^3.0.0","form-data":"^4.0.2"}).

🪛 GitHub Actions: Pull Request Checks
components/wordpress_com/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Specifically, lockfile specifiers do not match package.json specs.

🪛 Biome (1.9.4)
components/wordpress_com/common/methods.mjs

[error] 175-175: A character class cannot match a joined character sequence.

A zero width joiner composes several emojis into a new one. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: pnpm publish
🔇 Additional comments (7)
components/wordpress_com/README.md (1)

12-41: Well-structured documentation for the new WordPress.com features.

The documentation clearly outlines the new event sources and actions, making it easy for users to understand what functionality is available and how to use it. Good job providing the required and optional properties for each component.

components/wordpress_com/actions/upload-media.mjs (1)

80-82:

❌ Incorrect review comment

Missing safety-check for form.getHeaders()

form.getHeaders() exists only for form-data instances.
When the user passes a plain object that merely quacks like FormData, this will throw.

Add a defensive check:

- contentType : form.getHeaders()["content-type"],
+ const headers = form.getHeaders?.() || {};
+ contentType : headers["content-type"] || "multipart/form-data",

🏁 Script executed:

#!/bin/bash
# Search for usage of form.getHeaders
rg -n "form.getHeaders" -A2 -B2 components/wordpress_com/actions/upload-media.mjs

# Show function signature and where 'form' comes from
rg -n "uploadMedia" -A10 -B3 components/wordpress_com/actions/upload-media.mjs

# Inspect FormData import
rg -n "FormData" -n components/wordpress_com/actions/upload-media.mjs

Length of output: 567


🏁 Script executed:

#!/bin/bash
# Display the first 200 lines to inspect how `form` is assigned and used
sed -n '1,200p' components/wordpress_com/actions/upload-media.mjs

Length of output: 2228


🏁 Script executed:

#!/bin/bash
# Find and display definition of isFormData in wordpress_com.app.mjs
rg -n "isFormData" -A5 -B5 components/wordpress_com/wordpress_com.app.mjs

# Output common/utils.mjs to inspect prepareMediaUpload
sed -n '1,200p' components/common/utils.mjs

Length of output: 188


🏁 Script executed:

#!/bin/bash
# Inspect prepareMediaUpload implementation
sed -n '1,200p' components/wordpress_com/common/utils.mjs

# Inspect wordpress_com.app.mjs to find isFormData definition
sed -n '1,200p' components/wordpress_com/wordpress_com.app.mjs

Length of output: 5818


🏁 Script executed:

#!/bin/bash
# Locate isFormData definition in wordpress_com common methods
rg -n "isFormData" -A5 -B5 components/wordpress_com/common/methods.mjs

# Show the first 200 lines of methods.mjs for additional context
sed -n '1,200p' components/wordpress_com/common/methods.mjs

Length of output: 6355


Redundant safety check for form.getHeaders()
The form variable is guaranteed to have a .getHeaders() method because it’s either:

  • A user-provided object that passed isFormData() (which requires typeof input.getHeaders === "function"), or
  • A FormData instance created by prepareMediaUpload (the form-data package’s FormData also implements getHeaders).

Adding an extra getHeaders?.() guard is unnecessary here.

Likely an incorrect or invalid review comment.

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

12-18: ⚠️ Potential issue

Default parameter uses this before binding

this is not yet bound while evaluating default parameter values, so
$ = this will resolve to undefined in strict mode. Axios will then throw.

Refactor to supply $ explicitly:

-_makeRequest({
-  $ = this,
-  url,
-  contentType,
-  ...opts
-}) {
+_makeRequest({ $, url, contentType, ...opts }) {
+  // require callers to pass `$`

All internal callers already pass $, so this is a safe change.

Likely an incorrect or invalid review comment.

components/wordpress_com/sources/new-post.mjs (1)

1-121: Well-structured polling source component for WordPress.com new posts.

The implementation effectively tracks and emits events for new WordPress.com posts, handling various post types and maintaining state correctly. The cursor-based approach ensures no duplicate emissions while properly tracking the highest seen post ID.

components/wordpress_com/sources/new-comment.mjs (1)

1-116: Overall well-implemented polling source component for WordPress.com comments.

The implementation correctly handles fetching, filtering, and emitting new comment events with proper cursor management.

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

1-87: Well-implemented media utilities for WordPress.com integration.

The utilities for sanitizing props and preparing media uploads are well-structured and documented. The prepareMediaUpload function correctly handles the FormData preparation and the fetchStreamWithHeaders function implements appropriate error handling.

components/wordpress_com/common/methods.mjs (1)

175-175:

❌ Incorrect review comment

Fix regex character class issue.

The character class contains zero-width joiners which can't be matched this way according to static analysis.

-    const dubiousCharRegex = /[\\<>{}|"`^]|[\u200B\u200C\u200D\u2060\uFEFF\u00A0]/g;
+    const dubiousCharRegex = /[\\<>{}|"`^]|\u200B|\u200C|\u200D|\u2060|\uFEFF|\u00A0/g;

🏁 Script executed:

#!/bin/bash
# Check if the suggested regex works by testing it against a sample string containing invisible characters

echo -e "Testing improved regex pattern...\n"

# Create a test JavaScript file
cat > test_regex.js << 'EOF'
// Test the original pattern (problematic)
const original = /[\\<>{}|"`^]|[\u200B\u200C\u200D\u2060\uFEFF\u00A0]/g;

// Test the fixed pattern
const fixed = /[\\<>{}|"`^]|\u200B|\u200C|\u200D|\u2060|\uFEFF|\u00A0/g;

// Test string with invisible characters and visible ones
const testString = "Test\u200Bstring\u200Cwith\u200Dinvisible<characters>";

console.log("Original regex matches:", testString.match(original));
console.log("Fixed regex matches:", testString.match(fixed));
EOF

# Run the test using Node.js
node test_regex.js

Length of output: 210


No change needed: original regex correctly matches zero-width characters

I tested the existing pattern and confirmed it already captures both the visible punctuation and the zero-width code points as intended:

const original = /[\\<>{}|"`^]|[\u200B\u200C\u200D\u2060\uFEFF\u00A0]/g;
const testString = "Test\u200Bstring\u200Cwith\u200Dinvisible<characters>";
console.log(testString.match(original));
// → [ '​', '‌', '‍', '<', '>' ]

The proposed alternative produces identical matches, so there’s no need to rewrite the regex. Marking this suggestion as unnecessary.

Likely an incorrect or invalid review comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 175-175: A character class cannot match a joined character sequence.

A zero width joiner composes several emojis into a new one. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

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

🧹 Nitpick comments (21)
components/wordpress_com/common/methods.mjs (3)

12-18: Fix method name typo

The method name isEmptySting contains a typo and should be corrected to isEmptyString.

-isEmptySting(input){
+isEmptyString(input){
   if(this.isString(input)){
     if(input.trim() === "") return true;
   };

   return false;
 },

175-175: Fix misleading character class in regex

The regex contains a character class with zero-width joiners, which Biome flags as potentially problematic. Consider using alternation instead.

-  const dubiousCharRegex = /[\\<>{}|"`^]|[\u200B\u200C\u200D\u2060\uFEFF\u00A0]/g;
+  const dubiousCharRegex = /[\\<>{}|"`^]|\u200B|\u200C|\u200D|\u2060|\uFEFF|\u00A0/g;
🧰 Tools
🪛 Biome (1.9.4)

[error] 175-175: A character class cannot match a joined character sequence.

A zero width joiner composes several emojis into a new one. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)


296-300: Remove incomplete comment block

There's an incomplete comment block at the end of the file that should be removed.

-/* ===================================================================================================
-   If 
-====================================================================================================== */
-
components/wordpress_com/README.md (1)

28-29: Format "Available Actions" heading properly

The "Available Actions" section heading is missing proper markdown formatting (# or ## prefix).

Each source manages its own database cursor to ensure only new data is processed each time it runs — no duplicates, no missed updates.
-Available Actions
+# Available Actions

Perform direct operations on your Wordpress.com site:
components/wordpress_com/actions/delete-post.mjs (1)

8-8: Improve version number and description

According to Pipedream component guidelines, when introducing a new component as part of a published package, the version should align with the package version. Also, the description could be more informative.

-  version: "0.0.1",
+  version: "0.7.0",
-  description: "Delete post",
+  description: "Delete an existing post from a WordPress.com site",
components/wordpress_com/actions/create-post.mjs (2)

60-60: Remove debug comment.

The "// TEST" comment should be removed in production code.

-    warnings.push(...wordpress.checkDomainOrId(site)); // TEST
+    warnings.push(...wordpress.checkDomainOrId(site));

64-72: Remove debug comment and fix indentation.

The "// TEST" comment should be removed and the indentation is inconsistent with extra spaces.

      try {
-        response = await wordpress.createWordpressPost({ //TEST
-          
+        response = await wordpress.createWordpressPost({
          $,
          site,
          data : {
            ...fields
          }
        });
components/wordpress_com/sources/new-follower.mjs (3)

47-61: Improve code formatting and cursor initialization.

The indentation is inconsistent in the first run block. Additionally, the initialization logic could be improved for clarity.

    // First run: Initialize cursor
    if (!lastFollowerId) {
-    if (!followers.length) {
+      if (!followers.length) {
        console.log("No followers found on first run. Source initialized with no cursor.");
        return;
-    }
+      }
-
-    const newest = followers[0]?.ID;
-    if (!newest) {
+      const newest = followers[0]?.ID;
+      if (!newest) {
        throw new Error("Failed to initialize: The latest follower does not have a valid ID.");
-    }
+      }
-
-    await db.set("lastFollowerId", newest);
-    console.log(`Initialized lastFollowerId on first run with follower ID ${newest}.`);
-    return;
+      await db.set("lastFollowerId", newest);
+      console.log(`Initialized lastFollowerId on first run with follower ID ${newest}.`);
+      return;
    }

75-81: Fix indentation in the emit loop.

The indentation is inconsistent in the loop that emits events.

    for (const follower of newFollowers) {
-    this.$emit(follower, {
-        id: follower.ID,
-        summary: follower.label || follower.login || "Anonymous Follower",
-        ts: follower.date_subscribed && +new Date(follower.date_subscribed),
-    });
+      this.$emit(follower, {
+        id: follower.ID,
+        summary: follower.label || follower.login || "Anonymous Follower",
+        ts: follower.date_subscribed && +new Date(follower.date_subscribed),
+      });
    }

84-89: Fix indentation in the cursor update block.

The indentation is inconsistent in the cursor update block.

    // Update last seen follower ID
    if (newFollowers.length > 0) {
-    await db.set("lastFollowerId", maxFollowerIdTracker);
-    console.log(`Checked for new followers. Emitted ${newFollowers.length} follower(s).`);
+      await db.set("lastFollowerId", maxFollowerIdTracker);
+      console.log(`Checked for new followers. Emitted ${newFollowers.length} follower(s).`);
    } else {
-    console.log("No new followers found.");
+      console.log("No new followers found.");
    }
components/wordpress_com/actions/upload-media.mjs (2)

89-89: Remove debugging console.log statement.

There's a console.log statement that should be removed before production deployment.

-      console.log(response);

58-72: Improve conditionals and comments for handling different media input types.

The code handling media input types could be improved for clarity, and the comments don't add much value.

-    // If not form data
    if (wordpress.isFormData(media)){ 
-
-      console.log("Media was received as multipart/form-data");
+      // Media is already in FormData format
       warnings.push("Media was received as multipart/form-data");
-
       form = media;
-
     } else {
-
+      // Media is a URL that needs to be fetched
       warnings.push("Media was received as URL");
       warnings.push(...wordpress.checkIfUrlValid(media)); 
-
       form = await prepareMediaUpload(media, fields, $);
     }
components/wordpress_com/common/utils.mjs (3)

28-31: Complete JSDoc comments for prepareMediaUpload function.

The JSDoc comments are incomplete. They should include proper @param and @return tags.

 /**
  * Prepares a multipart/form-data payload for uploading media to WordPress.com.
- * Fetches the media file from a given URL, wraps it in a FormData object*/
+ * Fetches the media file from a given URL, wraps it in a FormData object
+ * 
+ * @param {string} mediaUrl - URL of the media to upload
+ * @param {Object} fields - Optional metadata fields for the upload
+ * @param {string} [fields.title] - Title of the media
+ * @param {string} [fields.caption] - Caption for the media
+ * @param {string} [fields.description] - Description of the media
+ * @returns {Promise<FormData>} FormData object ready for upload
+ */

60-63: Complete JSDoc comments for fetchStreamWithHeaders function.

The JSDoc comments are incomplete. They should include proper @param and @return tags.

 /**
  * Fetches a remote media file as a readable stream, including it's content type.
- * Sends a basic GET request while mimicking a browser to avoid blocks from some servers.*/
+ * Sends a basic GET request while mimicking a browser to avoid blocks from some servers.
+ * 
+ * @param {string} url - URL of the media to fetch
+ * @returns {Promise<{stream: ReadableStream, contentType: string}>} Object containing stream and content type
+ */

7-25: Simplify removeCustomPropFields function.

The current implementation is unnecessarily complex for a simple filtering operation. It can be simplified while maintaining the same functionality.

 export function removeCustomPropFields(input) {
     const blacklist = new Set(["extendedType", "postBody"]);
-    const clean = {};
-  
-    for (const key of Object.keys(input)) {
-      const prop = input[key];
-      const cloned = {};
-  
-      for (const field of Object.keys(prop)) {
-        if (!blacklist.has(field)) {
-          cloned[field] = prop[field];
-        }
-      }
-  
-      clean[key] = cloned;
-    }
-  
-    return clean;
+    
+    return Object.entries(input).reduce((clean, [key, prop]) => {
+      clean[key] = Object.entries(prop).reduce((cloned, [field, value]) => {
+        if (!blacklist.has(field)) {
+          cloned[field] = value;
+        }
+        return cloned;
+      }, {});
+      return clean;
+    }, {});
   };
components/wordpress_com/sources/new-post.mjs (3)

90-97: Consider additional sort check for post IDs

The code assumes posts from the API are returned in descending order by ID. If the API changes or returns posts in a different order, this logic might miss new posts.

Consider adding a sort before looping through posts to ensure they're processed in the correct order:

+ // Sort posts by ID to ensure we process them in order
+ posts.sort((a, b) => b.ID - a.ID);

  for (const post of posts) { 
    if (post.ID > lastPostId) {
      newPosts.push(post);
      if (post.ID > maxPostIdTracker) {
        maxPostIdTracker = post.ID;
      }
    }
  }

99-107: Add clarification comment for post reversal

The code reverses the posts array before emitting events, but it's not immediately clear why. Adding a comment would improve code clarity.

Add a comment explaining why posts are reversed:

+ // Reverse posts to emit them in ascending chronological order (oldest first)
  for (const post of newPosts.reverse()) {
    
    this.$emit(post, {
      id: post.ID,
      summary: post.title,
      ts: post.date && +new Date(post.date),
    });
    
  }

104-104: Improve timestamp readability

The current timestamp conversion using +new Date() works but is less readable than alternatives.

Consider using a more explicit method for timestamp conversion:

-      ts: post.date && +new Date(post.date),
+      ts: post.date && new Date(post.date).getTime(),
components/wordpress_com/wordpress_com.app.mjs (1)

76-76: Remove misleading comment about HTTP method

The comment suggests this is using POST instead of DELETE, but the actual method used is GET. This comment appears to be mistakenly copied from the delete method.

Remove the misleading comment:

-        method: "GET", // use POST instead of DELETE. Wordpress does not allow DELETE methods on free accounts. 
+        method: "GET",
components/wordpress_com/sources/new-comment.mjs (2)

98-98: Improve timestamp readability

Similar to new-post.mjs, the timestamp conversion could be more readable.

Use a more explicit method for timestamp conversion:

-        ts: comment.date && +new Date(comment.date),
+        ts: comment.date && new Date(comment.date).getTime(),

97-97: More descriptive summary field

The current summary only shows the author name or "Anonymous Comment," which doesn't provide much context about the comment content.

Consider including truncated comment content in the summary for better identification:

-        summary: comment.author?.name || "Anonymous Comment",
+        summary: `${comment.author?.name || "Anonymous"}: ${comment.content.slice(0, 50)}${comment.content.length > 50 ? '...' : ''}`,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 50d817c and b780b29.

📒 Files selected for processing (11)
  • components/wordpress_com/README.md (1 hunks)
  • components/wordpress_com/actions/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media.mjs (1 hunks)
  • components/wordpress_com/common/methods.mjs (1 hunks)
  • components/wordpress_com/common/utils.mjs (1 hunks)
  • components/wordpress_com/package.json (1 hunks)
  • components/wordpress_com/sources/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post.mjs (1 hunks)
  • components/wordpress_com/wordpress_com.app.mjs (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
components/wordpress_com/common/methods.mjs

[error] 175-175: A character class cannot match a joined character sequence.

A zero width joiner composes several emojis into a new one. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

🪛 GitHub Actions: Pull Request Checks
components/wordpress_com/package.json

[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Run 'pnpm install --no-frozen-lockfile' or update the lockfile.

🪛 GitHub Actions: Components Checks
components/wordpress_com/package.json

[error] 16-17: You need to increment the version of this component. See https://pipedream.com/docs/components/guidelines/#versioning for more information.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: pnpm publish
🔇 Additional comments (1)
components/wordpress_com/README.md (1)

12-41: Documentation looks comprehensive and well-structured

The documentation for new event sources and actions is clear, concise, and provides good information about each feature's capabilities and requirements.

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

♻️ Duplicate comments (10)
components/wordpress_com/actions/delete-post.mjs (2)

44-44: 🛠️ Refactor suggestion

Improve summary message handling.

The current implementation doesn't handle the case when there are no warnings and may produce an incorrect message if the response doesn't contain an ID.

-    $.export("$summary", `Post ID = ${response?.ID} successfully deleted.` + "\n- "  + warnings.join("\n- "));
+    $.export("$summary", `Post ID = ${postId} successfully deleted.` + (warnings.length ? "\n- " + warnings.join("\n- ") : ""));

33-34: 🛠️ Refactor suggestion

Add validation for postId.

The code validates the site parameter but doesn't verify that postId is a valid integer before proceeding.

  warnings.push(...wordpress.checkDomainOrId(site)); 
+  
+  // Validate postId
+  if (!wordpress.isIdNumber(postId)) {
+    warnings.push(`Invalid Post ID: ${postId}. Post ID must be a positive integer.`);
+  }
+  
+  // If there are validation errors, exit early
+  if (warnings.length > 0) {
+    $.export("$summary", `Cannot delete post due to validation errors:` + "\n- " + warnings.join("\n- "));
+    return;
+  }
components/wordpress_com/actions/create-post.mjs (1)

78-78: 🛠️ Refactor suggestion

Improve summary message handling.

The current implementation may produce an incorrect message if there are no warnings and doesn't handle the case when response is undefined.

-      $.export("$summary", `Post successfully created. ID = ${response?.ID}` + "\n- "  + warnings.join("\n- "));
+      $.export("$summary", `Post successfully created. ID = ${response?.ID}` + (warnings.length ? "\n- " + warnings.join("\n- ") : ""));
components/wordpress_com/sources/new-follower.mjs (1)

38-42: 🛠️ Refactor suggestion

Handle response undefined case.

If an error occurs during the API call, the code will throw an error with throwCustomError. However, if for some reason execution continues, response might be undefined when accessed on line 42.

  } catch (error) {
    wordpress.throwCustomError("Failed to fetch followers from WordPress:", error, warnings);
  }

-  const followers = response.subscribers || [];
+  const followers = response?.subscribers || [];
components/wordpress_com/actions/upload-media.mjs (2)

92-96: ⚠️ Potential issue

Add return statement after error handling.

After throwing an error with throwCustomError, the function should return to prevent further execution with undefined variables.

  } catch (error) {
    
    wordpress.throwCustomError("Failed to upload media", error, warnings); 
+   return;
  };

84-87: ⚠️ Potential issue

Add null check before accessing media properties.

The code doesn't check if the media array exists or contains any items before accessing its properties, which could cause a runtime error.

-      const media = response.media[0];
+      const media = response?.media?.[0];
+      
+      if (!media) {
+        $.export("$summary", "Media uploaded but no media data was returned" + "\n- " + warnings.join("\n- "));
+        return response;
+      }

      $.export("$summary", `Media "${media.title}" uploaded successfully (ID: ${media.ID})` + "\n- " + warnings.join("\n- "));
components/wordpress_com/sources/new-post.mjs (1)

61-64: ⚠️ Potential issue

Add return statement after error handling to prevent undefined references.

The code continues execution after throwing an error, which could lead to accessing properties on an undefined response variable. Add a return statement to exit the function after error handling.

  } catch (error) {
    wordpress.throwCustomError("Failed to fetch posts from WordPress:", error, warnings); 
+   return;
  }
components/wordpress_com/wordpress_com.app.mjs (1)

12-27: 🛠️ Refactor suggestion

Enhance error handling in _makeRequest method.

The current implementation doesn't handle HTTP error status codes, which can lead to unclear error messages for users when API requests fail.

  _makeRequest({
    $ = this,
    url,
    contentType,
    ...opts
  }) {

    return axios($, {
        url,
        headers : {
          "Authorization":  `Bearer ${this.$auth.oauth_access_token}`,
          "Content-Type": (contentType) ? contentType : "application/json",
        },
        ...opts,
+       validateStatus: () => true, // Don't throw on non-2xx responses
      })
+     .then((response) => {
+       // Handle API errors with appropriate messages
+       if (response.status >= 400) {
+         const errorMsg = response.data?.message || `Request failed with status ${response.status}`;
+         if (response.status === 429) {
+           throw new Error(`WordPress API rate limit exceeded: ${errorMsg}`);
+         } else if (response.status === 401 || response.status === 403) {
+           throw new Error(`Authentication error: ${errorMsg}. Please check your WordPress.com API credentials.`);
+         } else {
+           throw new Error(`WordPress API error: ${errorMsg}`);
+         }
+       }
+       return response;
+     });
  },
components/wordpress_com/sources/new-comment.mjs (2)

85-94: Align comment ordering logic with new-post.mjs for consistency.

The ordering logic here differs from new-post.mjs - here comments are filtered and then the result array is reversed, while in new-post.mjs posts are collected and the collection is reversed.

  for (const comment of comments) {
    if (Number(comment.ID) > lastCommentId) {
      newComments.push(comment);
      if (Number(comment.ID) > maxCommentIdTracker) {
        maxCommentIdTracker = comment.ID;
      }
    }
  }

-  for (const comment of newComments.reverse()) {
+  // Reverse to emit in chronological order (oldest first)
+  for (const comment of [...newComments].reverse()) {
    this.$emit(comment, {
      id: comment.ID,

62-64: 🛠️ Refactor suggestion

Add response existence check.

There's no verification that the response exists before trying to access its properties, which could lead to runtime errors if the API call failed.

+  if (!response) {
+    console.log("No valid response from WordPress API. Exiting.");
+    return;
+  }
  const comments = response.comments || [];
  const lastCommentId = Number(await db.get("lastCommentId"));
🧹 Nitpick comments (12)
components/wordpress_com/common/methods.mjs (3)

12-13: Fix the typo in the method name.

The method name should be isEmptyString instead of isEmptySting.

-isEmptySting(input){
+isEmptyString(input){

89-89: Fix typo in comment.

There's a typo in the comment.

-  // Warnin accumulator
+  // Warning accumulator

219-223: Remove incomplete comment.

The comment at the end of the file appears to be incomplete and should be removed.

-
-/* ===================================================================================================
-   If 
-====================================================================================================== */
-
components/wordpress_com/actions/create-post.mjs (2)

60-60: Remove debug comment.

Remove the debugging comment "// TEST" as it's not needed in production code.

-    warnings.push(...wordpress.checkDomainOrId(site)); // TEST
+    warnings.push(...wordpress.checkDomainOrId(site));

64-68: Fix indentation and remove debug comment.

Fix the inconsistent indentation (6 spaces instead of 4) and remove the debugging comment.

-      try {
-        response = await wordpress.createWordpressPost({ //TEST
-          
-          $,
-          site,
+    try {
+      response = await wordpress.createWordpressPost({
+        $,
+        site,
🧰 Tools
🪛 GitHub Check: Lint Code Base

[failure] 64-64:
Expected indentation of 4 spaces but found 6

components/wordpress_com/sources/new-follower.mjs (1)

66-73: Fix inconsistent indentation.

The indentation in the for loop is inconsistent with the rest of the file.

  for (const follower of followers) {
-    if (Number(follower.ID) > lastFollowerId) {
-        newFollowers.push(follower);
-        if (Number(follower.ID) > maxFollowerIdTracker) {
-        maxFollowerIdTracker = follower.ID;
-        }
-    }
+    if (Number(follower.ID) > lastFollowerId) {
+      newFollowers.push(follower);
+      if (Number(follower.ID) > maxFollowerIdTracker) {
+        maxFollowerIdTracker = follower.ID;
+      }
+    }
  }
components/wordpress_com/actions/upload-media.mjs (2)

30-34: Add a description for the caption prop.

The component prop caption must have a description to maintain consistency with documentation guidelines and help users understand its purpose.

  caption: {
    type: "string",
    label: "Caption",
+   description: "Caption text for the uploaded media.",
    optional: true,
  },
🧰 Tools
🪛 GitHub Check: Lint Code Base

[warning] 30-30:
Component prop caption must have a description. See https://pipedream.com/docs/components/guidelines/#props


35-39: Add a description for the description prop.

The component prop description must have a description to maintain consistency with documentation guidelines and help users understand its purpose.

  description: {
    type: "string",
    label: "Description",
+   description: "Detailed description of the uploaded media.",
    optional: true,
  },
🧰 Tools
🪛 GitHub Check: Lint Code Base

[warning] 35-35:
Component prop description must have a description. See https://pipedream.com/docs/components/guidelines/#props

components/wordpress_com/sources/new-post.mjs (2)

6-6: Update source description to follow guidelines.

Source descriptions should start with "Emit new" according to Pipedream's component guidelines.

-  description: "Emit a separate event for each new post published since the last run. If no new posts, emit nothing.",
+  description: "Emit new post events for each post published since the last run. If no new posts, emit nothing.",
🧰 Tools
🪛 GitHub Check: Lint Code Base

[warning] 6-6:
Source descriptions should start with "Emit new". See https://pipedream.com/docs/components/guidelines/#source-description


17-26: Add description for the type prop.

Component props must have descriptions according to Pipedream's component guidelines.

  type: {
    type: "string",
    label: "Post Type",
+   description: "The type of WordPress content to monitor for new items.",
    options: [
      { label: "Post", value: "post" },
      { label: "Page", value: "page" },
      { label: "Attachment", value: "attachment" },
    ],
    default: "post",
  },
🧰 Tools
🪛 GitHub Check: Lint Code Base

[warning] 17-17:
Component prop type must have a description. See https://pipedream.com/docs/components/guidelines/#props

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

75-77: Fix incorrect comment in getWordpressPosts method.

The comment incorrectly states "use POST instead of DELETE" but this method uses GET.

  return this._makeRequest({
-    method: "GET", // use POST instead of DELETE. Wordpress does not allow DELETE methods on free accounts. 
+    method: "GET",
    url, 
components/wordpress_com/sources/new-comment.mjs (1)

6-6: Update source description to follow guidelines.

Source descriptions should start with "Emit new" according to Pipedream's component guidelines.

-  description: "Emit a separate event for each new comment added since the last run. If no new comments, emit nothing.",
+  description: "Emit new comment events for each comment added since the last run. If no new comments, emit nothing.",
🧰 Tools
🪛 GitHub Check: Lint Code Base

[warning] 6-6:
Source descriptions should start with "Emit new". See https://pipedream.com/docs/components/guidelines/#source-description

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b780b29 and 8fbc421.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • components/wordpress_com/actions/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media.mjs (1 hunks)
  • components/wordpress_com/common/methods.mjs (1 hunks)
  • components/wordpress_com/package.json (2 hunks)
  • components/wordpress_com/sources/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post.mjs (1 hunks)
  • components/wordpress_com/wordpress_com.app.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/wordpress_com/package.json
🧰 Additional context used
🪛 GitHub Check: Lint Code Base
components/wordpress_com/actions/create-post.mjs

[failure] 14-14:
Missing trailing comma


[failure] 43-43:
Expected a line break after this opening brace


[failure] 43-43:
Object properties must go on a new line


[failure] 43-43:
Expected a line break before this closing brace


[failure] 44-44:
Expected a line break after this opening brace


[failure] 44-44:
Object properties must go on a new line


[failure] 44-44:
Expected a line break before this closing brace


[failure] 47-47:
Missing trailing comma


[failure] 49-49:
Trailing spaces not allowed


[failure] 64-64:
Expected indentation of 4 spaces but found 6

components/wordpress_com/actions/delete-post.mjs

[warning] 12-12:
Component prop site must have a label. See https://pipedream.com/docs/components/guidelines/#props

components/wordpress_com/actions/upload-media.mjs

[warning] 30-30:
Component prop caption must have a description. See https://pipedream.com/docs/components/guidelines/#props


[warning] 35-35:
Component prop description must have a description. See https://pipedream.com/docs/components/guidelines/#props

components/wordpress_com/sources/new-comment.mjs

[warning] 6-6:
Source descriptions should start with "Emit new". See https://pipedream.com/docs/components/guidelines/#source-description

components/wordpress_com/sources/new-follower.mjs

[warning] 7-7:
Source descriptions should start with "Emit new". See https://pipedream.com/docs/components/guidelines/#source-description

components/wordpress_com/sources/new-post.mjs

[warning] 6-6:
Source descriptions should start with "Emit new". See https://pipedream.com/docs/components/guidelines/#source-description


[warning] 17-17:
Component prop type must have a description. See https://pipedream.com/docs/components/guidelines/#props

🪛 GitHub Actions: Pull Request Checks
components/wordpress_com/actions/create-post.mjs

[error] 14-14: ESLint: Missing trailing comma (comma-dangle).

🪛 Biome (1.9.4)
components/wordpress_com/common/methods.mjs

[error] 111-111: A character class cannot match a joined character sequence.

A zero width joiner composes several emojis into a new one. Replace the character class with an alternation.

(lint/suspicious/noMisleadingCharacterClass)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components

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 (3)
components/wordpress_com/actions/upload-media.mjs (2)

87-89: ⚠️ Potential issue

Add null check before accessing media properties

The code doesn't check if media is defined before accessing its properties, which could cause runtime errors if the API returns unexpected data.

-      const media = response.media[0];
+      const media = response?.media?.[0];
+      
+      if (!media) {
+        $.export("$summary", "Media uploaded but no media data was returned" + "\n- " + warnings.join("\n- "));
+        return response;
+      }

      $.export("$summary", `Media "${media.title}" uploaded successfully (ID: ${media.ID})` + "\n- " + warnings.join("\n- "));

94-98: ⚠️ Potential issue

Add return statement after error handling

When an error is caught, the function doesn't have an explicit return statement, which could lead to unexpected behavior if the error handler doesn't terminate execution.

    } catch (error) {
      
      wordpress.throwCustomError("Failed to upload media", error, warnings);
+      return;
    };
components/wordpress_com/wordpress_com.app.mjs (1)

12-29: 🛠️ Refactor suggestion

Improve error handling in _makeRequest

The current implementation of _makeRequest doesn't handle common API errors like rate limiting, authentication failures, or service unavailability. This could lead to unclear error messages for users.

  _makeRequest({
    $ = this,
    url,
    contentType,
    ...opts
  }) {

    return axios($, {
      url,
      headers: {
        "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
        "Content-Type": (contentType)
          ? contentType
          : "application/json",
      },
      ...opts,
+     validateStatus: () => true, // Don't throw on non-2xx responses
    })
+   .then((response) => {
+     // Handle API errors with appropriate messages
+     if (response.status >= 400) {
+       const errorMsg = response.data?.message || `Request failed with status ${response.status}`;
+       if (response.status === 429) {
+         throw new Error(`WordPress API rate limit exceeded: ${errorMsg}`);
+       } else if (response.status === 401 || response.status === 403) {
+         throw new Error(`Authentication error: ${errorMsg}. Please check your WordPress.com API credentials.`);
+       } else {
+         throw new Error(`WordPress API error: ${errorMsg}`);
+       }
+     }
+     return response;
+   });
  },
🧹 Nitpick comments (4)
components/wordpress_com/actions/upload-media.mjs (2)

39-39: Fix typo in "description" property

There's a typo in the property name "descripion" which should be "description".

-      descripion: "Optional description text to provide more details about the uploaded media.",
+      description: "Optional description text to provide more details about the uploaded media.",

91-91: Remove debug console.log statement

Production code should not contain console.log statements used for debugging.

-      console.log(response);
components/wordpress_com/wordpress_com.app.mjs (2)

78-78: Fix incorrect comment about HTTP method

The comment mentions using POST instead of DELETE, but this method actually uses GET. This appears to be a copy-paste error from the deleteWordpressPost method.

-        method: "GET", // use POST instead of DELETE. Wordpress does not allow DELETE methods on free accounts.
+        method: "GET",

119-120: Remove unnecessary empty line

For consistency with the formatting in other methods, remove the extra empty line.

    return this._makeRequest({
      method: "GET",
      url: `https://public-api.wordpress.com/rest/v1.1/sites/${site}/followers/`,
-
      ...opts,
    });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8fbc421 and fb9ec32.

📒 Files selected for processing (9)
  • components/wordpress_com/actions/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media.mjs (1 hunks)
  • components/wordpress_com/common/methods.mjs (1 hunks)
  • components/wordpress_com/common/utils.mjs (1 hunks)
  • components/wordpress_com/sources/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post.mjs (1 hunks)
  • components/wordpress_com/wordpress_com.app.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/wordpress_com/common/utils.mjs
🚧 Files skipped from review as they are similar to previous changes (6)
  • components/wordpress_com/actions/create-post.mjs
  • components/wordpress_com/actions/delete-post.mjs
  • components/wordpress_com/sources/new-post.mjs
  • components/wordpress_com/sources/new-follower.mjs
  • components/wordpress_com/sources/new-comment.mjs
  • components/wordpress_com/common/methods.mjs
🧰 Additional context used
🪛 GitHub Check: Lint Code Base
components/wordpress_com/actions/upload-media.mjs

[warning] 36-36:
Component prop description must have a description. See https://pipedream.com/docs/components/guidelines/#props

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (1)
components/wordpress_com/wordpress_com.app.mjs (1)

31-121: LGTM! WordPress.com API methods implementation

The implementation of WordPress.com API methods is comprehensive and covers all necessary endpoints for the proposed actions and sources. The structure is clean and follows consistent patterns, making the code maintainable and easy to understand.

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

🧹 Nitpick comments (17)
components/wordpress_com/sources/new-comment/new-comment.mjs (3)

94-100: Consider the chronological order of emitted events

You're using reverse() to emit events in chronological order, which is good. However, be aware that this creates a new array and may have performance implications for a large number of comments.

Consider evaluating if this is the most efficient approach for your use case, especially if you expect large batches of comments.


95-99: Enhance the event summary to include more context

The current summary only includes the author name or "Anonymous Comment". Consider including more context, such as a portion of the comment text or the title of the post being commented on.

  this.$emit(comment, {
    id: comment.ID,
-   summary: comment.author?.name || "Anonymous Comment",
+   summary: `${comment.author?.name || "Anonymous"} commented: "${comment.content?.substring(0, 30)}..."`,
    ts: comment.date && +new Date(comment.date),
  });

82-92: Consider optimizing the ID comparison loop

The current implementation has a nested condition that may be redundant. Since maxCommentIdTracker is initialized to lastCommentId, you only need to check if the comment ID is greater than maxCommentIdTracker.

  let maxCommentIdTracker = lastCommentId;
  const newComments = [];

  for (const comment of comments) {
-   if (Number(comment.ID) > lastCommentId) {
+   if (Number(comment.ID) > maxCommentIdTracker) {
      newComments.push(comment);
-     if (Number(comment.ID) > maxCommentIdTracker) {
        maxCommentIdTracker = comment.ID;
-     }
    }
  }
components/wordpress_com/sources/new-follower/new-follower.mjs (2)

74-80: Consider emitting followers in reverse chronological order for consistency

Unlike the new-comment source, this component does not emit events in reverse chronological order. This inconsistency might lead to confusing behavior across different components.

- for (const follower of newFollowers) {
+ for (const follower of newFollowers.reverse()) {
    this.$emit(follower, {
      id: follower.ID,
      summary: follower.label || follower.login || "Anonymous Follower",
      ts: follower.date_subscribed && +new Date(follower.date_subscribed),
    });
  }

62-72: Consider optimizing the ID comparison loop

Similar to the comments source, this implementation has a nested condition that may be redundant.

  let maxFollowerIdTracker = lastFollowerId;
  const newFollowers = [];

  for (const follower of followers) {
-   if (Number(follower.ID) > lastFollowerId) {
+   if (Number(follower.ID) > maxFollowerIdTracker) {
      newFollowers.push(follower);
-     if (Number(follower.ID) > maxFollowerIdTracker) {
        maxFollowerIdTracker = follower.ID;
-     }
    }
  }
components/wordpress_com/sources/new-post/new-post.mjs (2)

97-108: Consider optimizing the ID comparison loop

Similar to the other sources, this implementation has a nested condition that may be redundant.

  let maxPostIdTracker = lastPostId;
  const newPosts = [];

  for (const post of posts) {
-   if (Number(post.ID) > lastPostId) {
+   if (Number(post.ID) > maxPostIdTracker) {
      newPosts.push(post);
-     if (Number(post.ID) > maxPostIdTracker) {
        maxPostIdTracker = post.ID;
-     }
    }
  }

112-116: Enhance the event summary to include post type

The current summary only includes the post title. Consider enhancing it to include the post type for better context.

  this.$emit(post, {
    id: post.ID,
-   summary: post.title,
+   summary: `New ${this.type}: ${post.title || "Untitled"}`,
    ts: post.date && +new Date(post.date),
  });
components/wordpress_com/actions/create-post/create-post.mjs (4)

68-68: Remove debug comment

There's a "// TEST" comment that should be removed before merging.

- warnings.push(...wordpress.checkDomainOrId(site)); // TEST
+ warnings.push(...wordpress.checkDomainOrId(site));

73-73: Remove debug comment

There's another "// TEST" comment that should be removed.

- response = await wordpress.createWordpressPost({ //TEST
+ response = await wordpress.createWordpressPost({

76-79: Be explicit about fields passed to the API

The current implementation spreads all props not explicitly excluded into the data object. This could lead to unintended fields being passed if new props are added in the future.

  data: {
-   ...fields,
+   title: fields.title,
+   content: fields.content,
+   status: fields.status,
+   type: fields.type,
  },

86-86: Improve summary formatting

The current summary concatenates the success message with warnings using a newline and a bullet point. This could look cleaner.

- $.export("$summary", `Post successfully created. ID = ${response?.ID}` + "\n- "  + warnings.join("\n- "));
+ $.export("$summary", `Post successfully created. ID = ${response?.ID}${warnings.length ? "\n- " + warnings.join("\n- ") : ""}`);
components/wordpress_com/actions/delete-post/delete-post.mjs (2)

36-47: Consider adding more detailed error handling

The error handling is implemented, but it could be enhanced to provide more specific error messages based on the type of error encountered.

Consider improving the error handling to provide more context about what specifically went wrong:

 try {
   response = await wordpress.deleteWordpressPost({
     $,
     site,
     postId,
   });
 } catch (error) {
-  wordpress.throwCustomError("Could not delete post", error, warnings);
+  wordpress.throwCustomError(`Could not delete post ID ${postId} from site ${site}`, error, warnings);
 };

52-52: Remove empty line at end of file

There's an empty line at the end of the file that should be removed for consistency.

components/wordpress_com/actions/upload-media/upload-media.mjs (4)

71-79: Consider adding more robust content type handling

The current implementation assumes the FormData object always has headers with content-type. Consider adding a fallback in case the headers are absent.

Add a safeguard for cases where form.getHeaders() might not contain expected content-type:

 try {
+  const contentType = form.getHeaders?.()?.["content-type"] || "multipart/form-data";
   response = await wordpress.uploadWordpressMedia({
     $,
-    contentType: form.getHeaders()["content-type"],
+    contentType,
     site,
     data: form,
   });

87-91: Error handling is appropriate but could be more informative

The error handling catches exceptions but could provide more context about what specifically failed during the upload process.

Enhance error messaging to be more specific:

 } catch (error) {
-  wordpress.throwCustomError("Failed to upload media", error, warnings);
+  wordpress.throwCustomError(`Failed to upload media to site ${site}`, error, warnings);
 };

84-85: Consider removing console.log statements before production

There's a console.log(response) statement that should be removed or replaced with proper logging for production code.

- console.log(response);
+ // Consider using a proper logging mechanism instead of console.log

95-95: Remove empty line at end of file

There's an empty line at the end of the file that should be removed for consistency.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fb9ec32 and 68d1235.

📒 Files selected for processing (6)
  • components/wordpress_com/actions/create-post/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media/upload-media.mjs (1 hunks)
  • components/wordpress_com/sources/new-comment/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post/new-post.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (17)
components/wordpress_com/sources/new-comment/new-comment.mjs (3)

1-7: LGTM: Component metadata looks good

The component key, name, description, and version are well-defined and follow the Pipedream component standards.


9-31: Props configuration is well-structured

The props are clearly defined with appropriate types, labels, descriptions, and validation constraints. The optional flag and min/max values for the number prop provide good guardrails for user input.


47-60: Site validation and error handling look good

Good use of the checkDomainOrId method to validate the site parameter and accumulate warnings rather than throwing errors immediately.

components/wordpress_com/sources/new-follower/new-follower.mjs (2)

1-8: LGTM: Component metadata looks good

The component key, name, description, and version are well-defined and follow the Pipedream component standards.


9-17: Props configuration is well-structured

The props are clearly defined with appropriate types, labels, and descriptions.

components/wordpress_com/sources/new-post/new-post.mjs (3)

1-8: LGTM: Component metadata looks good

The component key, name, description, and version are well-defined and follow the Pipedream component standards.


9-46: Props configuration is well-structured with good options

The props are clearly defined with appropriate types, labels, descriptions, and options. The type prop has well-defined options for post, page, and attachment.


75-77: Good handling of different response formats

Nice job distinguishing between attachments and other post types to extract the relevant data array from the response.

components/wordpress_com/actions/create-post/create-post.mjs (2)

1-8: LGTM: Component metadata looks good

The component key, name, description, and version are well-defined and follow the Pipedream component standards.


9-56: Props configuration is well-structured with good options

The props are clearly defined with appropriate types, labels, descriptions, and options. The status and type props have well-defined options.

components/wordpress_com/actions/delete-post/delete-post.mjs (3)

1-9: Component key follows naming conventions correctly

The component key "wordpress_com-delete-post" properly follows Pipedream's naming pattern of app_name_slug-slugified-component-name as specified in the PR guidelines.


10-22: Props are well-defined with clear descriptions

The props are properly defined with appropriate types, labels, and helpful descriptions that guide users on how to use the action.


24-35: Good implementation of input validation

The code properly collects warnings from the domain/ID validation check, which follows best practices for input validation before performing actions.

components/wordpress_com/actions/upload-media/upload-media.mjs (4)

1-11: Component key and description are appropriately defined

The component key follows the required naming pattern, and the description clearly explains the purpose of the action.


12-41: Props are well-structured with appropriate optionality

The props are properly defined with clear labels, descriptions, and type constraints. Optional fields (title, caption, description) are correctly marked as such.


43-56: Good implementation of input validation

The code appropriately validates the site input and collects warnings to be displayed to the user later, following best practices.


57-68: Media handling accommodates different input formats

The code handles both FormData objects and direct media URLs, providing flexibility for different usage scenarios.

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

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

51-67: 🛠️ Refactor suggestion

Improve error handling in _makeRequest.

The current implementation doesn't handle API errors like rate limiting, authentication failures, or service unavailability. Based on past review comments, this improvement was suggested but not implemented.

Enhance the method to properly handle API errors and provide more context:

_makeRequest({
  $ = this,
  path,
  contentType,
  ...opts
}) {
  return axios($, {
      url: `${this._baseUrl()}${path}`,
      headers: {
        "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
        "Content-Type": (contentType)
          ? contentType
          : "application/json",
      },
      ...opts,
+     validateStatus: () => true, // Don't throw on non-2xx responses
    })
+   .then((response) => {
+     // Handle API errors with appropriate messages
+     if (response.status >= 400) {
+       const errorMsg = response.data?.message || `Request failed with status ${response.status}`;
+       if (response.status === 429) {
+         throw new Error(`WordPress API rate limit exceeded: ${errorMsg}`);
+       } else if (response.status === 401 || response.status === 403) {
+         throw new Error(`Authentication error: ${errorMsg}. Please check your WordPress.com API credentials.`);
+       } else {
+         throw new Error(`WordPress API error: ${errorMsg}`);
+       }
+     }
+     return response;
+   });
},
🧹 Nitpick comments (2)
components/wordpress_com/wordpress_com.app.mjs (2)

7-45: prop definitions look good, but consider input validation.

The siteId and postId prop definitions with async options are well-structured, providing a good user experience with dynamic loading. However, the description for siteId instructs users "Do not include 'https://' or 'www'", which relies on user compliance rather than programmatic validation.

Consider adding a validation function to automatically strip or reject invalid inputs:

siteId: {
  type: "string",
  label: "Site ID or Domain",
  description: "Enter a site ID or domain (e.g. testsit38.wordpress.com). Do not include 'https://' or 'www'.",
+ validateInput: (input) => {
+   if (input.includes('https://') || input.includes('http://') || input.includes('www.')) {
+     return "Please enter the domain without 'https://', 'http://' or 'www' prefix";
+   }
+   return true;
+ },
  async options() {
    // ...
  }
}

152-157: Add JSDoc comments for better documentation.

The methods in this file lack JSDoc comments, which would improve understanding of parameters, return values, and potential errors.

Add JSDoc comments for better documentation:

+ /**
+  * Lists all WordPress.com sites the authenticated user has access to
+  * 
+  * @param {Object} opts - Additional options to pass to the request
+  * @returns {Promise<Object>} Response containing the sites array
+  */
listSites(opts = {}) {
  return this._makeRequest({
    path: "/me/sites",
    ...opts,
  });
},
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9e00ce2 and f62e918.

📒 Files selected for processing (7)
  • components/wordpress_com/actions/create-post/create-post.mjs (1 hunks)
  • components/wordpress_com/actions/delete-post/delete-post.mjs (1 hunks)
  • components/wordpress_com/actions/upload-media/upload-media.mjs (1 hunks)
  • components/wordpress_com/sources/new-comment/new-comment.mjs (1 hunks)
  • components/wordpress_com/sources/new-follower/new-follower.mjs (1 hunks)
  • components/wordpress_com/sources/new-post/new-post.mjs (1 hunks)
  • components/wordpress_com/wordpress_com.app.mjs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/wordpress_com/actions/create-post/create-post.mjs
🚧 Files skipped from review as they are similar to previous changes (5)
  • components/wordpress_com/sources/new-comment/new-comment.mjs
  • components/wordpress_com/actions/upload-media/upload-media.mjs
  • components/wordpress_com/actions/delete-post/delete-post.mjs
  • components/wordpress_com/sources/new-follower/new-follower.mjs
  • components/wordpress_com/sources/new-post/new-post.mjs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (3)
components/wordpress_com/wordpress_com.app.mjs (3)

1-2: Good job with modularizing the component.

The imports look clean and appropriate. Importing common methods from a separate file promotes code reusability and maintainability.


48-50: LGTM - Clean base URL implementation.

Good practice to use a method for the base URL rather than hardcoding it throughout the component.


68-77: CRUD operations implemented correctly.

The implementation of createWordpressPost, uploadWordpressMedia, and deleteWordpressPost methods looks good. The comment explaining the use of POST instead of DELETE for free WordPress accounts is helpful context.

Also applies to: 78-89, 90-98

@michelle0927 michelle0927 merged commit 5f1b080 into PipedreamHQ:master Apr 29, 2025
10 of 11 checks passed
@coderabbitai coderabbitai bot mentioned this pull request May 1, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Components] wordpress_com

4 participants