Skip to content

[Components] plaid - new components #16586

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

jcortes
Copy link
Collaborator

@jcortes jcortes commented May 7, 2025

WHY

Resolves #15144

Summary by CodeRabbit

  • New Features

    • Introduced multiple Plaid integration actions, including creating access tokens, creating sandbox public tokens, fetching real-time balances, and retrieving transactions.
    • Added webhook event sources for instant notifications on new accounts, sync updates, and general Plaid events.
    • Enhanced Plaid app integration with expanded configuration, improved error handling, and comprehensive API support.
    • Provided utility modules for constants, sandbox institutions, and helper functions.
    • Included test event data for webhook event simulations.
  • Chores

    • Updated package dependencies and version for improved compatibility.

@jcortes jcortes self-assigned this May 7, 2025
Copy link

vercel bot commented May 7, 2025

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

3 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Ignored (Inspect) May 7, 2025 10:28pm
pipedream-docs ⬜️ Ignored (Inspect) May 7, 2025 10:28pm
pipedream-docs-redirect-do-not-edit ⬜️ Ignored (Inspect) May 7, 2025 10:28pm

Copy link
Contributor

coderabbitai bot commented May 7, 2025

Walkthrough

This update introduces a comprehensive Plaid integration, adding new Plaid API actions, webhook sources, utility modules, and constants. The Plaid app component is refactored to use the official SDK, with robust prop definitions and methods for API interaction, error handling, and pagination. Webhook sources and test events are implemented for real-time event handling.

Changes

Files / Grouped Files Change Summary
components/plaid/plaid.app.mjs Refactored to integrate the official Plaid SDK, added detailed propDefinitions, and implemented methods for Plaid API endpoints, error handling, and pagination.
components/plaid/actions/create-access-token/create-access-token.mjs
components/plaid/actions/create-sandbox-public-token/create-sandbox-public-token.mjs
components/plaid/actions/get-real-time-balance/get-real-time-balance.mjs
components/plaid/actions/get-transactions/get-transactions.mjs
Added four new action modules: exchange public_token for access_token, create sandbox public_token, get real-time balance, and get transactions. Each defines input properties and calls Plaid API methods via the app component.
components/plaid/common/constants.mjs
components/plaid/common/sandbox-institutions.mjs
components/plaid/common/utils.mjs
Introduced new modules for constants (limits), sandbox institution definitions, and utility functions for iteration and nested property access.
components/plaid/sources/common/events.mjs Added a module exporting webhook type and code constants for use in event handling.
components/plaid/sources/common/webhook.mjs Added a generic Plaid webhook source component with activation, event processing, and customizable hooks for metadata and event relevance.
components/plaid/sources/new-accounts-available-instant/new-accounts-available-instant.mjs
components/plaid/sources/new-accounts-available-instant/test-event.mjs
New webhook source and test event for "New Accounts Available" events, using shared webhook logic and event constants.
components/plaid/sources/new-event-instant/new-event-instant.mjs
components/plaid/sources/new-event-instant/test-event.mjs
New webhook source and test event for generic Plaid item/status change events, with custom event metadata generation.
components/plaid/sources/sync-updates-available-instant/sync-updates-available-instant.mjs
components/plaid/sources/sync-updates-available-instant/test-event.mjs
New webhook source and test event for "Sync Updates Available" events, including event relevance filtering and metadata generation.
components/plaid/package.json Updated Plaid component version to 0.7.0, upgraded @pipedream/platform dependency, and added Plaid SDK dependency.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Action
    participant PlaidApp
    participant PlaidAPI

    User->>Action: Trigger action (e.g., get-transactions)
    Action->>PlaidApp: Call method (e.g., getTransactions)
    PlaidApp->>PlaidAPI: Make API request
    PlaidAPI-->>PlaidApp: Return API response
    PlaidApp-->>Action: Return processed data
    Action-->>User: Output result
