Skip to content

Conversation

GTFalcao
Copy link
Collaborator

@GTFalcao GTFalcao commented Oct 4, 2025

Closes #18630

Summary by CodeRabbit

  • New Features
    • Added AirTop integration with actions: Create Session (optional profile save), End Session, Create Window, Load URL, Query Page, and Scrape Content.
    • New app-level AirTop client exposing session/window management and page/query/scrape APIs.
    • Added a reusable polling worker and a "New Session Created" event source.
    • Utility helpers for parsing options and human-friendly time formatting.
  • Chores
    • Bumped package version to 0.1.0 and added a platform dependency.

Copy link

vercel bot commented Oct 4, 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 4, 2025 1:24am
pipedream-docs-redirect-do-not-edit Ignored Ignored Oct 4, 2025 1:24am

Copy link
Contributor

coderabbitai bot commented Oct 4, 2025

Walkthrough

Adds a new Airtop app client with HTTP request wrapper and public methods, multiple new action modules for session/window/page operations, polling infrastructure and a concrete "new session created" source, utility helpers, and updates package metadata and dependencies.

Changes

Cohort / File(s) Summary of changes
Airtop app client
components/airtop/airtop.app.mjs
Adds centralized _headers and _makeRequest, populates propDefinitions, and implements public methods: createSession, listSessions, getSession, endSession, createWindow, listWindows, getWindow, loadUrl, queryPage, scrapeContent, saveProfileOnTermination. Removes authKeys().
Actions: session & window ops
components/airtop/actions/create-session/create-session.mjs, components/airtop/actions/create-window/create-window/create-window.mjs, components/airtop/actions/end-session/end-session.mjs
New actions to create sessions (with profileName validation and optional save-on-termination), create windows, and end sessions. Each exports a summary and returns API responses.
Actions: page ops
components/airtop/actions/load-url/load-url.mjs, components/airtop/actions/query-page/query-page.mjs, components/airtop/actions/scrape-content/scrape-content.mjs
New actions to load URLs, query page content with AI, and scrape structured content. Props include session/window scoping and optional timing/cost controls; run methods call corresponding app methods and export summaries.
Sources: polling infrastructure
components/airtop/sources/common/polling.mjs, components/airtop/sources/new-session-created/new-session-created.mjs
Introduces a reusable polling base (timestamp persistence, isNew, run loop, abstract getResources/generateMeta) and a concrete source implementing session pagination, filtering for new sessions, metadata generation, and event emission.
Utilities
components/airtop/common/utils.mjs
Adds parseObjectEntries(value) (normalizes object/JSON string and parses values) and formatTimeAgo(dateString) (human-friendly relative time).
Package metadata
components/airtop/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 Create Session Action
  participant App as Airtop App
  participant API as Airtop API

  User->>Action: Run with profileName, options
  Action->>Action: Validate profileName
  Action->>App: createSession(data)
  App->>API: POST /sessions
  API-->>App: 201 { sessionId, status }
  App-->>Action: Response
  alt saveProfileOnTermination requested and profileName provided
    Action->>App: saveProfileOnTermination(sessionId, profileName)
    App->>API: POST /sessions/{id}/save-profile
    API-->>App: 200 { result }
    App-->>Action: Result
  end
  Action-->>User: Summary: sessionId, status
Loading
sequenceDiagram
  autonumber
  actor User
  participant Action as Load/Query/Scrape Action
  participant App as Airtop App
  participant API as Airtop API

  User->>Action: Run with sessionId, windowId, params
  Action->>App: loadUrl/queryPage/scrapeContent(...)
  App->>API: POST /sessions/{id}/windows/{id}/...
  API-->>App: 200 { response }
  App-->>Action: Response
  Action-->>User: Summary exported
Loading
sequenceDiagram
  autonumber
  participant Source as New Session Created Source
  participant Common as Polling Base
  participant App as Airtop App
  participant API as Airtop API
  participant Store as DB (lastTs)

  Source->>Store: _getLastTs()
  Source->>App: listSessions(limit, offset)
  App->>API: GET /sessions
  API-->>App: 200 { sessions[] }
  App-->>Source: sessions[]
  Source->>Source: Filter isNew(dateCreated > lastTs)
  loop per new session
    Source->>Source: generateMeta(session)
    Source-->>Source: emit(event, meta)
    Source->>Store: Update lastTs (max)
  end
  Source->>Store: _setLastTs(lastTs)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • luancazarine
  • michelle0927

Poem

