Skip to content

Conversation

@luancazarine
Copy link
Collaborator

@luancazarine luancazarine commented Oct 9, 2025

Resolves #10808

Summary by CodeRabbit

  • New Features
    • Add Item action: add torrents to your Bitport account, with optional target folder selection.
    • Search action: find folders and files in your Bitport cloud and get a quick summary of results.
    • New File trigger: emits events when new files appear in a selected folder.
    • New Media trigger: emits events for newly added audio/video.
    • Folder picker & improved folder listing for actions/triggers.
    • Sample test events included for trigger previews.
  • Chores
    • Bumped Bitport package to version 0.1.0 and added platform dependency.

- Introduced `Add Item` action for adding torrents with optional folder selection.
- Added `Search` action to find files and folders in the cloud.
- Implemented utility function `prepareList` for organizing folder and file data.
- Updated `bitport.app.mjs` to include new prop definitions and methods for folder management.
- Created new sources for detecting new files and media, enhancing event-driven capabilities.
- Bumped package version to 0.1.0 and added necessary dependencies.
@luancazarine luancazarine linked an issue Oct 9, 2025 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Oct 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
pipedream-docs Ignored Ignored Oct 9, 2025 8:41pm
pipedream-docs-redirect-do-not-edit Ignored Ignored Oct 9, 2025 8:41pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

Walkthrough

Adds a Bitport integration: core app with API helpers and folder selection, two actions (Search, Add Item), a prepareList utility, a reusable polling base source, two concrete sources (New File, New Media) with sample events, and package metadata/dependency updates.

Changes

Cohort / File(s) Summary
Bitport App Core
components/bitport/bitport.app.mjs
Implements API helpers (_apiUrl, _getHeaders, _makeRequest), search, listFolders, addItem, and adds a folderCode propDefinition with dynamic options. Imports axios and prepareList.
Actions
components/bitport/actions/add-item/add-item.mjs, components/bitport/actions/search/search.mjs
New actions: Add Item posts to /transfers and returns response; Search queries /search/{query}, returns results and exports a summary with folder/file counts.
Sources Base
components/bitport/sources/common/base.mjs
New reusable polling base: props for app/db/timer/folderCode, methods to track last seen date, emitEvent(maxResults), deploy() bootstrap, and run() to poll, plus filtering/sorting/emitting logic using prepareList.
Source: New File
components/bitport/sources/new-file/new-file.mjs, components/bitport/sources/new-file/test-event.mjs
New source extending common base; emits "New File" events, provides getSummary, and includes a sample event payload.
Source: New Media
components/bitport/sources/new-media/new-media.mjs, components/bitport/sources/new-media/test-event.mjs
New source extending common base; filters for audio/video via getFilter, emits "New Media" summaries, and includes a sample media event payload.
Utils
components/bitport/common/utils.mjs
Adds prepareList(items, parentName = "", filesOnly = false) to recursively flatten folder/file trees and optionally return files-only lists.
Package
components/bitport/package.json
Bumps package version to 0.1.0 and adds dependency "@pipedream/platform": "^3.1.0".

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Action as Add Item Action
  participant App as Bitport App
  participant API as Bitport API

  User->>Action: provide `torrent` (+ optional `folderCode`)
  Action->>App: addItem({ torrent, folder_code })
  App->>API: POST /v2/transfers
  API-->>App: 201 Created + transfer data
  App-->>Action: response
  Action-->>User: export "$summary" + data
Loading
sequenceDiagram
  autonumber
  actor User
  participant Action as Search Action
  participant App as Bitport App
  participant API as Bitport API

  User->>Action: provide `query`
  Action->>App: search({ query })
  App->>API: GET /v2/search/{query}
  API-->>App: 200 OK + results
  App-->>Action: { folders, files }
  Action-->>User: export "$summary" + data
