Skip to content

Eng 8702,eng 8703,eng 8704 #18072

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 33 commits into
base: master
Choose a base branch
from

Conversation

HarshGautam7101
Copy link

@HarshGautam7101 HarshGautam7101 commented Aug 15, 2025

WHY

Summary by CodeRabbit

  • New Features
    • Added multiple Token Metrics actions: prices, hourly/daily OHLCV, trading signals (hourly and daily), TM/Fundamental/Technology grades (current and historical), market metrics, moonshot tokens, AI reports, crypto investors, resistance/support, quantmetrics, scenario analysis, correlation, and indices (list, holdings, performance).
    • Introduced pagination with page support and sensible defaults.
  • Documentation
    • Rewrote README to API-first format with authentication, available actions, rate limits, and support details.
  • Refactor
    • Standardized API client, centralized filter definitions, and consistent success/error summaries.
  • Chores
    • Updated dependency versions and package metadata.

Copy link

vercel bot commented Aug 15, 2025

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

A member of the Team first needs to authorize it.

Copy link

vercel bot commented Aug 15, 2025

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

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
pipedream-docs-redirect-do-not-edit Ignored Ignored Aug 22, 2025 11:09am

Copy link
Contributor

coderabbitai bot commented Aug 15, 2025

Walkthrough

Adds centralized endpoint/constants and utilities, refactors the Token Metrics app to a generic API client with standardized error handling, and rewrites README. Introduces numerous new action modules and updates existing ones to use shared utilities (buildParams, generateFilterSummary) and new endpoint wrappers with consistent pagination and summaries.

Changes