I hop through headers, payloads light,
I spin up windows in the night.
I parse the fields, I poll the skies,
New sessions shine like carrot pies.
A tiny rabbit ships the bytes—hop, delight! 🐇✨

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 includes a “Closes #18630” reference and omits the required WHY section from the repository’s template, providing no context or rationale for the changes. Please expand the description to follow the template by adding a WHY section that explains the motivation, plus any additional details such as WHAT was changed and how it addresses the linked issue.
Title Check ❓ Inconclusive The title “Airtop new components” is vague and does not clearly convey the primary changes introduced in the pull request, as it fails to specify what components or modules have been added or updated. Please update the title to be more descriptive of the main contribution, for example “Add Airtop app client, actions, sources, and utilities” or “Implement new Airtop components for session and window management.”
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The pull request adds the Airtop app client methods, action modules, source modules, and utility functions exactly as outlined by issue #18630, fulfilling the coding requirements to integrate Airtop components.
Out of Scope Changes Check ✅ Passed All code modifications are contained within the components/airtop directory and relate directly to implementing the Airtop integration, with no unrelated or extraneous changes detected.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 18630-airtop-new-components

📜 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 e59d66f and 4e53f68.

📒 Files selected for processing (1)
  • components/airtop/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/airtop/package.json
⏰ 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: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base

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

🧹 Nitpick comments (4)
components/airtop/common/utils.mjs (2)

9-22: Consider adding error handling for initial JSON.parse.

If value is a string but contains invalid JSON, the JSON.parse on Line 11 will throw an uncaught error. Consider wrapping it in a try-catch or documenting that callers must provide valid JSON strings.

Apply this diff to add error handling:

 export function parseObjectEntries(value = {}) {
-  const obj = typeof value === "string"
-    ? JSON.parse(value)
-    : value;
+  let obj;
+  if (typeof value === "string") {
+    try {
+      obj = JSON.parse(value);
+    } catch (e) {
+      throw new Error(`Invalid JSON string provided to parseObjectEntries: ${e.message}`);
+    }
+  } else {
+    obj = value;
+  }
   return Object.fromEntries(
     Object.entries(obj).map(([
       key,
       value,
     ]) => [
       key,
       optionalParseAsJSON(value),
     ]),
   );
 }

24-51: Consider validating the date input.