Loading
sequenceDiagram
  autonumber
  participant Timer as Timer
  participant Source as Base Source
  participant App as Bitport App
  participant API as Bitport API
  participant Util as prepareList
  participant Stream as Event Stream

  Timer-->>Source: tick() / deploy()
  Source->>App: listFiles({ folderPathBase64, maxResults? })
  App->>API: GET /v2/cloud/byPath
  API-->>App: 200 OK + tree
  App-->>Source: tree
  Source->>Util: prepareList(items, filesOnly: true)
  Util-->>Source: flattened files
  Source->>Source: filter by date (> lastDate) and optional getFilter
  Source->>Source: sort desc, cap to maxResults, update lastDate
  loop emit oldest -> newest
    Source-->>Stream: emit({ id, summary, ts })
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop through clouds where new files play,
Media and torrents brighten my day.
I list, I search, I add with a cheer,
Emitting events far and near.
A rabbit’s small dance for Bitport’s new way. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description only contains “Resolves #10808” and does not follow the repository’s description template, which requires a “## WHY” section and additional context about why the changes are needed. Please expand the pull request description to include the required “## WHY” section with an explanation of the motivation behind these Bitport.io actions and sources, as well as any relevant design considerations.
Title Check ❓ Inconclusive The title “10808 bitportio” only references the issue number and the app name without summarizing the changes or their intent, making it too vague to quickly understand the main contribution of the pull request. Consider renaming the title to something more descriptive of the primary changes, such as “Add Bitport.io actions and sources for search, add-item, new-file, and new-media,” to clearly convey what this pull request implements.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The changes fulfill the issue’s coding requirements by implementing the Bitport.io app integration with search and add-item actions, as well as adding the New File and New Media sources with appropriate filtering and summary methods for #10808.
Out of Scope Changes Check ✅ Passed All modifications relate directly to the Bitport.io integration tasks specified in issue #10808, and there are no unrelated or extraneous changes outside of implementing the app methods, actions, and sources for this feature.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10808-bitportio

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

❤️ Share

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

Copy link
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 (6)
components/bitport/sources/new-media/test-event.mjs (1)

1-22: Note: Identical test event.

This test event is identical to components/bitport/sources/new-file/test-event.mjs. If both sources (New File and New Media) are meant to emit the same event structure, this duplication is acceptable. Otherwise, consider whether New Media should filter by media types or use a different sample.

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

8-11: Consider adding null checks for item.files.

If item.files is undefined or null, the spread operator will throw a runtime error.