Loading
sequenceDiagram
    participant PlaidAPI
    participant WebhookSource
    participant System

    PlaidAPI-->>WebhookSource: Send webhook event
    WebhookSource->>WebhookSource: Check event relevance
    WebhookSource->>System: Emit event with metadata
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement webhook sources: new-accounts-available-instant, new-event-instant, sync-updates-available-instant (#15144)
Implement actions: create-access-token, create-sandbox-public-token, get-real-time-balance, get-transactions (#15144)

Suggested labels

ai-assisted

Poem

A Plaid of code, new threads entwine,
Webhooks and actions, all align.
Tokens exchanged, balances found,
Transactions fetched, events abound!
With every hop, this rabbit cheers—
For Plaid is woven through our gears.
🐇✨

✨ 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.

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
components/plaid/sources/new-accounts-available-instant/new-accounts-available-instant.mjs (1)

24-30: Same deduplication concern as other source

See the note about using event_id instead of Date.now() for deterministic IDs. Applying the same change here keeps the sources consistent.

🧹 Nitpick comments (18)
components/plaid/common/constants.mjs (1)

4-7: Consider Named Exports for Tree-Shaking
Using a default export object may hinder tree-shaking. Consider switching to named exports:

-export default {
-  DEFAULT_LIMIT,
-  DEFAULT_MAX,
-};
+export { DEFAULT_LIMIT, DEFAULT_MAX };
components/plaid/common/sandbox-institutions.mjs (3)

1-3: Add File-Level Documentation
This file defines a large static map of sandbox institutions. Adding a JSDoc header or inline comment explaining its purpose and usage will improve developer onboarding and maintainability.


2-21: Group Institutions by Category
The non-OAuth banks (INS_109508–INS_109512) would benefit from a comment block separating them from other categories. For example:

+// ── Non-OAuth sandbox institutions ────────────────────────────────────────
 INS_109508: { … },
 INS_109509: { … },
 …

22-70: Add Section Comments for Clarity
Institutions span Canadian, UK, OAuth, and degraded/unsupported cases. Adding comments before each logical group will make future updates easier to navigate.

components/plaid/sources/common/events.mjs (3)

1-5: Freeze WEBHOOK_TYPE for Immutability
Protect these constants from unintended mutation by applying Object.freeze. E.g.:

-const WEBHOOK_TYPE = { … };
+const WEBHOOK_TYPE = Object.freeze({ … });

7-26: Freeze WEBHOOK_CODE and Nested Objects
Similarly, lock down the nested WEBHOOK_CODE object and its sub-objects:

-const WEBHOOK_CODE = { … };
+const WEBHOOK_CODE = Object.freeze({ … });

28-31: Consider Named Exports over Default Export
Using named exports (export { WEBHOOK_TYPE, WEBHOOK_CODE };) improves tree-shaking and makes individual constants easier to import directly.

components/plaid/package.json (1)

16-17: Verify Dependency Versions and Compatibility
Ensure the newly added plaid@^33.0.0 SDK and upgraded @pipedream/platform@^3.0.3 are compatible and available. You can run:

npm view plaid@^33.0.0 version
npm view @pipedream/platform@^3.0.3 version
components/plaid/sources/new-accounts-available-instant/test-event.mjs (1)

8-8: Remove stray line number.

There appears to be a stray character/number "8" at the end of the file that should be removed.

  "webhook_type": "ITEM"
};
-8
components/plaid/common/utils.mjs (1)

1-17: Consider adding JSDoc comments to utility functions.

Adding JSDoc comments would improve code maintainability by providing clear documentation about parameters, return values, and usage examples.

+/**
+ * Collects all items from an async iterable into an array
+ * @param {AsyncIterable} iterations - The async iterable to collect from
+ * @returns {Promise<Array>} Array containing all items from the iterable
+ */
async function iterate(iterations) {
  const items = [];
  for await (const item of iterations) {
    items.push(item);
  }
  return items;
}

+/**
+ * Safely accesses nested properties in an object using a dot-separated path
+ * @param {Object} obj - The object to access properties from
+ * @param {string} propertyString - Dot-separated path to the property (e.g., "user.address.zipCode")
+ * @returns {*} The value at the specified path or undefined if the path doesn't exist
+ */
function getNestedProperty(obj, propertyString) {
  const properties = propertyString.split(".");
  return properties.reduce((prev, curr) => prev?.[curr], obj);
}
components/plaid/actions/get-transactions/get-transactions.mjs (3)

68-80: Consider simplifying conditional options handling.

The conditional logic for building the options object is well-structured, but could be more concise.

Consider using object property shorthand when the property name matches the variable name:

- if (includeOriginalDescription !== undefined) {
-   options.include_original_description = includeOriginalDescription;
- }
+ if (includeOriginalDescription !== undefined) {
+   options.include_original_description = includeOriginalDescription;
+ }

While the implementation is correct, this is just a stylistic suggestion.


88-91: Simplify conditional spread for options.

The conditional spread operator with logical AND could be simplified for better readability.

- ...(Object.keys(options).length > 0 && {
-   options,
- }),
+ ...(Object.keys(options).length ? { options } : {}),

This alternative is more explicit about the intent and avoids potential confusion with the logical AND operator.


95-96: Consider handling empty transactions array more directly.

The current implementation handles the possibility of transactions being undefined, which may not be necessary if the paginate method always returns an array.

- const transactionCount = transactions?.length || 0;
+ const transactionCount = transactions.length;

If there's a possibility that transactions could be undefined or null from the paginate method, then the current implementation is correct. Otherwise, this simplification would be cleaner.

components/plaid/sources/common/webhook.mjs (3)

61-62: Remove console.log statement in production code.

Console logging the createLinkToken response may not be appropriate for production code.

- console.log("createLinkToken response", response);

Consider using a debug log level if you need to retain this for troubleshooting, or remove it entirely for production code.


85-87: Uncomment or remove HTTP response handling.

There are commented-out lines related to HTTP response handling. These should either be uncommented or removed to maintain clean code.

Either uncomment and use:

http.respond({
  status: 200,
});

Or remove the commented code entirely if it's not needed.


71-73: Document the intention of isEventRelevant method.

The isEventRelevant method always returns true, which means all webhook events will be processed by default. This is likely intended to be overridden by extending components.

Add a comment to clarify the intention:

isEventRelevant() {
+  // Base implementation accepts all events; override in extending components to filter events
  return true;
},
components/plaid/sources/new-event-instant/new-event-instant.mjs (1)

14-21: Consider using a more unique event ID.

The current ID generation uses a timestamp (Date.now()), which could potentially cause collisions if multiple events are processed at the exact same millisecond.

Consider incorporating the webhook type and code into the ID for better uniqueness:

generateMeta(resource) {
  const ts = Date.now();
  return {
-   id: ts,
+   id: `${resource.webhook_type}.${resource.webhook_code}-${ts}`,
    summary: `New Event: ${resource.webhook_type}.${resource.webhook_code}`,
    ts,
  };
},

This would ensure that even if two different events arrive at the same millisecond, they would still have unique IDs.

components/plaid/sources/sync-updates-available-instant/sync-updates-available-instant.mjs (1)

20-27: Use webhook-provided identifiers for deterministic deduping

generateMeta relies on Date.now() for both id and ts. When two webhooks arrive in the same millisecond the IDs will collide, causing dropped events in “unique” dedupe mode.
Plaid webhook payloads include an event_id; prefer that when available, falling back to the timestamp only if not present:

generateMeta(resource) {
-  const ts = Date.now();
-  return {
-    id: ts,
-    summary: `New Event: ${resource.webhook_type}.${resource.webhook_code}`,
-    ts,
-  };
+  const ts = Date.now();
+  return {
+    id: resource.event_id ?? ts,
+    summary: `New Event: ${resource.webhook_type}.${resource.webhook_code}`,
+    ts,
+  };
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b36acd5 and d876bb2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • components/plaid/actions/create-access-token/create-access-token.mjs (1 hunks)
  • components/plaid/actions/create-sandbox-public-token/create-sandbox-public-token.mjs (1 hunks)
  • components/plaid/actions/get-real-time-balance/get-real-time-balance.mjs (1 hunks)
  • components/plaid/actions/get-transactions/get-transactions.mjs (1 hunks)
  • components/plaid/common/constants.mjs (1 hunks)
  • components/plaid/common/sandbox-institutions.mjs (1 hunks)
  • components/plaid/common/utils.mjs (1 hunks)
  • components/plaid/package.json (2 hunks)
  • components/plaid/plaid.app.mjs (1 hunks)
  • components/plaid/sources/common/events.mjs (1 hunks)
  • components/plaid/sources/common/webhook.mjs (1 hunks)
  • components/plaid/sources/new-accounts-available-instant/new-accounts-available-instant.mjs (1 hunks)
  • components/plaid/sources/new-accounts-available-instant/test-event.mjs (1 hunks)
  • components/plaid/sources/new-event-instant/new-event-instant.mjs (1 hunks)
  • components/plaid/sources/new-event-instant/test-event.mjs (1 hunks)
  • components/plaid/sources/sync-updates-available-instant/sync-updates-available-instant.mjs (1 hunks)
  • components/plaid/sources/sync-updates-available-instant/test-event.mjs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (17)
components/plaid/common/constants.mjs (1)

1-2: Constants Naming and Purpose Clear
The DEFAULT_LIMIT and DEFAULT_MAX constants follow standard uppercase naming and appropriately centralize pagination settings.

components/plaid/package.json (1)

3-3: Version Bump Looks Good
Updating to 0.7.0 correctly reflects the addition of new features; this follows semantic versioning for a minor release.

components/plaid/sources/sync-updates-available-instant/test-event.mjs (1)

1-8: Test Fixture Matches Event Schema
The structure (environment, flags, item_id, webhook_code, webhook_type) aligns with the webhook event constants. This test event will correctly simulate a "SYNC_UPDATES_AVAILABLE" transactions webhook.

components/plaid/sources/new-event-instant/test-event.mjs (1)

1-8: Test event looks good and follows Plaid webhook format.

The exported object correctly models a Plaid webhook event with the appropriate fields needed for testing the "New Event (Instant)" source. The payload includes all required fields for a webhook update acknowledgment event.

components/plaid/sources/new-accounts-available-instant/test-event.mjs (1)

1-7: Test event structure looks good for NEW_ACCOUNTS_AVAILABLE webhook.

The payload correctly structures a Plaid webhook event for new accounts becoming available, with all the necessary fields.

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

1-7: Good implementation of async iteration utility.

The iterate function correctly collects all items from an async iterable into an array, which is useful for handling paginated responses from the Plaid API.


9-12: Effective utility for safely accessing nested properties.

The getNestedProperty function uses optional chaining to safely access nested object properties, which is ideal for handling complex nested response structures from Plaid.

components/plaid/actions/get-real-time-balance/get-real-time-balance.mjs (2)

9-29: Props are well-defined with appropriate descriptions.

The props include the required access token and optional account IDs with clear labels and descriptions. The dynamic account ID options based on the access token provide a good user experience.


4-8: Version suggests this is a new component.

The version "0.0.1" indicates this is the first release of this component. Ensure adequate testing has been performed, especially with the Plaid sandbox environment.

Have you tested this component with real Plaid sandbox credentials to verify it works as expected?

components/plaid/actions/create-access-token/create-access-token.mjs (1)

1-32: Good implementation of the Plaid token exchange action.

This action properly implements the exchange of a public token for an access token using the Plaid API. The structure follows Pipedream's conventions with clear property definitions and a straightforward implementation.

components/plaid/actions/get-transactions/get-transactions.mjs (1)

1-100: Overall well-structured transaction retrieval action.

The action correctly implements transaction retrieval with proper pagination support and parameter handling. The code is well-organized with appropriate property definitions and validation rules.

components/plaid/sources/common/webhook.mjs (2)

54-58: Review hardcoded products array vs. configurable products props.

The webhook is configured with hardcoded products ("transactions" and "assets"), but the component also accepts product-related props that aren't being used in the Link token creation.

Consider whether the hardcoded products should be replaced with the configurable products from props:

- products: [
-   "transactions",
-   "assets",
- ],
+ products: this.products,

If the intention is to always use these specific products regardless of the props, consider removing the product-related props or adding a comment explaining why they're not used in this context.


1-93: Solid foundation for Plaid webhook event handling.

Overall, this common webhook base component provides a good foundation for handling Plaid webhook events. It correctly sets up the webhook endpoint, defines methods that can be overridden by extending components, and provides a consistent structure for event processing.

components/plaid/sources/new-event-instant/new-event-instant.mjs (1)

1-24: Clean implementation of webhook event source.

This is a well-implemented specific webhook source that correctly extends the common webhook component. It provides appropriate metadata generation for its events and includes a sample event for testing.

components/plaid/actions/create-sandbox-public-token/create-sandbox-public-token.mjs (1)

86-95: Pass a single payload object to createSandboxPublicToken

makeRequest expects args to be the first positional argument in the SDK call, but spreading the payload (lines 86-95) directly into the wrapper call also spreads it into the options bag understood by makeRequest.
A safer pattern is:

-const response = await app.createSandboxPublicToken({
-  institution_id: institutionId,
-  initial_products: initialProducts,
-  ...(Object.keys(options).length > 0 && { options }),
-  ...(userToken && { user_token: userToken }),
-});
+const payload = {
+  institution_id: institutionId,
+  initial_products: initialProducts,
+  ...(Object.keys(options).length && { options }),
+  ...(userToken && { user_token: userToken }),
+};
+
+const response = await app.createSandboxPublicToken(payload);

This guarantees that the wrapper receives exactly the structure it forward-calls with, safeguarding against accidental argument shadowing.

components/plaid/sources/new-accounts-available-instant/new-accounts-available-instant.mjs (1)

18-23: Guard against undefined constants

If events.WEBHOOK_CODE[webhookType] is missing (e.g. future Plaid change or typo), accessing .NEW_ACCOUNTS_AVAILABLE will throw.
Defensively test before dereferencing:

const webhookType = events.WEBHOOK_TYPE.ITEM;
-const webhookCode = events.WEBHOOK_CODE[webhookType].NEW_ACCOUNTS_AVAILABLE;
+const webhookCode =
+  events.WEBHOOK_CODE?.[webhookType]?.NEW_ACCOUNTS_AVAILABLE;

Return false early when the constant is absent to avoid runtime exceptions.

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

217-260: Pagination loop can spin indefinitely if the API ignores offset

offset is incremented blindly (line 259) without checking whether the next page actually yielded different resources.
If Plaid ever ignores offset for a particular endpoint, the loop will never exit.
Store the last batch’s first resource ID or use the SDK’s next_cursor (for /transactions/sync-style endpoints) when available.

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] plaid
2 participants