If dateString is invalid, new Date(dateString) on Line 25 produces an Invalid Date object, causing diffInSeconds to be NaN. This results in incorrect output. Consider adding validation:

 export function formatTimeAgo(dateString) {
   const date = new Date(dateString);
+  if (isNaN(date.getTime())) {
+    throw new Error(`Invalid date string: ${dateString}`);
+  }
   const now = new Date();
   const diffInSeconds = Math.floor((now - date) / 1000);
components/airtop/sources/common/polling.mjs (1)

22-27: Avoid emitting every poll when dateCreated is absent

isNew currently returns true whenever resource.dateCreated is falsy. For any API object that omits this field, run() can’t advance lastTs, so the same record will be re-emitted on every poll. Please guard for that case so we quietly skip items without a timestamp (or add a fallback field).

-    isNew(resource, lastTs) {
-      if (!resource.dateCreated || !lastTs) {
-        return true;
-      }
-      return new Date(resource.dateCreated).getTime() > lastTs;
-    },
+    isNew(resource, lastTs) {
+      if (!lastTs) {
+        return true;
+      }
+      if (!resource.dateCreated) {
+        return false;
+      }
+      return new Date(resource.dateCreated).getTime() > lastTs;
+    },
components/airtop/airtop.app.mjs (1)

24-29: Handle missing timestamps in option labels

If Airtop omits lastActivity or dateCreated, formatTimeAgo yields “NaN days ago”, which looks broken in the UI. Guard for missing values and fall back to something like “unknown” before composing the label.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82f5551 and e59d66f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • components/airtop/actions/create-session/create-session.mjs (1 hunks)
  • components/airtop/actions/create-window/create-window.mjs (1 hunks)
  • components/airtop/actions/end-session/end-session.mjs (1 hunks)
  • components/airtop/actions/load-url/load-url.mjs (1 hunks)
  • components/airtop/actions/query-page/query-page.mjs (1 hunks)
  • components/airtop/actions/scrape-content/scrape-content.mjs (1 hunks)
  • components/airtop/airtop.app.mjs (1 hunks)
  • components/airtop/common/utils.mjs (1 hunks)
  • components/airtop/package.json (2 hunks)
  • components/airtop/sources/common/polling.mjs (1 hunks)
  • components/airtop/sources/new-session-created/new-session-created.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
components/airtop/actions/end-session/end-session.mjs (2)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/actions/create-session/create-session.mjs (2)
  • response (74-77)
  • sessionId (79-79)
components/airtop/actions/scrape-content/scrape-content.mjs (2)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/actions/query-page/query-page.mjs (1)
  • response (60-72)
components/airtop/actions/create-window/create-window.mjs (3)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/actions/create-session/create-session.mjs (1)
  • response (74-77)
components/airtop/actions/load-url/load-url.mjs (1)
  • response (53-62)
components/airtop/sources/new-session-created/new-session-created.mjs (2)
components/airtop/sources/common/polling.mjs (3)
  • lastTs (36-36)
  • resources (38-38)
  • resource (40-40)
components/airtop/airtop.app.mjs (4)
  • offset (14-14)
  • limit (13-13)
  • data (16-22)
  • data (40-42)
components/airtop/airtop.app.mjs (8)
components/airtop/sources/new-session-created/new-session-created.mjs (3)
  • limit (17-17)
  • offset (16-16)
  • data (21-26)
components/airtop/actions/create-session/create-session.mjs (3)
  • data (64-72)
  • sessionId (79-79)
  • response (74-77)
components/airtop/common/utils.mjs (1)
  • formatTimeAgo (24-51)
components/airtop/actions/create-window/create-window.mjs (2)
  • response (53-62)
  • windowId (64-64)
components/airtop/actions/end-session/end-session.mjs (1)
  • response (21-24)
components/airtop/actions/load-url/load-url.mjs (1)
  • response (53-62)
components/airtop/actions/query-page/query-page.mjs (1)
  • response (60-72)
components/airtop/actions/scrape-content/scrape-content.mjs (1)
  • response (54-63)
components/airtop/actions/load-url/load-url.mjs (2)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/actions/create-window/create-window.mjs (1)
  • response (53-62)
components/airtop/actions/create-session/create-session.mjs (2)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/common/utils.mjs (1)
  • parseObjectEntries (9-22)
components/airtop/actions/query-page/query-page.mjs (2)
components/airtop/airtop.app.mjs (1)
  • response (111-118)
components/airtop/actions/scrape-content/scrape-content.mjs (1)
  • response (54-63)
⏰ 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: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (11)
components/airtop/package.json (1)

3-3: LGTM! Version bump and dependency are appropriate.

The minor version bump to 0.1.0 correctly reflects the new feature additions (actions and sources). The @pipedream/platform dependency at ^3.1.0 is the current stable version.

Also applies to: 15-16

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

1-7: LGTM! Safe JSON parsing helper.

The try-catch wrapper correctly handles parsing failures by returning the original value, which is the expected behavior for optional parsing.

components/airtop/actions/end-session/end-session.mjs (1)

3-29: LGTM! Clean action implementation.

The action correctly terminates a session using the app's endSession method and provides a clear summary with the session ID.

components/airtop/actions/create-session/create-session.mjs (4)

1-10: LGTM! Correct imports and metadata.

The action properly imports utilities and uses ConfigurationError for validation failures.


11-49: LGTM! Well-documented props.

The property definitions are clear, with helpful descriptions and appropriate types. The documentation links provide additional context for users.


50-72: LGTM! Solid validation and data construction.

The profileName validation correctly enforces the documented character restrictions, and the data payload is properly structured with parsed additional options.


74-95: LGTM! Correct API flow and response handling.

The action properly handles the session creation and optional profile saving. The conditional logic ensures saveProfileOnTermination is only called when both the flag is enabled and a profile name is provided.

components/airtop/actions/scrape-content/scrape-content.mjs (1)

3-68: LGTM! Clean scraping action.

The action correctly scopes windowId to the selected sessionId and passes the appropriate parameters to the scraping API. The implementation follows the established pattern.

components/airtop/actions/load-url/load-url.mjs (1)

3-67: LGTM! Correct navigation action.

The action properly handles URL navigation with the required url parameter and correctly scoped windowId. The summary provides clear feedback about the navigation.

components/airtop/actions/create-window/create-window.mjs (1)

3-69: LGTM! Well-structured window creation action.

The action provides sensible defaults (Pipedream homepage and 1280x720 resolution) and follows the established pattern of extracting the ID from the response. The implementation is clean and correct.

components/airtop/actions/query-page/query-page.mjs (1)

3-77: LGTM! Correct query action implementation.

The action properly structures the request with a nested configuration object containing the threshold and pagination settings. The required prompt parameter and scoped windowId are appropriate for this operation.

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!

@GTFalcao GTFalcao merged commit ea3708a into master Oct 4, 2025
10 checks passed
@GTFalcao GTFalcao deleted the 18630-airtop-new-components branch October 4, 2025 15:50
verhovsky added a commit to verhovsky/pipedream that referenced this pull request Oct 6, 2025
* upstream/master:
  Adding app scaffolding for stackby
  Airtop new components (PipedreamHQ#18637)
  Sinch - new components (PipedreamHQ#18635)
  Mintlify - new components (PipedreamHQ#18519)
  Linear App - updates and new components (PipedreamHQ#18606)
  Merging pull request PipedreamHQ#18622
  Adding app scaffolding for airtop
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.

[Components] airtop
2 participants