Apply this diff:

     if (filesOnly) {
       itemsArray.push(
-        ...item.files,
+        ...(item.files || []),
       );
     } else {

19-23: Consider adding null checks for item.folders.

If item.folders is undefined or null, the recursive call and iteration will fail.

Apply this diff:

     itemsArray.push(...prepareList({
-      items: item.folders,
+      items: item.folders || [],
       parentName: fullName,
       filesOnly,
     }));
components/bitport/bitport.app.mjs (1)

205-231: Consider removing or documenting commented paginate helper.

The commented-out paginate async generator helper is either incomplete or for future use. Consider removing it if not needed, or adding a TODO comment explaining its purpose.

components/bitport/actions/search/search.mjs (1)

17-29: Consider adding defensive checks for response structure.

If the API returns an error or the response structure is unexpected, accessing data.folders.length on Line 23 will throw a runtime error.

Apply this diff to add basic null checks:

     const { data } = await this.app.search({
       $,
       query: this.query,
     });
 
-    $.export("$summary", `Successfully found for ${data.folders.length} folder${data.folders.length > 1
+    const folderCount = data?.folders?.length || 0;
+    const fileCount = data?.files?.length || 0;
+    $.export("$summary", `Successfully found ${folderCount} folder${folderCount > 1
       ? "s"
-      : ""} and ${data.files.length} file${data.files.length > 1
+      : ""} and ${fileCount} file${fileCount > 1
       ? "s"
       : ""}`);
     return data;
components/bitport/sources/common/base.mjs (1)

52-55: Optimize date parsing in sort comparator.

The sort comparator calls Date.parse() twice for every comparison. Consider parsing dates once and caching, or sorting by the pre-parsed values.

Apply this diff for more efficient sorting:

       if (items.length) {
-        items = items.filter((item) => {
-          return Date.parse(item.created_at.date) > lastDate;
-        })
-          .sort((a, b) => Date.parse(b.created_at.date) - Date.parse(a.created_at.date));
+        items = items
+          .map((item) => ({
+            ...item,
+            _timestamp: Date.parse(item.created_at.date),
+          }))
+          .filter((item) => item._timestamp > lastDate)
+          .sort((a, b) => b._timestamp - a._timestamp);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1744391 and 7325139.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • components/bitport/actions/add-item/add-item.mjs (1 hunks)
  • components/bitport/actions/search/search.mjs (1 hunks)
  • components/bitport/bitport.app.mjs (1 hunks)
  • components/bitport/common/utils.mjs (1 hunks)
  • components/bitport/package.json (2 hunks)
  • components/bitport/sources/common/base.mjs (1 hunks)
  • components/bitport/sources/new-file/new-file.mjs (1 hunks)
  • components/bitport/sources/new-file/test-event.mjs (1 hunks)
  • components/bitport/sources/new-media/new-media.mjs (1 hunks)
  • components/bitport/sources/new-media/test-event.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
components/bitport/common/utils.mjs (1)
components/bitport/sources/common/base.mjs (1)
  • items (46-49)
components/bitport/sources/new-media/new-media.mjs (1)
components/bitport/sources/common/base.mjs (1)
  • items (46-49)
components/bitport/sources/common/base.mjs (2)
components/bitport/actions/add-item/add-item.mjs (1)
  • response (25-31)
components/bitport/common/utils.mjs (2)
  • prepareList (1-27)
  • prepareList (1-27)
components/bitport/bitport.app.mjs (1)
components/bitport/common/utils.mjs (2)
  • prepareList (1-27)
  • prepareList (1-27)
⏰ 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: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (16)
components/bitport/sources/new-file/test-event.mjs (1)

1-22: LGTM!

The test event structure appears consistent with the Bitport API response format for file metadata.

components/bitport/package.json (2)

3-3: LGTM!

Version bump to 0.1.0 is appropriate for the new features being added (sources and actions).


15-16: LGTM!

The dependency on @pipedream/platform version 3.1.0 is correct and aligns with the latest stable release.

Based on learnings.

components/bitport/sources/new-file/new-file.mjs (1)

1-19: LGTM!

The source module follows Pipedream conventions correctly, extending the common base and providing a custom summary method.

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

1-2: LGTM!

The imports are correct, using the axios helper from @pipedream/platform and the local prepareList utility.


26-42: LGTM!

The API helper methods (_apiUrl, _getHeaders, _makeRequest) follow Pipedream conventions correctly and use the OAuth access token from this.$auth.


43-57: LGTM!

The search, listFolders, and addItem methods correctly use the internal request helper to call the Bitport API endpoints.

components/bitport/actions/add-item/add-item.mjs (1)

1-36: LGTM!

The action follows Pipedream conventions correctly, properly using the app's addItem method and exporting a summary.

components/bitport/sources/new-media/new-media.mjs (3)

1-2: LGTM!

Import statements are correct and follow the standard pattern for Pipedream component extensions.


4-11: LGTM!

Component metadata is properly configured with appropriate dedupe strategy for a polling source.


12-26: LGTM!

The getFilter and getSummary methods correctly implement media-specific filtering and event formatting.

components/bitport/sources/common/base.mjs (5)

1-3: LGTM!

Import statements are correct and use appropriate platform utilities.


5-22: LGTM!

Props are properly configured for a polling source with appropriate timer interval and folder selection.


78-85: LGTM!

The deploy hook and run method follow the standard pattern for Pipedream polling sources, with deploy loading an initial batch of historical events.


36-37: Confirm encoding the correct folderCode property
Encoding this.folderCode.label targets the display name, not the folder identifier. Verify that folderCode exposes an ID property (e.g., .value) and use that (or the raw folderCode) when Base64-encoding.


39-55: Client-side date filtering is correct: Bitport API has no server-side date filter for listFiles; local filtering is required.

- Removed the `foldersOnly` option from the `prepareList` function.
- Deleted the `listFiles` method to streamline file management.
- Updated the `listFolders` method call for improved folder handling.
- Added `annotations` to `Add Item` and `Search` actions for better metadata.
- Adjusted timestamp parsing to ensure consistency across data handling.
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 7325139 and 416bb62.

📒 Files selected for processing (4)
  • components/bitport/actions/add-item/add-item.mjs (1 hunks)
  • components/bitport/actions/search/search.mjs (1 hunks)
  • components/bitport/bitport.app.mjs (1 hunks)
  • components/bitport/sources/common/base.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/bitport/sources/common/base.mjs
  • components/bitport/actions/search/search.mjs
🧰 Additional context used
🧬 Code graph analysis (1)
components/bitport/bitport.app.mjs (2)
components/bitport/common/utils.mjs (2)
  • prepareList (1-27)
  • prepareList (1-27)
components/spotify/actions/get-album-tracks/get-album-tracks.mjs (1)
  • axios (53-56)
⏰ 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: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (4)
components/bitport/bitport.app.mjs (2)

15-20: LGTM! Parameter mismatch from previous review has been fixed.

The previous review flagged an incorrect foldersOnly: true parameter. This has been correctly resolved by relying on the default filesOnly = false in prepareList, which returns folder objects with the fullName property needed for the folder selector.


25-64: LGTM! Clean API helper implementation.

The API helper methods (_apiUrl, _getHeaders, _makeRequest, search, listFolders, addItem) follow Pipedream conventions and properly use the axios helper from @pipedream/platform. The removal of the hardcoded mock data from the previous listFiles method also addresses a critical issue from the past review.

components/bitport/actions/add-item/add-item.mjs (2)

9-13: LGTM! Annotations added as requested.

The previous review flagged missing annotations. These have been correctly added with appropriate values:

  • destructiveHint: false - adding a torrent is not destructive
  • openWorldHint: true - action calls external Bitport API
  • readOnlyHint: false - action creates a new transfer

29-40: LGTM! Clean action implementation.

The action properly:

  • Calls this.app.addItem() with the Pipedream step context $
  • Converts the camelCase prop folderCode to snake_case folder_code as expected by the API
  • Exports a user-friendly summary message
  • Returns the API response

Comment on lines +12 to +21
async options() {
const { data } = await this.listFolders();

return prepareList({
items: data,
}).map((item) => ({
label: item.fullName,
value: item.code,
}));
},
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 | 🔴 Critical

🧩 Analysis chain

Verify the API response structure for folder listing.

The code destructures data from the listFolders() response on line 13. Ensure that the Bitport API actually returns an object with a data property. If the API returns the folder array directly (without wrapping it in a data property), this will fail.

Run the following script to check the actual API response structure:

Alternatively, please search the web for the Bitport API documentation:


🏁 Script executed:

#!/bin/bash
# Description: Search for API response examples or tests that show the structure

# Search for any test files or documentation about the listFolders response
rg -n -A10 -B3 'cloud/byPath|listFolders' --type=js

# Search for any example responses or mock data
rg -n -A10 'status.*success.*data' --type=json --type=js

Length of output: 0


🌐 Web query:

What is the response structure of the Bitport.io API endpoint GET /v2/cloud/byPath with scope=recursive parameter?

💡 Result:

Top-level wrapper

  • status: "success" | "error"
  • data: object (on success)
  • errors: null | array

When calling GET /v2/cloud/byPath?scope=recursive the data object contains the folder metadata plus recursive lists of folders and files. Skeleton (fields shown from Bitport docs):

{
"status": "success",
"data": {
"name": "",
"code": "<folder code|null>",
"size": ,
"folders": [
{
"name": "",
"code": "",
"size": "",
"created_at": { "date": "YYYY-MM-DD HH:MM:SS.000000", "timezone_type": 3, "timezone": "UTC" },
"files_count": ""
},
...
],
"files": [
{
"name": "",
"crc32": ,
"created_at": { "date": "YYYY-MM-DD HH:MM:SS.000000", "timezone_type": 3, "timezone": "UTC" },
"code": "",
"parent_folder_code": "",
"size": ,
"video": true|false,
"conversion_status": "",
"screenshots": { "small": "", "medium": "", "big": "" },
"extension": "",
"type": "<video|music|archive|...>",
"paused_at": ,
"virus": true|false
},
...
]
},
"errors": null
}

Source: Bitport API docs for cloud endpoints and file-byPath examples. [1][2]

References
[1] Bitport API — /v2/cloud (example recursive response).
[2] Bitport API — /v2/files/byPath (file object structure).


Extract the folders array from the API response
The Bitport endpoint returns { status, data: { folders: [...], files: […] } }, so const { data } = await this.listFolders() yields an object, not an array. Update to:

const { data: { folders } } = await this.listFolders();
return prepareList({ items: folders }).map(/* … */);
🤖 Prompt for AI Agents
In components/bitport/bitport.app.mjs around lines 12 to 21, the code
destructures the API response as const { data } = await this.listFolders(), but
the endpoint returns data: { folders: [...], files: [...] } so data is an object
not an array; change the destructure to extract folders (const { data: { folders
} } = await this.listFolders()) and pass folders into prepareList (prepareList({
items: folders })) then map over the resulting list to return label/value
objects.

Copy link
Collaborator

@michelle0927 michelle0927 left a comment

Choose a reason for hiding this comment

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

LGTM, Ready for QA!

@vunguyenhung vunguyenhung merged commit d6385d7 into master Oct 10, 2025
10 checks passed
@vunguyenhung vunguyenhung deleted the 10808-bitportio branch October 10, 2025 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bitport.io

3 participants