Cohort / File(s) Summary
Documentation
components/token_metrics/README.md
Rewrote README to API-first doc style; added auth, actions, rate limits, and support sections; removed platform-specific examples.
Core client and shared utilities
components/token_metrics/token_metrics.app.mjs, components/token_metrics/common/constants.mjs, components/token_metrics/common/utils.mjs, components/token_metrics/package.json
Refactored app to generic API client with standardized headers, error handling, and endpoint wrappers; added centralized ENDPOINTS, FILTER_DEFINITIONS, ERROR_MESSAGES; introduced param and error utilities; updated package metadata and dependency.
Refactored existing actions
components/token_metrics/actions/get-market-metrics/get-market-metrics.mjs, components/token_metrics/actions/get-tokens/get-tokens.mjs
Migrated to shared ENDPOINTS/filters, buildParams, generateFilterSummary; switched to tokenMetrics client; added pagination and enhanced error/success summaries.
Grades actions (new)
.../actions/get-fundamental-grades/*, .../actions/get-technology-grades/*, .../actions/get-tm-grades/*
Added actions for current and historical Fundamental, Technology, and TM grades with filter props, pagination, standardized run flow, and error handling.
OHLCV actions (new)
.../actions/get-hourly-ohlcv/get-hourly-ohlcv.mjs, .../actions/get-daily-ohlcv/get-daily-ohlcv.mjs
Added hourly and daily OHLCV actions using shared utilities and endpoint wrappers with date filters and pagination.
Signals actions (new)
.../actions/get-trading-signals/get-trading-signals.mjs, .../actions/get-hourly-trading-signals/get-hourly-trading-signals.mjs
Added trading signals (daily/hourly) actions with extensive filters, pagination, summaries, and standardized error handling.
Indices actions (new)
.../actions/get-indices/get-indices.mjs, .../actions/get-indices-holdings/get-indices-holdings.mjs, .../actions/get-indices-performance/get-indices-performance.mjs
Added indices listing, holdings, and performance actions with relevant filters, pagination, and shared flow.
Market/data actions (new)
.../actions/get-price/get-price.mjs, .../actions/get-quantmetrics/get-quantmetrics.mjs, .../actions/get-top-market-cap-tokens/get-top-market-cap-tokens.mjs, .../actions/get-moonshot-tokens/get-moonshot-tokens.mjs, .../actions/get-ai-reports/get-ai-reports.mjs, .../actions/get-crypto-investors/get-crypto-investors.mjs, .../actions/get-resistance-support/get-resistance-support.mjs, .../actions/get-scenario-analysis/get-scenario-analysis.mjs, .../actions/get-correlation/get-correlation.mjs
Added multiple data retrieval actions (price, quantmetrics, top market cap, moonshot, AI reports, crypto investors, resistance/support, scenario analysis, correlation) with filter props, pagination, standardized summaries, and error handling.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Action
  participant Utils as Utils (buildParams / generateFilterSummary)
  participant App as TokenMetrics App
  participant API as Token Metrics API

  User->>Action: Invoke action with props
  Action->>Utils: buildParams(props, endpoint.filters)
  Action->>App: makeApiCall(endpoint, params)
  App->>API: GET /v2/<endpoint>?params
  API-->>App: Response / Error
  alt Success
    App-->>Action: Data
    Action->>Utils: generateFilterSummary(props, filters)
    Action-->>User: Return data (+ $summary)
  else Error
    App-->>Action: Error
    Action-->>User: Throw "Token Metrics API Error (status): message"
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–60 minutes

Poem

Hop-hop! I wired new routes to the moon,
With filters that sing a tidy tune.
Params in a row, errors kept tight,
Summaries sparkle, pagination’s light.
From grades to signals, the data streams bloom—
A rabbit’s refactor, swift as a zoom! 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@adolfo-pd adolfo-pd added the User submitted Submitted by a user label Aug 15, 2025
@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: 2

♻️ Duplicate comments (10)
components/token_metrics/actions/get-indices/get-indices.mjs (2)

58-69: Reuse the shared error handler introduced in utils

See earlier comment in get-resistance-support for the handleActionError helper and apply the same replacement here to remove duplicated error handling.


1-72: Confirm client/constant alignment for ‘indices’

Covered by the verification script provided in get-resistance-support.

components/token_metrics/actions/get-technology-grades/get-technology-grades.mjs (2)

66-77: Extract the repeated error handling

Adopt the handleActionError helper suggested in get-resistance-support to reduce duplication.


1-80: Confirm client/constant alignment for ‘technology grades’

Covered by the verification script provided in get-resistance-support.

components/token_metrics/actions/get-scenario-analysis/get-scenario-analysis.mjs (2)

62-73: Centralize error handling to a util

See earlier handleActionError suggestion and apply here.


1-76: Confirm client/constant alignment for ‘scenario analysis’

Covered by the verification script provided in get-resistance-support.

components/token_metrics/actions/get-top-market-cap-tokens/get-top-market-cap-tokens.mjs (2)

41-52: Adopt shared error handling helper

Use handleActionError as suggested in get-resistance-support for consistency and less duplication.


1-55: Confirm client/constant alignment for ‘top market cap tokens’

Covered by the verification script provided in get-resistance-support.

components/token_metrics/actions/get-quantmetrics/get-quantmetrics.mjs (2)

8-8: Verify hyphen vs underscore in component key

The component key uses an underscore (token_metrics-get-quantmetrics). Verify this is consistent with other Token Metrics components.


18-19: Remove "Click here" placeholder text from prop descriptions

Similar to the other actions, the descriptions contain non-functional "Click here" text that should be removed or replaced with actual documentation links.

-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
+      description: "Comma Separated Token IDs. Example: 3375,3306",
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC,ETH",
+      description: "Comma Separated Token Symbols. Example: BTC,ETH",
-      description: "Comma separated category name. Click here to access the list of categories. Example: layer-1,nft",
+      description: "Comma separated category name. Example: layer-1,nft",
-      description: "Comma separated exchange name. Click here to access the list of exchanges. Example: binance,gate",
+      description: "Comma separated exchange name. Example: binance,gate",

Also applies to: 22-23, 26-27, 30-31

🧹 Nitpick comments (74)
components/token_metrics/package.json (1)

3-3: Avoid version downgrade; confirm intended and adjust per SemVer

PR summary indicates a downgrade from 0.1.0 → 0.0.1. Unless you’re re-publishing under a new package or intentionally resetting, avoid going backwards per SemVer to prevent publish/install issues.

If this was unintentional, bump forward instead:

-  "version": "0.0.1",
+  "version": "0.1.1",
components/token_metrics/README.md (3)

26-29: Expand “Available Actions” to reflect the full action surface (or link to an index)

This section lists only three actions, but the PR adds many more (e.g., OHLCV, TM Grades, Technology Grades, Market Metrics, Trading Signals, Indices, etc.). Please either enumerate the new actions or add a link to an index so users can discover them easily.


17-23: Minor grammar/formatting: tighten the Authentication list

LanguageTool flagged this segment. Suggest rewording for clarity and proper list formatting.

- To use the Token Metrics API, you'll need:
-
- 1. A Token Metrics account
- 2. An API key from your Token Metrics dashboard
+ To use the Token Metrics API, you will need:
+
+ 1. A Token Metrics account
+ 2. An API key from your Token Metrics dashboard

32-32: Add a direct link to rate limit docs

Point users to the exact documentation page for rate limits (if available) to reduce ambiguity.

If you have the URL, add it here; otherwise, link to the main developer docs for Token Metrics.

components/token_metrics/common/constants.mjs (2)

183-190: Grammar: pluralize “scenario”

Minor copy fix in SCENARIO_ANALYSIS description.

-    description: "Get the price prediction based on different Crypto Market scenario",
+    description: "Get the price prediction based on different Crypto Market scenarios",

331-336: Consider adding bounds for top_k (optional)

If the API enforces sensible bounds (e.g., 1–500), reflect that here (either via description or validation) to give users immediate feedback.

   top_k: {
     type: "integer",
     label: "Top K",
-    description: "Specifies the number of top cryptocurrencies to retrieve, based on their market capitalization. Example: 100",
+    description: "Specifies the number of top cryptocurrencies to retrieve, based on their market capitalization (e.g., 1–500). Example: 100",
     optional: true,
   },
components/token_metrics/actions/get-tm-grades-historical/get-tm-grades-historical.mjs (4)

16-27: Avoid “Click here…” and point to a concrete lookup path

“Click here” isn’t actionable in the UI. Suggest referencing the “Get Tokens” action for lookups, or implement async options to let users search/select tokens directly.

   tokenId: {
     ...FILTER_DEFINITIONS.token_id,
-    description: "Click here to access the list of token IDs. Example: 3375",
+    description: "Token ID(s). Use the 'Get Tokens' action to look up IDs. Example: 3375",
   },
   tokenName: {
     ...FILTER_DEFINITIONS.token_name,
-    description: "Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names.",
+    description: "Crypto asset names (e.g., Bitcoin, Ethereum). Use the 'Get Tokens' action to look up names.",
   },
   symbol: {
     ...FILTER_DEFINITIONS.symbol,
-    description: "Click here to access the list of token symbols. Example: BTC,ETH",
+    description: "Symbols (e.g., BTC,ETH). Use the 'Get Tokens' action to look up symbols.",
   },

Optionally, I can help convert these to async options so users can search tokens inline.


28-35: Use neutral, realistic date examples

Examples in the future may confuse users and sample runs. Prefer recent historical dates.

   startDate: {
     ...FILTER_DEFINITIONS.start_date,
-    description: "Start Date accepts date as a string - YYYY-MM-DD format. Example: 2025-07-01",
+    description: "Start date (YYYY-MM-DD). Example: 2024-07-01",
   },
   endDate: {
     ...FILTER_DEFINITIONS.end_date,
-    description: "End Date accepts date as a string - YYYY-MM-DD format. Example: 2025-07-05",
+    description: "End date (YYYY-MM-DD). Example: 2024-07-05",
   },

54-63: Validate that at least one token selector is provided

The API likely needs at least one of tokenId, tokenName, or symbol. Add a guard to provide immediate feedback.

   async run({ $ }) {
-    // Build parameters using utility function
+    // Validate required filter presence
+    if (!this.tokenId && !this.tokenName && !this.symbol) {
+      throw new Error("Please provide at least one of: tokenId, tokenName, or symbol.");
+    }
+    // Build parameters using utility function
     const params = buildParams(this, endpoint.filters);

75-85: Preserve original error as cause

Wrap the original error to retain stack/context in logs.

-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
+      // Throw a more descriptive error with original cause
+      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`, { cause: error });
components/token_metrics/actions/get-hourly-ohlcv/get-hourly-ohlcv.mjs (4)

16-27: Replace “Click here…” with discoverable guidance or async options

Guide users to the “Get Tokens” action or implement async options for better UX.

   tokenId: {
     ...FILTER_DEFINITIONS.token_id,
-    description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
+    description: "Comma-separated token IDs. Use the 'Get Tokens' action to look up IDs. Example: 3375,3306",
   },
   symbol: {
     ...FILTER_DEFINITIONS.symbol,
-    description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC,ETH",
+    description: "Comma-separated symbols. Use the 'Get Tokens' action to look up symbols. Example: BTC,ETH",
   },
   tokenName: {
     ...FILTER_DEFINITIONS.token_name,
-    description: "Comma Separated Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names. Example: Bitcoin, Ethereum",
+    description: "Comma-separated crypto asset names (e.g., Bitcoin, Ethereum). Use the 'Get Tokens' action to look up names.",
   },

If you’d like, I can add async options that query the Tokens endpoint to populate these fields.


28-35: Clarify/enforce the “past 30 days” constraint

The description states the start date cannot be earlier than the past 30 days. Enforce this (and validate date order) to fail fast with helpful errors.

   startDate: {
     ...FILTER_DEFINITIONS.start_date,
-    description: "Start Date accepts date as a string - YYYY-MM-DD format. Note: The Start Date cannot be earlier than the past 30 days from the current date. Example: 2025-03-01",
+    description: "Start date (YYYY-MM-DD). Note: Cannot be earlier than the past 30 days from today. Example: 2024-03-01",
   },
   endDate: {
     ...FILTER_DEFINITIONS.end_date,
-    description: "End Date accepts date as a string - YYYY-MM-DD format. Example: 2025-03-20",
+    description: "End date (YYYY-MM-DD). Example: 2024-03-20",
   },

And add validation in run():

   async run({ $ }) {
-    // Build parameters using utility function
+    // Basic input validation
+    if (!this.tokenId && !this.symbol && !this.tokenName) {
+      throw new Error("Please provide at least one of: tokenId, symbol, or tokenName.");
+    }
+    if (this.startDate && this.endDate) {
+      const sd = new Date(this.startDate);
+      const ed = new Date(this.endDate);
+      if (Number.isNaN(sd.getTime()) || Number.isNaN(ed.getTime())) {
+        throw new Error("Invalid date format. Use YYYY-MM-DD.");
+      }
+      if (sd > ed) {
+        throw new Error("startDate must be earlier than or equal to endDate.");
+      }
+    }
+    if (this.startDate) {
+      const sd = new Date(this.startDate);
+      const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
+      if (Date.now() - sd.getTime() > THIRTY_DAYS_MS) {
+        throw new Error("startDate cannot be earlier than the past 30 days from today.");
+      }
+    }
+    // Build parameters using utility function
     const params = buildParams(this, endpoint.filters);

If the 30-day limit is not actually enforced server-side, remove that note and validation to avoid false negatives.


54-63: Add required filter presence check (at least one token selector)

Mirror TM Grades Historical: enforce presence of tokenId/symbol/tokenName for clearer UX.

   async run({ $ }) {
-    // Build parameters using utility function
+    // Ensure at least one token selector is present
+    if (!this.tokenId && !this.symbol && !this.tokenName) {
+      throw new Error("Please provide at least one of: tokenId, symbol, or tokenName.");
+    }
+    // Build parameters using utility function
     const params = buildParams(this, endpoint.filters);

75-85: Preserve original error as cause

Match the error handling improvement suggested in the TM Grades Historical action.

-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
+      // Throw a more descriptive error with original cause
+      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`, { cause: error });
components/token_metrics/actions/get-hourly-trading-signals/get-hourly-trading-signals.mjs (5)

16-20: Don’t force tokenId for an endpoint that supports “all tokens”

Docs/endpoint description indicate hourly trading signals can be fetched for all tokens. Making tokenId required prevents that use case.

Consider this change:

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
-      optional: false,
+      description: "Comma-separated Token IDs (e.g., 3375,3306)",
+      optional: true,
     },

Follow-up:

  • If the API actually requires token_id, keep it required and please confirm. Otherwise, making it optional restores the “all tokens” capability.
  • Also, avoid “Click here” without a link in descriptions across actions (replace with a concrete link or remove). I can help wire an async prop to search tokens if helpful.

53-56: Make $summary count robust to different response shapes

Some endpoints/clients return arrays under response.data.data or as the top-level response. Guard against those shapes to avoid reporting 0.

Apply:

-        const dataLength = response.data?.length || 0;
-        $.export("$summary", `Successfully retrieved hourly trading signals for ${dataLength} records${filterSummary}`);
+        const dataLength = Array.isArray(response?.data)
+          ? response.data.length
+          : Array.isArray(response?.data?.data)
+            ? response.data.data.length
+            : Array.isArray(response)
+              ? response.length
+              : 0;
+        $.export("$summary", `Successfully retrieved hourly trading signals for ${dataLength} records${filterSummary}`);

3-3: Leverage centralized error handling

You introduced handleApiError in utils. Import it here for consistent error mapping across actions.

Apply:

-import { buildParams, generateFilterSummary } from "../../common/utils.mjs";
+import { buildParams, generateFilterSummary, handleApiError } from "../../common/utils.mjs";

59-70: Delegate error mapping to handleApiError for consistency

Unifies error behavior and avoids duplicating logic in each action.

Apply:

-    } catch (error) {
-      // Enhanced error handling
-      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
-      const statusCode = error.response?.status;
-      
-      if ($ && $.export) {
-        $.export("$summary", `Error: ${errorMessage}`);
-      }
-      
-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
-    }
+    } catch (error) {
+      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
+      if ($?.export) {
+        $.export("$summary", `Error: ${errorMessage}`);
+      }
+      handleApiError(error);
+    }

21-37: Minor: avoid duplicating pagination defaults across actions

You’re setting limit/page defaults here but not in some other actions (e.g., get-price). Consider centralizing defaults at the app-level propDefinitions or documenting consistently across actions.

I can help standardize pagination descriptions/defaults repo-wide if you want.

components/token_metrics/actions/get-price/get-price.mjs (5)

16-19: Require tokenId for the Price endpoint

The price endpoint description suggests token IDs must be provided. Making tokenId required improves UX and avoids ambiguous API errors.

Apply:

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
+      description: "Comma-separated Token IDs (e.g., 3375,3306)",
+      optional: false,
     },

If the API supports “all tokens” without token_id for price, ignore this suggestion and keep it optional. Please confirm expected API behavior.


21-32: Align pagination props with other actions

Other actions add descriptions/defaults for limit/page. Keep consistent here for a uniform authoring experience.

Apply:

     limit: {
       propDefinition: [
         tokenMetrics,
         "limit",
       ],
+      description: "Limit the number of items in response. Defaults to 50",
+      default: 50,
     },
     page: {
       propDefinition: [
         tokenMetrics,
         "page",
       ],
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      default: 1,
     },

48-51: Make $summary count robust to different response shapes

Mirror the more resilient counting across actions.

Apply:

-        const dataLength = response.data?.length || 0;
-        $.export("$summary", `Successfully retrieved ${dataLength} price records${filterSummary}`);
+        const dataLength = Array.isArray(response?.data)
+          ? response.data.length
+          : Array.isArray(response?.data?.data)
+            ? response.data.data.length
+            : Array.isArray(response)
+              ? response.length
+              : 0;
+        $.export("$summary", `Successfully retrieved ${dataLength} price records${filterSummary}`);

3-3: Import handleApiError for consistent error mapping

Stay consistent with shared utilities.

Apply:

-import { buildParams, generateFilterSummary } from "../../common/utils.mjs";
+import { buildParams, generateFilterSummary, handleApiError } from "../../common/utils.mjs";

55-65: Use centralized error handling

Delegate detailed mapping to the shared utility and export a brief summary.

Apply:

-    } catch (error) {
-      // Enhanced error handling
-      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
-      const statusCode = error.response?.status;
-      
-      if ($ && $.export) {
-        $.export("$summary", `Error: ${errorMessage}`);
-      }
-      
-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
-    }
+    } catch (error) {
+      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
+      if ($?.export) {
+        $.export("$summary", `Error: ${errorMessage}`);
+      }
+      handleApiError(error);
+    }
components/token_metrics/common/utils.mjs (4)

10-13: Don’t drop falsy but valid values when building params

The current truthy check skips values like 0 or false. Prefer explicit undefined/null/empty string checks.

Apply:

-    if (props[propKey]) {
+    if (props[propKey] !== undefined && props[propKey] !== null && props[propKey] !== "") {
       params[key] = props[propKey];
     }

43-46: Ensure filter summary includes valid falsy values

Mirrors the buildParams fix so values like 0 aren’t dropped from the summary.

Apply:

-    if (value) {
+    if (value !== undefined && value !== null && value !== "") {
       const label = key.replace(/_/g, " ").replace(/\b\w/g, l => l.toUpperCase());
       appliedFilters.push(`${label}: ${value}`);
     }

75-79: Potential mismatch when generating the app prop name

Using [app.app] creates a prop like "token_metrics", but actions expect the prop name tokenMetrics (matching the import variable). This helper may produce unusable props unless the caller’s variable name equals app.app.

Recommended approach: accept the desired prop name as an argument and assign the app under that name.

-export function generateEndpointProps(app, endpoint) {
-  const props = {
-    [app.app]: app, // Add the app reference
-  };
+export function generateEndpointProps({ app, appPropName, endpoint }) {
+  const props = {
+    [appPropName]: app,
+  };
   // ...
-  props.limit = { propDefinition: [app, "limit"] };
-  props.page = { propDefinition: [app, "page"] };
+  props.limit = { propDefinition: [app, "limit"] };
+  props.page = { propDefinition: [app, "page"] };
   return props;
 }

If you plan to use this helper, I can refactor a couple of actions to consume it as an example.


52-71: Optional: expand error mapping (404, network, timeouts)

handleApiError is good. If useful, consider handling 404 separately (e.g., “No data found for the provided filters”) and network/timeout errors (axios distinguishes ECONNABORTED, etc.). Not a blocker.

components/token_metrics/actions/get-daily-ohlcv/get-daily-ohlcv.mjs (5)

16-35: Replace “Click here” placeholders in prop descriptions

There are multiple “Click here” references without actual links. Either add real links or remove the phrase to avoid user confusion.

Apply:

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375",
+      description: "Comma-separated Token IDs (e.g., 3375)",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC",
+      description: "Comma-separated Token Symbols (e.g., BTC)",
     },
     tokenName: {
       ...FILTER_DEFINITIONS.token_name,
-      description: "Comma Separated Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names. Example: Bitcoin",
+      description: "Comma-separated Crypto Asset Names (e.g., Bitcoin, Ethereum). Example: Bitcoin",
     },
     startDate: {
       ...FILTER_DEFINITIONS.start_date,
-      description: "Start Date accepts date as a string - YYYY-MM-DD format. Note: The Start Date cannot be earlier than the past 30 days from the current date. Example: 2025-01-01",
+      description: "Start Date (YYYY-MM-DD). Note: Must be within the past 30 days. Example: 2025-01-01",
     },
     endDate: {
       ...FILTER_DEFINITIONS.end_date,
-      description: "End Date accepts date as a string - YYYY-MM-DD format. Example: 2025-01-23",
+      description: "End Date (YYYY-MM-DD). Example: 2025-01-23",
     },

69-71: Make $summary count robust to response shape

Align with the more defensive pattern used in other suggestions.

Apply:

-        const dataLength = response.data?.length || 0;
+        const dataLength = Array.isArray(response?.data)
+          ? response.data.length
+          : Array.isArray(response?.data?.data)
+            ? response.data.data.length
+            : Array.isArray(response)
+              ? response.length
+              : 0;

3-3: Import handleApiError for unified error handling

Apply:

-import { buildParams, generateFilterSummary } from "../../common/utils.mjs";
+import { buildParams, generateFilterSummary, handleApiError } from "../../common/utils.mjs";

75-85: Use centralized error utility and keep $summary brief

Apply:

-    } catch (error) {
-      // Enhanced error handling
-      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
-      const statusCode = error.response?.status;
-      
-      if ($ && $.export) {
-        $.export("$summary", `Error: ${errorMessage}`);
-      }
-      
-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
-    }
+    } catch (error) {
+      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
+      if ($?.export) {
+        $.export("$summary", `Error: ${errorMessage}`);
+      }
+      handleApiError(error);
+    }

28-35: Optional: validate date format pre-flight

The UI hints at YYYY-MM-DD and 30-day bound, but there’s no validation. Consider a lightweight check to fail fast with a clear message, or move validation into the app client.

I can add a simple regex/date-range validation in run() to prevent avoidable API calls if you want.

components/token_metrics/actions/get-fundamental-grades-historical/get-fundamental-grades-historical.mjs (5)

16-27: Replace “Click here” placeholders with concrete text or links

Avoid dangling CTA text in prop descriptions.

Apply:

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Click here to access the list of token IDs. Example: 3375",
+      description: "Token IDs (e.g., 3375)",
     },
     tokenName: {
       ...FILTER_DEFINITIONS.token_name,
-      description: "Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names.",
+      description: "Crypto Asset Names (e.g., Bitcoin, Ethereum).",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Click here to access the list of token symbols. Example: BTC,ETH",
+      description: "Token Symbols (e.g., BTC,ETH)",
     },

55-57: Guard against empty filters if the API requires at least one identifier

If the endpoint expects at least one of tokenId/tokenName/symbol, add a quick check to help users.

Apply:

   async run({ $ }) {
-    // Build parameters using utility function
+    // Build parameters using utility function
+    if (!this.tokenId && !this.tokenName && !this.symbol) {
+      throw new Error("Please provide at least one of tokenId, tokenName, or symbol.");
+    }
     const params = buildParams(this, endpoint.filters);

If the API supports broad queries without filters, skip this suggestion. Please confirm expected behavior.


69-71: Make $summary count robust to response shape

Apply:

-        const dataLength = response.data?.length || 0;
+        const dataLength = Array.isArray(response?.data)
+          ? response.data.length
+          : Array.isArray(response?.data?.data)
+            ? response.data.data.length
+            : Array.isArray(response)
+              ? response.length
+              : 0;

3-3: Import handleApiError for unified error mapping

Apply:

-import { buildParams, generateFilterSummary } from "../../common/utils.mjs";
+import { buildParams, generateFilterSummary, handleApiError } from "../../common/utils.mjs";

75-85: Use shared error utility and export a brief summary

Apply:

-    } catch (error) {
-      // Enhanced error handling
-      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
-      const statusCode = error.response?.status;
-      
-      if ($ && $.export) {
-        $.export("$summary", `Error: ${errorMessage}`);
-      }
-      
-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
-    }
+    } catch (error) {
+      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
+      if ($?.export) {
+        $.export("$summary", `Error: ${errorMessage}`);
+      }
+      handleApiError(error);
+    }
components/token_metrics/actions/get-resistance-support/get-resistance-support.mjs (3)

16-23: Avoid “Click here” in descriptions and fix hyphenation

Inline “Click here” without a link degrades UX, and “Comma Separated” should be “Comma-separated.”

Apply this diff:

-    tokenId: {
-      ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
-    },
+    tokenId: {
+      ...FILTER_DEFINITIONS.token_id,
+      description: "Comma-separated token IDs. See Token Metrics docs for the list of supported token IDs. Example: 3375,3306",
+    },
-    symbol: {
-      ...FILTER_DEFINITIONS.symbol,
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC,ETH",
-    },
+    symbol: {
+      ...FILTER_DEFINITIONS.symbol,
+      description: "Comma-separated token symbols. See Token Metrics docs for the list of supported symbols. Example: BTC,ETH",
+    },

33-40: Clarify page description: it should be a positive 1-based integer

“Non-negative” conflicts with “1 indicating the beginning.” Use “positive (1-based).”

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control. Page should be a positive integer (1-based index). Default: 1",

62-73: DRY the error handling into a shared helper

The try/catch block is duplicated across actions. Centralize it in a utils function to reduce repetition and keep behavior consistent.

  • Add in components/token_metrics/common/utils.mjs:
export function handleActionError($, error, context = "Token Metrics API Error") {
  const errorMessage = error?.response?.data?.message || error?.message || "An error occurred";
  const statusCode = error?.response?.status ?? "Unknown";

  if ($ && $.export) {
    $.export("$summary", `Error: ${errorMessage}`);
  }
  // Preserve original error as cause if supported by the runtime
  // Node 16+: new Error(message, { cause: error })
  throw new Error(`${context} (${statusCode}): ${errorMessage}`);
}
  • Then replace this file’s catch block with:
-    } catch (error) {
-      // Enhanced error handling
-      const errorMessage = error.response?.data?.message || error.message || "An error occurred";
-      const statusCode = error.response?.status;
-      
-      if ($ && $.export) {
-        $.export("$summary", `Error: ${errorMessage}`);
-      }
-      
-      // Throw a more descriptive error
-      throw new Error(`Token Metrics API Error (${statusCode || 'Unknown'}): ${errorMessage}`);
-    }
+    } catch (error) {
+      return handleActionError($, error, "Token Metrics API Error");
+    }
components/token_metrics/actions/get-indices/get-indices.mjs (1)

29-36: Clarify page description: it should be a positive 1-based integer

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control. Page should be a positive integer (1-based index). Default: 1",
components/token_metrics/actions/get-technology-grades/get-technology-grades.mjs (2)

16-27: Avoid “Click here” and improve phrasing

-    tokenId: {
-      ...FILTER_DEFINITIONS.token_id,
-      description: "Click here to access the list of token IDs. Example: 3375",
-    },
+    tokenId: {
+      ...FILTER_DEFINITIONS.token_id,
+      description: "Token ID. See Token Metrics docs for the list of supported token IDs. Example: 3375",
+    },
-    tokenName: {
-      ...FILTER_DEFINITIONS.token_name,
-      description: "Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names.",
-    },
+    tokenName: {
+      ...FILTER_DEFINITIONS.token_name,
+      description: "Crypto asset names (e.g., Bitcoin, Ethereum). See Token Metrics docs for the list of supported names.",
+    },
-    symbol: {
-      ...FILTER_DEFINITIONS.symbol,
-      description: "Click here to access the list of token symbols. Example: BTC,ETH",
-    },
+    symbol: {
+      ...FILTER_DEFINITIONS.symbol,
+      description: "Token symbols. See Token Metrics docs for the list of supported symbols. Example: BTC,ETH",
+    },

37-44: Clarify page description to avoid ambiguity

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control. Page should be a positive integer (1-based index). Default: 1",
components/token_metrics/actions/get-scenario-analysis/get-scenario-analysis.mjs (2)

16-23: Avoid “Click here” and fix hyphenation

-    tokenId: {
-      ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
-    },
+    tokenId: {
+      ...FILTER_DEFINITIONS.token_id,
+      description: "Comma-separated token IDs. See Token Metrics docs for the list of supported token IDs. Example: 3375,3306",
+    },
-    symbol: {
-      ...FILTER_DEFINITIONS.symbol,
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC,ETH",
-    },
+    symbol: {
+      ...FILTER_DEFINITIONS.symbol,
+      description: "Comma-separated token symbols. See Token Metrics docs for the list of supported symbols. Example: BTC,ETH",
+    },

33-40: Clarify page description to 1-based positive integer

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control. Page should be a positive integer (1-based index). Default: 1",
components/token_metrics/actions/get-top-market-cap-tokens/get-top-market-cap-tokens.mjs (1)

16-20: Consider enforcing topK > 0 at the schema level

To preempt invalid inputs, consider setting a minimum constraint in FILTER_DEFINITIONS.top_k (or validating here).

You can update components/token_metrics/common/constants.mjs:

top_k: {
  type: "integer",
  label: "Top K",
  description: "Specifies the number of top cryptocurrencies to retrieve, based on their market capitalization. Example: 100",
  optional: true,
  min: 1, // enforce positive integers
}
components/token_metrics/actions/get-moonshot-tokens/get-moonshot-tokens.mjs (3)

15-19: Remove reference to “screenshot” in code comments

Comment mentions “screenshot,” which is not actionable and may go stale. Keep comments tied to API docs or endpoint metadata only.

Apply this diff to tighten the comment:

-    // Filter props based on endpoint configuration and screenshot
+    // Filter props based on endpoint configuration and API documentation

34-35: Clarify page description (positive integer)

“Non-negative integer” suggests page 0 is valid, but the text says 1 is the start. Clarify to “positive integer” to avoid ambiguity.

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a positive integer, where 1 indicates the first page. Defaults to 1",

52-56: Consider robust count derivation for $summary

APIs sometimes return objects with metadata instead of an array. If that’s the case here, response.data?.length may be 0. Consider using a more robust count (e.g., check for arrays, or use an API-provided total if available).

If the API returns a non-array with a total count, consider:

-        const dataLength = response.data?.length || 0;
+        const dataLength = Array.isArray(response.data)
+          ? response.data.length
+          : (Number(response.data?.total) || Number(response.meta?.count) || 0);
components/token_metrics/actions/get-correlation/get-correlation.mjs (2)

16-31: Replace “Click here” with actionable or neutral copy; standardize capitalization

“Click here” without a link degrades UX. Also, standardize “Comma-separated” usage.

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 3375,3306",
+      description: "Comma-separated token IDs. Example: 3375,3306",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: BTC,ETH",
+      description: "Comma-separated token symbols. Example: BTC,ETH",
     },
     category: {
       ...FILTER_DEFINITIONS.category,
-      description: "Comma separated category name. Click here to access the list of categories. Example: layer-1,nft",
+      description: "Comma-separated category name. Example: layer-1,nft",
     },
     exchange: {
       ...FILTER_DEFINITIONS.exchange,
-      description: "Comma separated exchange name. Click here to access the list of exchanges. Example: gate,binance",
+      description: "Comma-separated exchange name. Example: binance,gate",
     },

46-47: Clarify page description (positive integer)

Same minor wording nit as other files.

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a positive integer, where 1 indicates the first page. Defaults to 1",
components/token_metrics/actions/get-crypto-investors/get-crypto-investors.mjs (2)

29-30: Clarify page description (positive integer)

Minor wording cleanup for consistency across actions.

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a positive integer, where 1 indicates the first page. Defaults to 1",

44-50: Optional: avoid computing filter summary for endpoints with no filters

Since endpoint.filters is empty, generateFilterSummary always returns an empty string. You can skip it to avoid extra work, though the cost is minimal.

-      // Generate summary using utility function
-      const filterSummary = generateFilterSummary(this, endpoint.filters);
-      
       // Use $ context for export
       if ($ && $.export) {
         const dataLength = response.data?.length || 0;
-        $.export("$summary", `Successfully retrieved ${dataLength} crypto investors${filterSummary}`);
+        $.export("$summary", `Successfully retrieved ${dataLength} crypto investors`);
       }
components/token_metrics/actions/get-fundamental-grades/get-fundamental-grades.mjs (2)

16-27: Replace “Click here” and standardize phrasing

Improve prop descriptions by removing “Click here” and using consistent casing and hyphenation.

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Click here to access the list of token IDs. Example: 3375",
+      description: "Token IDs. Example: 3375",
     },
     tokenName: {
       ...FILTER_DEFINITIONS.token_name,
-      description: "Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names.",
+      description: "Crypto asset names (e.g., Bitcoin, Ethereum).",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Click here to access the list of token symbols. Example: BTC,ETH",
+      description: "Token symbols. Example: BTC,ETH",
     },

42-43: Clarify page description (positive integer)

Same pagination copy nit.

-      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a positive integer, where 1 indicates the first page. Defaults to 1",
components/token_metrics/actions/get-trading-signals/get-trading-signals.mjs (4)

27-38: Add default and description for pagination props to match other actions

Limit/page props lack descriptions and defaults, unlike other actions in this PR. Add them for consistency and better UX.

     limit: {
       propDefinition: [
         tokenMetrics,
         "limit",
       ],
+      description: "Limit the number of items in response. Defaults to 50",
+      default: 50,
     },
     page: {
       propDefinition: [
         tokenMetrics,
         "page",
       ],
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a positive integer, where 1 indicates the first page. Defaults to 1",
+      default: 1,
     },

54-56: Optional: include a result count in the success summary

Most new actions surface a count in $summary. Consider doing the same for consistency.

-      if ($ && $.export) {
-        $.export("$summary", `Successfully retrieved trading signals${filterSummary}`);
-      }
+      if ($ && $.export) {
+        const dataLength = response.data?.length || 0;
+        $.export("$summary", `Successfully retrieved ${dataLength} trading signals${filterSummary}`);
+      }

16-25: Optional: basic date validation can improve DX

Given startDate/endDate accept YYYY-MM-DD, consider minimal validation and a friendly error message pre-request to catch obvious mistakes early.

If you want, I can provide a small helper to validate date format and ordering and wire it before the API call.


1-73: Reduce duplication via a small shared runner utility

Multiple actions share the same flow: build params -> call client -> format $summary -> rethrow with status. Consider extracting a helper like runEndpointAction({ $, endpoint, methodName, props, successSummaryFormatter }) to cut repetition and centralize error handling.

I can sketch a reusable helper if you’d like to move in that direction.

components/token_metrics/actions/get-tokens/get-tokens.mjs (3)

23-34: Set defaults and descriptions for pagination props to match other actions

Other actions in this package define defaults (limit=50, page=1) and include helpful descriptions. Align this action for consistency and better UX.

Apply this diff:

     limit: {
       propDefinition: [
         tokenMetrics,
         "limit",
       ],
+      description: "Limit the number of items in response. Defaults to 50",
+      default: 50,
     },
     page: {
       propDefinition: [
         tokenMetrics,
         "page",
       ],
+      description: "Enables pagination and data retrieval control by skipping a specified number of items before fetching data. Page should be a non-negative integer, with 1 indicating the beginning of the dataset. Defaults to 1",
+      default: 1,
     },

46-54: Include result count in success summary for parity with other actions

Other actions export the number of items retrieved; this one doesn’t. Small UX improvement for consistency.

Apply this diff:

-      // Generate summary using utility function
+      // Generate summary using utility function
       const filterSummary = generateFilterSummary(this, endpoint.filters);
       
       // Use $ context for export
       if ($ && $.export) {
-        $.export("$summary", `Successfully retrieved tokens list${filterSummary}`);
+        const dataLength = response.data?.length || 0;
+        $.export("$summary", `Successfully retrieved ${dataLength} tokens${filterSummary}`);
       }

36-66: Optional: Offer built-in auto-pagination toggle

Consider adding a boolean prop (e.g., paginateAll) to fetch all pages automatically, applying the shared limit/page props under the hood. This aligns with the Pipedream guideline to handle pagination where feasible.

If helpful, I can draft a minimal loop using the existing client and merge all pages into one array response.

components/token_metrics/actions/get-tm-grades/get-tm-grades.mjs (2)

15-15: Tighten the comment

Remove reference to “screenshot” to keep code comments source-agnostic.

-    // Filter props based on endpoint configuration and screenshot
+    // Filter props based on endpoint configuration

16-27: Replace “Click here” text with direct doc links

The descriptions reference “Click here” without an actual link, which isn’t actionable in many UIs. Link to the Tokens endpoint so users can discover IDs/names/symbols.

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Click here to access the list of token IDs. Example: 3375",
+      description: "Comma-separated Token IDs. Example: 3375. See the Tokens endpoint for the full list: https://developers.tokenmetrics.com/reference/tokens",
     },
     tokenName: {
       ...FILTER_DEFINITIONS.token_name,
-      description: "Crypto Asset Names (e.g., Bitcoin, Ethereum). Click here to access the list of token names.",
+      description: "Crypto asset names (e.g., Bitcoin, Ethereum). See the Tokens endpoint for the full list: https://developers.tokenmetrics.com/reference/tokens",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Click here to access the list of token symbols. Example: BTC,ETH",
+      description: "Comma-separated token symbols. Example: BTC,ETH. See the Tokens endpoint for the full list: https://developers.tokenmetrics.com/reference/tokens",
     },
components/token_metrics/actions/get-indices-performance/get-indices-performance.mjs (2)

61-63: Include index ID in the success summary

Improves observability of which index was queried when reviewing step output.

-        const dataLength = response.data?.length || 0;
-        $.export("$summary", `Successfully retrieved historical performance data for index with ${dataLength} data points${filterSummary}`);
+        const dataLength = response.data?.length || 0;
+        $.export("$summary", `Successfully retrieved historical performance data for index ${this.id} with ${dataLength} data points${filterSummary}`);

14-27: Optional: Validate date inputs

If feasible, lightly validate YYYY-MM-DD format before calling the API to fail fast with actionable errors.

Example:

const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
if (this.startDate && !DATE_RE.test(this.startDate)) {
  throw new Error("startDate must be in YYYY-MM-DD format");
}
if (this.endDate && !DATE_RE.test(this.endDate)) {
  throw new Error("endDate must be in YYYY-MM-DD format");
}
components/token_metrics/actions/get-market-metrics/get-market-metrics.mjs (1)

16-23: Optional: Add basic date format validation

As with other date-based actions, consider a lightweight YYYY-MM-DD check to provide earlier, clearer errors to users before hitting the API.

Example:

const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
if (this.startDate && !DATE_RE.test(this.startDate)) throw new Error("startDate must be in YYYY-MM-DD format");
if (this.endDate && !DATE_RE.test(this.endDate)) throw new Error("endDate must be in YYYY-MM-DD format");
components/token_metrics/actions/get-ai-reports/get-ai-reports.mjs (3)

17-23: Replace “Click here” text with direct doc links and consistent phrasing

Use direct links and consistent “Comma-separated …” phrasing, mirroring other actions.

     tokenId: {
       ...FILTER_DEFINITIONS.token_id,
-      description: "Comma Separated Token IDs. Click here to access the list of token IDs. Example: 37493,3484",
+      description: "Comma-separated Token IDs. Example: 37493,3484. See the Tokens endpoint for the full list: https://developers.tokenmetrics.com/reference/tokens",
     },
     symbol: {
       ...FILTER_DEFINITIONS.symbol,
-      description: "Comma Separated Token Symbols. Click here to access the list of token symbols. Example: APX,PAAL",
+      description: "Comma-separated token symbols. Example: APX,PAAL. See the Tokens endpoint for the full list: https://developers.tokenmetrics.com/reference/tokens",
     },

56-59: Fix success summary wording (“reports” vs “tokens”)

The endpoint returns reports; the summary currently says “tokens.”

-        const dataLength = response.data?.length || 0;
-        $.export("$summary", `Successfully retrieved AI reports for ${dataLength} tokens${filterSummary}`);
+        const dataLength = response.data?.length || 0;
+        $.export("$summary", `Successfully retrieved ${dataLength} AI reports${filterSummary}`);

42-73: Optional: Offer auto-pagination to fetch all reports

Consider adding a paginateAll boolean prop and loop through pages until exhaustion to comply with “handle pagination” guidance.

I can sketch a minimal implementation using your existing limit/page props that aggregates all pages before returning.

components/token_metrics/actions/get-technology-grades-historical/get-technology-grades-historical.mjs (1)

30-31: Fix date format examples to use past dates

The date examples show "2025-07-01" and "2025-07-05" which are future dates. For historical data retrieval, it would be more appropriate to use past dates in the examples.

-      description: "Start Date accepts date as a string - YYYY-MM-DD format. Example: 2025-07-01",
+      description: "Start Date accepts date as a string - YYYY-MM-DD format. Example: 2024-01-01",
-      description: "End Date accepts date as a string - YYYY-MM-DD format. Example: 2025-07-05",
+      description: "End Date accepts date as a string - YYYY-MM-DD format. Example: 2024-01-31",

Also applies to: 34-35

components/token_metrics/token_metrics.app.mjs (2)

64-303: Consider generating endpoint methods programmatically

The comment on line 63 suggests these methods could be generated automatically. Given the repetitive nature and the existence of ENDPOINTS constant, consider implementing a factory pattern to reduce code duplication.

Would you like me to help create a factory function that generates these endpoint methods dynamically from the ENDPOINTS constant? This would reduce the file size and make it easier to add new endpoints in the future.


51-62: Consider adding request/response logging for debugging

For better debugging capabilities, consider adding optional logging of requests and responses when a debug flag is set.

     async makeApiCall({
       $ = this,
       endpoint,
       params = {},
+      debug = false,
     }) {
+      if (debug) {
+        console.log(`Making API call to ${endpoint}`, params);
+      }
       return this._makeRequest({
         $,
         path: endpoint,
         method: "GET",
         params,
       });
     },

Copy link
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

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

Hi there, thanks for your contribution! I see you've added a lot of components, that is greatly appreciated.

I've commented on a few general changes that need to be made across most or all of the components, before this is ready to be merged. Let me know if you need any assistance

@GTFalcao GTFalcao moved this from Ready for PR Review to Changes Required in Component (Source and Action) Backlog Aug 21, 2025
HarshGautam7101 and others added 3 commits August 22, 2025 16:28
- Add markdown formatting to all example values with backticks
- Highlight date formats (`YYYY-MM-DD`) in prop descriptions
- Add `min: 1` validation to all page props across 19 action files
- Remove verbose pagination descriptions in favor of built-in validation
- Standardize prop definitions using `propDefinitions` from app file
- Convert comma-separated string props to `string[]` type for better UX
- Remove redundant `if ($ && $.export)` checks from all actions
- Remove custom `try/catch` blocks to leverage Pipedream's native error handling
- Clean up `handleApiError` utility function and related imports
- Fix prop descriptions to use proper options instead of text descriptions
- Update README.md to be more concise and professional per feedback

This refactor improves code maintainability, user experience, and follows
Pipedream component best practices for validation, error handling, and
documentation formatting.
- Add markdown formatting to all example values with backticks
- Highlight date formats (`YYYY-MM-DD`) in prop descriptions
- Add `min: 1` validation to all page props across 19 action files
- Remove verbose pagination descriptions in favor of built-in validation
- Standardize prop definitions using `propDefinitions` from app file
- Convert comma-separated string props to `string[]` type for better UX
- Remove redundant `if ($ && $.export)` checks from all actions
- Remove custom `try/catch` blocks to leverage Pipedream's native error handling
- Clean up `handleApiError` utility function and related imports
- Fix prop descriptions to use proper options instead of text descriptions
- Update README.md to be more concise and professional per feedback

This refactor improves code maintainability, user experience, and follows
Pipedream component best practices for validation, error handling, and
documentation formatting.
@HarshGautam7101
Copy link
Author

HarshGautam7101 commented Aug 22, 2025

@GTFalcao I’ve implemented all the required changes, it should be good now. Can you please recheck?

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
Development

Successfully merging this pull request may close these issues.

4 participants