Skip to content

Conversation

sergio-eliot-rodriguez
Copy link
Collaborator

@sergio-eliot-rodriguez sergio-eliot-rodriguez commented Oct 16, 2025

Implemented TicketSauce components expressed by user specified in #18366 (which this PR resolves), namely actions
List of Events
Event Details
Orders
Order Details
Ticket Checkin IDs
and source
New Event
which was specified by the app developer via email.

Summary by CodeRabbit

  • New Features
    • Added Ticketsauce actions to list and retrieve events, orders, ticket check‑in IDs, and event/order details.
    • Added a "New Event" source that emits new Ticketsauce events and supports incremental polling.
    • Added dynamic, real‑time selection fields for choosing events and orders in the UI.
  • Chores
    • Bumped Ticketsauce component version and added platform dependency.
  • Tests
    • Added a test event fixture for source testing.

Copy link

vercel bot commented Oct 16, 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 Oct 17, 2025 9:25pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@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 bot commented Oct 16, 2025

Walkthrough

Adds five new Ticketsauce actions, a polling "New Event" source with test data, extends the Ticketsauce app with propDefinitions and HTTP/API helper methods, and updates package.json to v0.1.0 with a dependency on @pipedream/platform.

Changes

Cohort / File(s) Summary
Action Modules
components/ticketsauce/actions/get-events/get-events.mjs, components/ticketsauce/actions/get-event-details/get-event-details.mjs, components/ticketsauce/actions/get-orders/get-orders.mjs, components/ticketsauce/actions/get-order-details/get-order-details.mjs, components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs
Added new action exports. Each defines metadata, props (including ticketsauce, optional partnerId/organizationId, and dynamic propDefinitions where applicable), and run() implementations that construct API params and call corresponding Ticketsauce app methods (listEvents, getEventDetails, listOrders, getOrderDetails, getTicketCheckinIds).
Event Source & Test Data
components/ticketsauce/sources/new-event/new-event.mjs, components/ticketsauce/sources/new-event/test-event.mjs
Added a new polling source that lists events, filters by persisted lastCreated, emits new events (deploy seeds up to 25), and persists last-processed timestamp; includes a static test-event fixture.
Core App Module
components/ticketsauce/ticketsauce.app.mjs
Extended public surface: added propDefinitions (eventId, orderId) with async option builders, added _makeRequest HTTP helper, and API methods listEvents, getEventDetails, listOrders, getOrderDetails, getTicketCheckinIds that use _makeRequest.
Package Configuration
components/ticketsauce/package.json
Bumped version from 0.0.1 to 0.1.0 and added dependencies including "@pipedream/platform": "^3.1.0".

Sequence Diagram(s)

sequenceDiagram
    participant Deploy
    participant Timer
    participant Source as "New Event Source"
    participant DB as "DB"
    participant App as "Ticketsauce App"
    participant API as "Ticketsauce API"
    participant Emit as "Emitter"

    Deploy->>Source: hooks.deploy()
    Source->>DB: _getLastCreated()
    DB-->>Source: lastCreated
    Source->>App: listEvents(partnerId?, organizationId?, params)
    App->>API: GET /events (via _makeRequest)
    API-->>App: events[]
    App-->>Source: events[]
    Source->>Source: filter created_after lastCreated, sort asc, limit 25
    Source->>DB: _setLastCreated(newLastCreated)
    loop for each new event
        Source->>Source: generateMeta(event)
        Source->>Emit: $emit(event, meta)
    end

    Note over Timer: periodic run
    Timer->>Source: run()
    Source->>App: listEvents()
    App->>API: GET /events
    API-->>App: events[]
    App-->>Source: events[]
    Source->>Source: filter & emit new events
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble logs and fetch new shows,
Five actions bloom where Ticketsauce flows.
I remember time, emit what’s new,
Seed some tests, and call APIs too.
— a joyful rabbit, hopping through code 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the required template structure. The repository template specifies a required "## WHY" section to explain the reasoning and motivation behind the changes, but the provided description omits this heading and instead provides a summary of what components are being implemented. While the description references issue #18366 and lists the specific components added, it fails to explain the "why"—the motivation, business rationale, or context for implementing these particular components as specified in the template requirement. Add a "## WHY" section to the description explaining the motivation and context for implementing these Ticketsauce components. This section should clarify why these specific actions and sources are needed, what user need they address, and how they support the Ticketsauce integration objectives. The current description reads more as a "what" summary than a "why" explanation, which is what the template requires.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "new ticketsauce actions and source" is directly related to the main changes in this pull request, which adds five new Ticketsauce actions (List Events, Event Details, Orders, Order Details, Ticket Checkin IDs) and one new source (New Event). The title is specific about the technology and type of changes being introduced, making it clear to someone scanning history that new components are being added to the Ticketsauce integration. While it doesn't enumerate every component, this level of detail is appropriate for a PR title.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

🧹 Nitpick comments (1)
components/ticketsauce/sources/new-event/new-event.mjs (1)

79-88: Simplify the lastCreated update logic.

The current implementation searches through all events to find the most recent created date, but since newEvents contains only events created after lastCreated, the most recent event in newEvents already represents the new maximum.

Apply this diff to simplify:

       // Update last created date if we have new events
       if (newEvents.length > 0) {
-        // Find the most recent created date
-        const mostRecentEvent = events.reduce((latest, current) => 
-          Date.parse(current.Event.created) > Date.parse(latest.Event.created) 
-            ? current 
-            : latest
-        );
+        // Get the most recent event from newEvents (last in sorted array)
+        const mostRecentEvent = newEvents[newEvents.length - 1];
         this._setLastCreated(mostRecentEvent.Event.created);
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe7f45d and 04e8c2a.

📒 Files selected for processing (9)
  • components/ticketsauce/actions/get-event-details/get-event-details.mjs (1 hunks)
  • components/ticketsauce/actions/get-events/get-events.mjs (1 hunks)
  • components/ticketsauce/actions/get-order-details/get-order-details.mjs (1 hunks)
  • components/ticketsauce/actions/get-orders/get-orders.mjs (1 hunks)
  • components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1 hunks)
  • components/ticketsauce/package.json (2 hunks)
  • components/ticketsauce/sources/new-event/new-event.mjs (1 hunks)
  • components/ticketsauce/sources/new-event/test-event.mjs (1 hunks)
  • components/ticketsauce/ticketsauce.app.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (2)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (83-98)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (131-147)
components/ticketsauce/sources/new-event/new-event.mjs (1)
components/ticketsauce/ticketsauce.app.mjs (1)
  • events (12-15)
components/ticketsauce/actions/get-events/get-events.mjs (2)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (131-147)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (83-98)
components/ticketsauce/actions/get-orders/get-orders.mjs (3)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (83-98)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (48-51)
components/ticketsauce/ticketsauce.app.mjs (5)
components/ticketsauce/sources/new-event/new-event.mjs (1)
  • events (50-58)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (83-98)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (131-147)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (48-51)
🪛 GitHub Actions: Components Checks
components/ticketsauce/package.json

[error] 1-1: pnpm install failed due to frozen-lockfile. The lockfile is not up to date with package.json. Run 'pnpm install' without --frozen-lockfile or update the lockfile. Specifiers in the lockfile ({}) don't match specs in package.json ({"@pipedream/platform":"^3.1.0"}).

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

[error] 1-1: pnpm install failed due to frozen-lockfile: pnpm-lock.yaml is not up to date with package.json. Specifiers in the lockfile don't match specs in package.json ("@pipedream/platform":"^3.1.0"). Run 'pnpm install --no-frozen-lockfile' or update the lockfile.


[error] 1-1: Dependency specifier mismatch detected in lockfile vs package.json for @pipedream/platform (^3.1.0).

⏰ 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). (1)
  • GitHub Check: pnpm publish
🔇 Additional comments (3)
components/ticketsauce/actions/get-order-details/get-order-details.mjs (1)

1-48: LGTM!

The action structure is well-organized with appropriate propDefinitions for dynamic option loading, and the implementation correctly retrieves order details.

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

1-47: LGTM!

The test fixture provides appropriate sample data for the New Event source.

components/ticketsauce/sources/new-event/new-event.mjs (1)

1-105: Verify whether the Ticketsauce /events endpoint supports or requires pagination.

The concern is valid: listEvents is called without pagination parameters in new-event.mjs, get-events.mjs, and propDefinitions, while other API calls in the same integration (e.g., listOrders) explicitly use per_page and page. If the /events endpoint returns paginated results, only the first page will be fetched, causing events beyond the first page to be missed.

However, this appears to be a consistent pattern across the integration, suggesting either the endpoint returns all results by default or there's a shared gap. Consult the Ticketsauce API documentation or test the endpoint to confirm whether pagination is needed. If required, add pagination parameters (e.g., per_page and pagination loop logic) to the listEvents calls.

Regarding deduplication: the dedupe: "unique" strategy combined with event id and lastCreated tracking should correctly prevent duplicates across runs, assuming event IDs are unique.

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 (7)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (2)

38-50: Use integer props + bounds for pagination params; avoid sending strings.

Define perPage/page as integer with min/max, and send numbers to the API.

@@
-    perPage: {
-      type: "string",
+    perPage: {
+      type: "integer",
       label: "Per Page",
       description: "How many results to retrieve (per page). Max 5000.",
       optional: true,
+      default: 100,
+      min: 1,
+      max: 5000,
     },
@@
-    page: {
-      type: "string",
+    page: {
+      type: "integer",
       label: "Page",
       description: "Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60.",
       optional: true,
-      default: "1",
+      default: 1,
+      min: 1,
     },
@@
-    const params = {
-      per_page: this.perPage,
-      page: this.page,
-    };
+    const params = {
+      per_page: this.perPage,
+      page: this.page,
+    };

Also applies to: 52-56


52-61: Optionally add “paginate all” support to meet the pagination guideline.

Add a boolean paginateAll to fetch all pages in one run; otherwise keep current single-page behavior. As per component checklist.

@@
   props: {
@@
+    paginateAll: {
+      type: "boolean",
+      label: "Paginate All",
+      description: "If true, fetches all pages of check-in IDs.",
+      optional: true,
+      default: false,
+    },
@@
   async run() {
-    const params = {
+    const params = {
       per_page: this.perPage,
       page: this.page,
     };
 
-    return this.ticketsauce.getTicketCheckinIds({
-      eventId: this.eventId,
-      params,
-    });
+    if (!this.paginateAll) {
+      return this.ticketsauce.getTicketCheckinIds({ eventId: this.eventId, params });
+    }
+    const all = [];
+    let page = params.page || 1;
+    while (true) {
+      const res = await this.ticketsauce.getTicketCheckinIds({ eventId: this.eventId, params: { ...params, page } });
+      const items = Array.isArray(res) ? res : (res?.data ?? []);
+      all.push(...items);
+      if (!items.length || (params.per_page && items.length < params.per_page)) break;
+      page += 1;
+    }
+    return all;
   },

Please confirm Ticketsauce’s “Ticket Check-in IDs” endpoint supports per_page/page and whether 5000 is the documented max. If different, we’ll adjust min/max and loop stop conditions.

components/ticketsauce/actions/get-events/get-events.mjs (2)

59-69: Set explicit defaults to match the descriptions.

Descriptions say default sort is date/asc, but props have no defaults. Add them for consistency.

   sortBy: {
     type: "string",
     label: "Sort By",
     description: "Which field to sort by. By default ('date'), will sort events by their start date. Other options are 'name' (event name) or 'city' (the city where the event is located).",
     optional: true,
+    default: "date",
     options: [
       "date",
       "name",
       "city",
     ],
   },
@@
   sortDir: {
     type: "string",
     label: "Sort Direction",
     description: "Which direction you'd like to sort - either ascending ('asc' - the default) or descending ('desc').",
     optional: true,
+    default: "asc",
     options: [
       "asc",
       "desc",
     ],
   },

Also applies to: 70-79


87-103: Avoid sending undefined query keys.

Clean the params object before calling the app method to prevent undefined from being sent.

   async run() {
-    const params = {
+    const paramsRaw = {
       partner_id: this.partnerId,
       organization_id: this.organizationId,
       start_after: this.startAfter,
       end_before: this.endBefore,
       active_only: this.activeOnly,
       privacy_type: this.privacyType,
       sort_by: this.sortBy,
       sort_dir: this.sortDir,
       include_performers: this.includePerformers,
     };
-
-    return this.ticketsauce.listEvents({
-      params,
-    });
+    const params = Object.fromEntries(Object.entries(paramsRaw).filter(([, v]) => v !== undefined));
+    return this.ticketsauce.listEvents({ params });
   },
components/ticketsauce/actions/get-orders/get-orders.mjs (3)

38-51: Use integer props + bounds for perPage/page.

Ensure numeric types and enforce API limits (max 500 as described).

   perPage: {
-      type: "string",
+      type: "integer",
       label: "Per Page",
       description: "How many results to retrieve (per page). Max 500.",
       optional: true,
-      default: "100",
+      default: 100,
+      min: 1,
+      max: 500,
     },
   page: {
-      type: "string",
+      type: "integer",
       label: "Page",
       description: "Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60.",
       optional: true,
-      default: "1",
+      default: 1,
+      min: 1,
     },

136-156: Strip undefined query params before request.

Prevents sending dead/undefined keys; keeps requests clean.

-    const params = {
+    const paramsRaw = {
       per_page: this.perPage,
       page: this.page,
       q: this.q,
       return_questionnaires: this.returnQuestionnaires,
       return_tickets: this.returnTickets,
       return_line_item_fees: this.returnLineItemFees,
       ordered_after: this.orderedAfter,
       ordered_before: this.orderedBefore,
       modified_after: this.modifiedAfter,
       modified_before: this.modifiedBefore,
       sort_by: this.sortBy,
       sort_dir: this.sortDir,
       total_above: this.totalAbove,
       total_below: this.totalBelow,
     };
+    const params = Object.fromEntries(Object.entries(paramsRaw).filter(([, v]) => v !== undefined));
 
     return this.ticketsauce.listOrders({
       eventId: this.eventId,
       params,
     });

38-75: Optional: add paginateAll to fetch all pages in one action.

Meets the “handle pagination” checklist; keeps current behavior default.

@@
   props: {
@@
+    paginateAll: {
+      type: "boolean",
+      label: "Paginate All",
+      description: "If true, fetches all pages of orders.",
+      optional: true,
+      default: false,
+    },
@@
   async run() {
-    const paramsRaw = {
+    const paramsRaw = {
       per_page: this.perPage,
       page: this.page,
@@
-    const params = Object.fromEntries(Object.entries(paramsRaw).filter(([, v]) => v !== undefined));
-
-    return this.ticketsauce.listOrders({
-      eventId: this.eventId,
-      params,
-    });
+    const params = Object.fromEntries(Object.entries(paramsRaw).filter(([, v]) => v !== undefined));
+    if (!this.paginateAll) {
+      return this.ticketsauce.listOrders({ eventId: this.eventId, params });
+    }
+    const all = [];
+    let page = params.page || 1;
+    while (true) {
+      const res = await this.ticketsauce.listOrders({ eventId: this.eventId, params: { ...params, page } });
+      const items = Array.isArray(res) ? res : (res?.data ?? []);
+      all.push(...items);
+      if (!items.length || (params.per_page && items.length < params.per_page)) break;
+      page += 1;
+    }
+    return all;
   },

Confirm Ticketsauce’s “Orders” endpoint page size limit (doc says 500 here). If different, update max.

Also applies to: 100-121, 135-157

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04e8c2a and 94760df.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • components/ticketsauce/actions/get-event-details/get-event-details.mjs (1 hunks)
  • components/ticketsauce/actions/get-events/get-events.mjs (1 hunks)
  • components/ticketsauce/actions/get-order-details/get-order-details.mjs (1 hunks)
  • components/ticketsauce/actions/get-orders/get-orders.mjs (1 hunks)
  • components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/ticketsauce/actions/get-order-details/get-order-details.mjs
  • components/ticketsauce/actions/get-event-details/get-event-details.mjs
🧰 Additional context used
🧬 Code graph analysis (3)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (2)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (88-98)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (136-151)
components/ticketsauce/actions/get-events/get-events.mjs (3)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (58-61)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (136-151)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-orders/get-orders.mjs (3)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (58-61)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (88-98)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (53-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (1)
components/ticketsauce/actions/get-events/get-events.mjs (1)

14-27: Confirm whether the Events API supports pagination; add props if so.

If the endpoint accepts per_page/page, expose them (integer with min/max) and forward to params to align with the pagination checklist. If not, ignore.

Also applies to: 87-98

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 (1)
components/ticketsauce/sources/new-event/new-event.mjs (1)

78-84: Consider clarifying the cursor update logic.

The logic correctly updates lastCreated to the most recent event from the full events array (not just newEvents), which properly advances the cursor. However, the condition if (newEvents.length > 0) might be clearer as a comment explaining that we only update the cursor when we've emitted new events.

Consider adding a clarifying comment:

-      // Update last created date if we have new events
       if (newEvents.length > 0) {
+        // Update cursor to the most recent event from all fetched events
         // Find the most recent created date
         const mostRecentEvent = events.reduce((latest, current) =>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94760df and 46e2542.

📒 Files selected for processing (3)
  • components/ticketsauce/package.json (2 hunks)
  • components/ticketsauce/sources/new-event/new-event.mjs (1 hunks)
  • components/ticketsauce/ticketsauce.app.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
components/ticketsauce/sources/new-event/new-event.mjs (1)
components/ticketsauce/ticketsauce.app.mjs (1)
  • events (14-17)
components/ticketsauce/ticketsauce.app.mjs (5)
components/ticketsauce/sources/new-event/new-event.mjs (1)
  • events (50-58)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (58-61)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (88-98)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)
  • params (136-151)
⏰ 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: Lint Code Base
  • GitHub Check: pnpm publish
🔇 Additional comments (7)
components/ticketsauce/package.json (1)

1-18: LGTM!

The version bump and dependency addition are appropriate for the new components being introduced. The past lockfile issue has been addressed.

components/ticketsauce/sources/new-event/new-event.mjs (3)

4-32: LGTM!

The source metadata, props, and timer configuration are well-structured. The 1-hour interval appropriately matches the API cache behavior mentioned in the comment.


34-46: LGTM!

The cursor management and metadata generation helpers follow standard patterns and integrate well with the db service.


93-100: LGTM!

The deploy hook with a 25-event limit and the unlimited run method follow the standard polling source pattern.

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

31-71: LGTM!

The orderId propDefinition correctly implements pagination with context tracking and appropriate handling of empty results. The label format provides helpful order identification.


74-85: LGTM!

The _makeRequest helper follows the standard pattern for API integration, properly handling authentication and parameter merging.


86-134: LGTM!

The API helper methods are well-structured and correctly delegate to _makeRequest. Each method appropriately handles its parameters and constructs the correct API paths.

Comment on lines +7 to +30
eventId: {
type: "string",
label: "Event",
description: "Select an event",
async options({
partnerId, organizationId,
}) {
const events = await this.listEvents({
partnerId,
organizationId,
});

if (!events?.length) {
return [];
}

const options = events.map((eventData) => ({
label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`,
value: eventData.Event.id,
}));

return options;
},
},
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 17, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Implement pagination for event options.

The eventId propDefinition fetches all events without pagination, which could fail to load all available events if the dataset is large. Per the component guidelines: "Handle pagination for API requests to ensure all data/events are processed."

Apply a similar pagination pattern to the orderId propDefinition (lines 31-71):

       async options({
-        partnerId, organizationId,
+        partnerId, organizationId, prevContext,
       }) {
         const events = await this.listEvents({
           partnerId,
           organizationId,
+          params: {
+            per_page: 100,
+            page: prevContext?.page || 0,
+          },
         });
 
         if (!events?.length) {
-          return [];
+          return prevContext?.page > 0
+            ? {
+              options: [],
+              context: {},
+            }
+            : [];
         }
 
         const options = events.map((eventData) => ({
           label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`,
           value: eventData.Event.id,
         }));
 
-        return options;
+        return {
+          options,
+          context: {
+            page: (prevContext?.page || 0) + 1,
+          },
+        };
       },

Note: Verify that the Ticketsauce API supports per_page and page parameters for the /events endpoint.


🏁 Script executed:

#!/bin/bash
# Verify if the Ticketsauce API documentation mentions pagination parameters for the events endpoint

rg -i "per_page|page|pagination" --type md -C 3

Length of output: 191188


🏁 Script executed:

#!/bin/bash
# Examine the ticketsauce component to verify pagination implementation

# First, find the ticketsauce component file
find . -name "ticketsauce.app.mjs" -o -name "ticketsauce*.mjs" | head -20

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Get the ticketsauce component content to verify pagination claims
cat components/ticketsauce/ticketsauce.app.mjs | head -150

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check if there's API documentation or examples for ticketsauce
find components/ticketsauce -type f \( -name "*.md" -o -name "*.js" -o -name "*.mjs" \) | head -20

Length of output: 490


🏁 Script executed:

#!/bin/bash
# Look for any common API integration files to understand pagination patterns
rg -l "per_page|prevContext" --type mjs components/ | head -10

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for the listEvents method specifically in ticketsauce
rg -A 20 "listEvents\s*\(" components/ticketsauce/

Length of output: 4957


🏁 Script executed:

#!/bin/bash
# Search for orderId propDefinition in ticketsauce to compare implementation
rg -A 30 "orderId.*propDefinition\|orderId\s*:\s*\{" components/ticketsauce/

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the complete file structure
wc -l components/ticketsauce/ticketsauce.app.mjs && head -200 components/ticketsauce/ticketsauce.app.mjs

Length of output: 3076


🏁 Script executed:

#!/bin/bash
# Look for any Ticketsauce-specific documentation or README
find components/ticketsauce -name "README*" -o -name "*.md" | xargs cat 2>/dev/null || echo "No README found"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for pagination patterns in the codebase to see if prevContext is the standard
rg -B 5 -A 15 'prevContext.*page' components/ --type mjs | head -80

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Specifically check orderId implementation in ticketsauce
ast-grep --pattern 'orderId.*:.*{
  $$$
  async options($_) {
    $$$
  }
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get the full ticketsauce.app.mjs to understand the complete context
cat components/ticketsauce/ticketsauce.app.mjs

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Search for API method to understand pagination support
rg -B 5 -A 20 "_makeRequest|getEventDetails|listEvents" components/ticketsauce/ticketsauce.app.mjs | head -100

Length of output: 2031


🏁 Script executed:

#!/bin/bash
# Check GitHub or external documentation reference
rg -i "ticketsauce.*api|api.*ticketsauce" components/ticketsauce/ --type md

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at the prop definitions more carefully
rg -B 2 -A 50 "propDefinitions\s*=" components/ticketsauce/ticketsauce.app.mjs | head -150

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Final check: examine lines 7-30 and 31-71 as mentioned in review
sed -n '1,150p' components/ticketsauce/ticketsauce.app.mjs

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check if orderId even exists and how pagination is implemented there
grep -n "orderId" components/ticketsauce/ticketsauce.app.mjs | head -20

Length of output: 101


🏁 Script executed:

#!/bin/bash
# Look for the entire propDefinitions section
sed -n '/propDefinitions/,/^  [a-zA-Z]/p' components/ticketsauce/ticketsauce.app.mjs | head -200

Length of output: 1581


🏁 Script executed:

#!/bin/bash
# Search broadly for pagination patterns in prop definitions
rg -B 3 -A 20 "async options.*partnerId.*organizationId" components/ --type mjs | head -100

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check if the Ticketsauce API endpoint documentation is mentioned anywhere
rg -i "event.*list|list.*event" components/ticketsauce/ --type md --type mjs | grep -i "per_page\|page\|limit\|offset"

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Get just the file with line numbers to see exact structure
cat -n components/ticketsauce/ticketsauce.app.mjs | head -180

Length of output: 3981


🏁 Script executed:

#!/bin/bash
# Check all files in ticketsauce directory
ls -la components/ticketsauce/

Length of output: 379


🏁 Script executed:

#!/bin/bash
# Get comprehensive view of the app.mjs file
head -300 components/ticketsauce/ticketsauce.app.mjs | tail -150

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Search for the actual line numbers mentioned (7-30 and 31-71)
sed -n '1,80p' components/ticketsauce/ticketsauce.app.mjs | cat -n

Length of output: 2463


🏁 Script executed:

#!/bin/bash
# Final attempt to get the complete structure to understand pagination
python3 << 'EOF'
import json
try:
    with open('components/ticketsauce/ticketsauce.app.mjs', 'r') as f:
        content = f.read()
    # Print first 1000 characters with line numbers
    for i, line in enumerate(content.split('\n')[:120], 1):
        print(f"{i:3d}: {line}")
except Exception as e:
    print(f"Error: {e}")
EOF

Length of output: 3304


🏁 Script executed:

#!/bin/bash
# Look at the entire component to understand its structure
wc -l components/ticketsauce/ticketsauce.app.mjs
cat components/ticketsauce/ticketsauce.app.mjs | head -250

Length of output: 3076


🏁 Script executed:

#!/bin/bash
# Search for pagination in this specific component more thoroughly
rg "page|pagination|per_page|prevContext|offset|limit" components/ticketsauce/ -A 2 -B 2

Length of output: 10360


🏁 Script executed:

#!/bin/bash
# Check if the component has actions or methods that show how the API works
find components/ticketsauce -type f -name "*.mjs" -o -name "*.js" | xargs ls -la

Length of output: 882


🏁 Script executed:

#!/bin/bash
# Look at test files or examples if they exist
find components/ticketsauce -name "*test*" -o -name "*example*" -o -name "*action*" | xargs cat 2>/dev/null | head -200

Length of output: 1485


🏁 Script executed:

#!/bin/bash
# Get the actual entire file now
cat components/ticketsauce/ticketsauce.app.mjs

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Simple check: does the file exist and get its size
stat components/ticketsauce/ticketsauce.app.mjs 2>&1 && echo "---" && wc -l components/ticketsauce/ticketsauce.app.mjs

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Use python to read and display the file safely
python3 -c "
with open('components/ticketsauce/ticketsauce.app.mjs', 'r') as f:
    lines = f.readlines()
    for i, line in enumerate(lines[:200], 1):
        print(f'{i:4d}: {line}', end='')
"

Length of output: 3845


🏁 Script executed:

#!/bin/bash
# Double-check the component exists and examine its key sections
file components/ticketsauce/ticketsauce.app.mjs && echo "---FILE EXISTS---" && head -250 components/ticketsauce/ticketsauce.app.mjs

Length of output: 42


🏁 Script executed:

#!/bin/bash
# If the direct approach fails, try finding similar components with working pagination
find components -name "*.app.mjs" -type f | xargs grep -l "prevContext" | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 30 "async options" {}'

Length of output: 12766


🏁 Script executed:

#!/bin/bash
# Look at how other components implement pagination to validate the pattern
rg -A 40 "prevContext\?\s*\." components --type mjs | head -150

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check if orderid exists in the file at all
grep -c "orderId\|eventId" components/ticketsauce/ticketsauce.app.mjs || echo "Pattern not found"

Length of output: 2


🏁 Script executed:

#!/bin/bash
# Final comprehensive check
python3 << 'EOF'
with open('components/ticketsauce/ticketsauce.app.mjs', 'r') as f:
    content = f.read()
    
# Show file length
print(f"Total lines: {len(content.split(chr(10)))}")
print("\n--- FIRST 300 LINES ---\n")
lines = content.split('\n')
for i, line in enumerate(lines[:300], 1):
    print(f"{i:4}: {line}")
EOF

Length of output: 3895


🏁 Script executed:

#!/bin/bash
# Check Ticketsauce API docs if available in repo
find . -name "*ticketsauce*" -type f | head -20

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Last resort: use head with explicit count
head -n 400 components/ticketsauce/ticketsauce.app.mjs

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check all mjs files in the component directory
find components/ticketsauce -name "*.mjs" | xargs wc -l

Length of output: 550


🏁 Script executed:

#!/bin/bash
# Display directory structure
ls -R components/ticketsauce/

Length of output: 649


🏁 Script executed:

#!/bin/bash
# Most direct approach - read the file
cat components/ticketsauce/ticketsauce.app.mjs 2>&1 | head -400

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check if orderId or eventId exists and list line numbers
grep -n "orderId\|eventId\|listEvents\|getOrderDetails\|getEventDetails" components/ticketsauce/ticketsauce.app.mjs | head -30

Length of output: 521


🏁 Script executed:

#!/bin/bash
# Get the section between propDefinitions and the methods
awk '/propDefinitions/,/^  [a-zA-Z_].*\(/ {print NR": "$0}' components/ticketsauce/ticketsauce.app.mjs | head -200

Length of output: 3486


🏁 Script executed:

#!/bin/bash
# Simple line extraction
awk 'NR>=1 && NR<=250 {print NR": "$0}' components/ticketsauce/ticketsauce.app.mjs

Length of output: 3601


🏁 Script executed:

#!/bin/bash
# Try to find the propDefinitions section more carefully
sed -n '1,200p' components/ticketsauce/ticketsauce.app.mjs | nl

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Use a Python approach to handle the file robustly
python3 << 'PYTHON'
try:
    with open('components/ticketsauce/ticketsauce.app.mjs') as f:
        for i, line in enumerate(f, 1):
            if i <= 300:
                print(f"{i:4}: {line.rstrip()}")
            else:
                break
except FileNotFoundError:
    print("File not found")
except Exception as e:
    print(f"Error: {e}")
PYTHON

Length of output: 3845


🏁 Script executed:

#!/bin/bash
# Extract propDefinitions section more robustly
python3 << 'PYTHON'
import re
try:
    with open('components/ticketsauce/ticketsauce.app.mjs') as f:
        content = f.read()
    
    # Find propDefinitions
    match = re.search(r'propDefinitions\s*=\s*\{(.*?)\n  \}', content, re.DOTALL)
    if match:
        prop_section = match.group(1)
        lines = prop_section.split('\n')
        for i, line in enumerate(lines[:150], 1):
            print(f"{i:4}: {line}")
    else:
        print("propDefinitions not found. Showing first 300 lines:")
        for i, line in enumerate(content.split('\n')[:300], 1):
            print(f"{i:4}: {line}")
except Exception as e:
    print(f"Error: {e}")
PYTHON

Length of output: 3904


🏁 Script executed:

#!/bin/bash
# Check if there's an orderId property that shows pagination
python3 << 'PYTHON'
import re
try:
    with open('components/ticketsauce/ticketsauce.app.mjs') as f:
        content = f.read()
    
    # Look for both eventId and orderId
    if 'orderId' in content:
        print("orderId FOUND - extracting context:")
        idx = content.find('orderId')
        print(content[max(0, idx-100):min(len(content), idx+500)])
        print("\n---\n")
    
    if 'eventId' in content:
        print("eventId FOUND - extracting context:")
        idx = content.find('eventId')
        print(content[max(0, idx-100):min(len(content), idx+500)])
    
    if 'orderId' not in content and 'eventId' not in content:
        print("Neither orderId nor eventId found. First 500 chars:")
        print(content[:500])
except Exception as e:
    print(f"Error: {e}")
PYTHON

Length of output: 1279


🏁 Script executed:

#!/bin/bash
# Get comprehensive view using tail and head
total=$(wc -l < components/ticketsauce/ticketsauce.app.mjs)
echo "Total lines: $total"
head -n 300 components/ticketsauce/ticketsauce.app.mjs

Length of output: 3046


🏁 Script executed:

#!/bin/bash
# Verify the component file is readable
test -r components/ticketsauce/ticketsauce.app.mjs && echo "File is readable" || echo "File not readable"
ls -la components/ticketsauce/ticketsauce.app.mjs
cat components/ticketsauce/ticketsauce.app.mjs

Length of output: 3138


🏁 Script executed:

#!/bin/bash
# Extract and display the propDefinitions
rg -A 250 "propDefinitions\s*=" components/ticketsauce/ticketsauce.app.mjs | head -300

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Just dump the whole file with line numbers
nl -ba components/ticketsauce/ticketsauce.app.mjs | head -300

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Use sed to extract lines 1-300
sed -n '1,300p' components/ticketsauce/ticketsauce.app.mjs | cat -n

Length of output: 3981


🏁 Script executed:

#!/bin/bash
# Use awk to display with line numbers
awk '{print NR": "$0}' components/ticketsauce/ticketsauce.app.mjs | head -300

Length of output: 3601


🏁 Script executed:

#!/bin/bash
# Try a basic cat with explicit line selection
cat components/ticketsauce/ticketsauce.app.mjs | sed -n '1,300p' | nl

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Ultimate fallback - use less then pipe through sed
head -300 < components/ticketsauce/ticketsauce.app.mjs | nl -ba -v 1

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Read using python line by line
python3 << 'PYEOF'
with open('components/ticketsauce/ticketsauce.app.mjs', 'r', encoding='utf-8', errors='ignore') as f:
    for line_num, line in enumerate(f, 1):
        if line_num <= 300:
            print(f"{line_num:4d}| {line}", end='')
PYEOF

Length of output: 3845


🏁 Script executed:

#!/bin/bash
# Check the actual structure by looking at the propDefinitions key
grep -n "propDefinitions" components/ticketsauce/ticketsauce.app.mjs && sed -n '1,150p' components/ticketsauce/ticketsauce.app.mjs

Length of output: 3052


🏁 Script executed:

#!/bin/bash
# Look at both patterns in the review - orderId and eventId
rg "orderId|eventId" components/ticketsauce/ticketsauce.app.mjs -B 5 -A 15

Length of output: 1769


🏁 Script executed:

#!/bin/bash
# Extract the exact lines mentioned in the review (7-30 and 31-71)
echo "=== Lines 1-80 of ticketsauce.app.mjs ===" && sed -n '1,80p' components/ticketsauce/ticketsauce.app.mjs && echo "" && echo "=== Line count ===" && wc -l components/ticketsauce/ticketsauce.app.mjs

Length of output: 2012


🏁 Script executed:

#!/bin/bash
# Final attempt: read entire file and pipe through tools
cat components/ticketsauce/ticketsauce.app.mjs | head -150

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check if code is readable and get a meaningful snippet
file components/ticketsauce/ticketsauce.app.mjs && head -c 2000 components/ticketsauce/ticketsauce.app.mjs

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Try expanding the view
expand components/ticketsauce/ticketsauce.app.mjs | head -300

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Most basic approach that should work
strings components/ticketsauce/ticketsauce.app.mjs | head -300

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Try with iconv if encoding issues
iconv -f UTF-8 -t UTF-8 components/ticketsauce/ticketsauce.app.mjs 2>/dev/null | head -250 || cat components/ticketsauce/ticketsauce.app.mjs | head -250

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Last resort: use od or hexdump to check file integrity then cat
od -c components/ticketsauce/ticketsauce.app.mjs | head -20 && echo "---" && cat components/ticketsauce/ticketsauce.app.mjs | head -200

Length of output: 3074


🏁 Script executed:

#!/bin/bash
# Simplest possible: just read it
cat < components/ticketsauce/ticketsauce.app.mjs | head -n 200

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check file permissions and try reading
stat components/ticketsauce/ticketsauce.app.mjs
timeout 5 cat components/ticketsauce/ticketsauce.app.mjs | head -n 250

Length of output: 88


🏁 Script executed:

#!/bin/bash
# Read the full file into a variable and extract
content=$(cat components/ticketsauce/ticketsauce.app.mjs 2>&1)
echo "$content" | head -200

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Use find to verify the file and then read it
find . -path "*ticketsauce/ticketsauce.app.mjs" -exec head -200 {} \;

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Final comprehensive script
ls -la components/ticketsauce/
echo "---"
echo "File type:"
file components/ticketsauce/ticketsauce.app.mjs
echo "---"
echo "Content:"
cat components/ticketsauce/ticketsauce.app.mjs 2>&1 | head -150

Length of output: 3480


🏁 Script executed:

#!/bin/bash
# Verify the ticketsauce component exists and show its structure
if [ -f components/ticketsauce/ticketsauce.app.mjs ]; then
  echo "✓ File exists"
  head -100 components/ticketsauce/ticketsauce.app.mjs
else
  echo "✗ File not found. Checking directory..."
  find . -name "*ticketsauce*" -type d
  find . -name "*ticketsauce*" -type f | head -10
fi

Length of output: 2291


🏁 Script executed:

#!/bin/bash
# Use process substitution to ensure we can read the file
{ head -250 components/ticketsauce/ticketsauce.app.mjs; } 2>&1

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Check if the component exists in a different location
find components -name "ticketsauce*" -type f

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Use sed to reliably extract content
sed '1,250!d' components/ticketsauce/ticketsauce.app.mjs

Length of output: 51


🏁 Script executed:

#!/bin/bash
# Double check the file with multiple approaches
test -e components/ticketsauce/ticketsauce.app.mjs && head -n 250 components/ticketsauce/ticketsauce.app.mjs || echo "File search:" && find . -name "ticketsauce.app.mjs"

Length of output: 3074


🏁 Script executed:

#!/bin/bash
# Most reliable: use bash read builtin
while IFS= read -r line; do
  ((n++))
  [ $n -le 250 ] && echo "$n: $line"
done < components/ticketsauce/ticketsauce.app.mjs

Length of output: 3601


🏁 Script executed:

#!/bin/bash
# Alternative: use awk with BEGIN to show structure
awk 'BEGIN{n=0} {n++; if(n<=250) print n": "$0}' components/ticketsauce/ticketsauce.app.mjs

Length of output: 3601


🏁 Script executed:

#!/bin/bash
# Final final attempt
(head -n 250 components/ticketsauce/ticketsauce.app.mjs) 2>&1 || (ls components/ticketsauce/ && echo "---" && file components/ticketsauce/ticketsauce.app.mjs)

Length of output: 3029


🏁 Script executed:

#!/bin/bash
# Read file and extract key sections
python3 << 'EOF'
import os
path = 'components/ticketsauce/ticketsauce.app.mjs'
if os.path.exists(path):
    with open(path, 'r', encoding='utf-8', errors='replace') as f:
        lines = f.readlines()
    print(f"Total lines: {len(lines)}\n")
    for i, line in enumerate(lines[:250], 1):
        print(f"{i:4}: {line.rstrip()}")
else:
    print(f"File not found: {path}")
    print("Available files:")
    for root, dirs, files in os.walk('components/ticketsauce'):
        for file in files:
            print(f"  {os.path.join(root, file)}")
EOF

Length of output: 3863


Implement pagination for eventId propDefinition.

eventId.options currently calls listEvents without pagination — users with many events will get truncated results. Apply the same prevContext / per_page / page pattern used by orderId (eventId: components/ticketsauce/ticketsauce.app.mjs, lines 7–30; listEvents: lines 86–105).

      async options({
-        partnerId, organizationId,
+        partnerId, organizationId, prevContext,
      }) {
        const events = await this.listEvents({
          partnerId,
          organizationId,
+          params: {
+            per_page: 100,
+            page: prevContext?.page || 0,
+          },
        });

        if (!events?.length) {
-          return [];
+          return prevContext?.page > 0
+            ? {
+              options: [],
+              context: {},
+            }
+            : [];
        }

        const options = events.map((eventData) => ({
          label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`,
          value: eventData.Event.id,
        }));

-        return options;
+        return {
+          options,
+          context: {
+            page: (prevContext?.page || 0) + 1,
+          },
+        };
      },

Verify /events accepts per_page/page (other ticketsauce actions use per_page/page for orders/tickets).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
eventId: {
type: "string",
label: "Event",
description: "Select an event",
async options({
partnerId, organizationId,
}) {
const events = await this.listEvents({
partnerId,
organizationId,
});
if (!events?.length) {
return [];
}
const options = events.map((eventData) => ({
label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`,
value: eventData.Event.id,
}));
return options;
},
},
eventId: {
type: "string",
label: "Event",
description: "Select an event",
async options({
partnerId, organizationId, prevContext,
}) {
const events = await this.listEvents({
partnerId,
organizationId,
params: {
per_page: 100,
page: prevContext?.page || 0,
},
});
if (!events?.length) {
return prevContext?.page > 0
? {
options: [],
context: {},
}
: [];
}
const options = events.map((eventData) => ({
label: `${eventData.Event.name} - ${eventData.Event.city} (${eventData.Event.start})`,
value: eventData.Event.id,
}));
return {
options,
context: {
page: (prevContext?.page || 0) + 1,
},
};
},
},

Copy link
Collaborator Author

@sergio-eliot-rodriguez sergio-eliot-rodriguez Oct 17, 2025

Choose a reason for hiding this comment

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

Pagination is not supported. "List of Events" endpoint returns all events, users always can filter out data.

List of Events
GET /v2/events
Get a list of all events you own. This data is not only sortable, but can be filtered by a large number of optional parameters. All date/time options should be UTC.

Copy link
Contributor

Choose a reason for hiding this comment

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

@sergio-eliot-rodriguez, thank you for clarifying! If the /events endpoint returns all events without pagination support, then the current implementation is correct. I appreciate you sharing this API behavior detail.


✏️ Learnings added
Learnt from: sergio-eliot-rodriguez
PR: PipedreamHQ/pipedream#18787
File: components/ticketsauce/ticketsauce.app.mjs:7-30
Timestamp: 2025-10-17T06:58:24.566Z
Learning: The TicketSauce "List of Events" API endpoint (GET /v2/events) does not support pagination and returns all events. Users can filter the data using the available query parameters (partner_id, organization_id, etc.) rather than paginating through results.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@sergio-eliot-rodriguez
Copy link
Collaborator Author

Resolves #18366

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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 (2)
components/ticketsauce/actions/get-orders/get-orders.mjs (2)

153-157: Add an action run summary.

Set a concise $summary so users see a helpful message in the UI.

-    return this.ticketsauce.listOrders({
+    const res = await this.ticketsauce.listOrders({
       eventId: this.eventId,
       params,
     });
+    this.$summary = `Retrieved orders for event ${this.eventId}`;
+    return res;

38-51: Use integer types, enforce bounds, and exclude undefined params.

The Ticketsauce app helper passes params directly to axios without sanitization or type conversion. Verify the refactor against the Ticketsauce API documentation to confirm the Max 500 per_page limit, then apply these changes:

@@
     perPage: {
-      type: "string",
+      type: "integer",
       label: "Per Page",
       description: "How many results to retrieve (per page). Max 500.",
       optional: true,
-      default: "100",
+      default: 100,
+      min: 1,
+      max: 500,
     },
     page: {
-      type: "string",
+      type: "integer",
       label: "Page",
       description: "Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60.",
       optional: true,
-      default: "1",
+      default: 1,
+      min: 1,
     },
@@
-    totalAbove: {
-      type: "string",
+    totalAbove: {
+      type: "integer",
       label: "Total Above",
       description: "Return only orders whose order total is greater than this value.",
       optional: true,
     },
     totalBelow: {
-      type: "string",
+      type: "integer",
       label: "Total Below",
       description: "Return only orders whose order total is less than this value.",
       optional: true,
     },
@@
   async run() {
-    const params = {
-      per_page: this.perPage,
-      page: this.page,
-      q: this.q,
-      return_questionnaires: this.returnQuestionnaires,
-      return_tickets: this.returnTickets,
-      return_line_item_fees: this.returnLineItemFees,
-      ordered_after: this.orderedAfter,
-      ordered_before: this.orderedBefore,
-      modified_after: this.modifiedAfter,
-      modified_before: this.modifiedBefore,
-      sort_by: this.sortBy,
-      sort_dir: this.sortDir,
-      total_above: this.totalAbove,
-      total_below: this.totalBelow,
-    };
+    const perPage = Math.min(Number(this.perPage ?? 100), 500);
+    const page = Math.max(Number(this.page ?? 1), 1);
+    const params = {
+      per_page: perPage,
+      page,
+      ...(this.q && { q: this.q }),
+      ...(this.returnQuestionnaires !== undefined && { return_questionnaires: this.returnQuestionnaires }),
+      ...(this.returnTickets !== undefined && { return_tickets: this.returnTickets }),
+      ...(this.returnLineItemFees !== undefined && { return_line_item_fees: this.returnLineItemFees }),
+      ...(this.orderedAfter && { ordered_after: this.orderedAfter }),
+      ...(this.orderedBefore && { ordered_before: this.orderedBefore }),
+      ...(this.modifiedAfter && { modified_after: this.modifiedAfter }),
+      ...(this.modifiedBefore && { modified_before: this.modifiedBefore }),
+      ...(this.sortBy && { sort_by: this.sortBy }),
+      ...(this.sortDir && { sort_dir: this.sortDir }),
+      ...(this.totalAbove !== undefined && { total_above: this.totalAbove }),
+      ...(this.totalBelow !== undefined && { total_below: this.totalBelow }),
+    };

Also applies to: lines 122-133, 135-151

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46e2542 and 3418247.

📒 Files selected for processing (1)
  • components/ticketsauce/actions/get-orders/get-orders.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
components/ticketsauce/actions/get-orders/get-orders.mjs (3)
components/ticketsauce/actions/get-ticket-checkin-ids/get-ticket-checkin-ids.mjs (1)
  • params (53-56)
components/ticketsauce/actions/get-events/get-events.mjs (1)
  • params (88-98)
components/ticketsauce/actions/get-event-details/get-event-details.mjs (1)
  • params (58-61)
⏰ 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: Lint Code Base
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (1)
components/ticketsauce/actions/get-orders/get-orders.mjs (1)

28-37: Dynamic event selector looks good.

Clean use of propDefinition with partnerId/organizationId context to scope event options.

export default {
key: "ticketsauce-get-orders",
name: "Get Orders",
description: "Get a list of orders from the specified event. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#orders)",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Use a stable docs URL (avoid query keys in the link).

The speca URL includes a ?key=... parameter that may be temporary. Link to the canonical page to prevent future link rot.


🌐 Web query:

What is the canonical public documentation URL for the Ticketsauce Orders endpoint (without a temporary key parameter)?

💡 Result:

Do you mean the TicketSauce API "Orders" documentation page (their public API docs)? If so, please confirm — I couldn't find a clear canonical Orders-docs URL and will search again once you confirm.


I'll perform a more targeted search to find Ticketsauce's official API documentation structure.

Let me search more specifically for Ticketsauce's official developer documentation.

Let me search specifically for information about speca.io and its URL structure.

Update the URL to remove the temporary query parameter.

The ?key=... parameter is not part of standard Speca.io documentation URLs and should be removed. Speca is an API design and documentation platform, and its canonical URL format is https://speca.io/[owner]/[api-name] without query parameters.

Change the link from:

https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#orders

To:

https://speca.io/ticketsauce/ticketsauce-public-api#orders
🤖 Prompt for AI Agents
components/ticketsauce/actions/get-orders/get-orders.mjs around line 6: the
documentation URL in the description includes a temporary query parameter
(?key=...) which should be removed; update the link to
https://speca.io/ticketsauce/ticketsauce-public-api#orders so it follows the
canonical speca.io format without the query string and retains the #orders
fragment.

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.

I made a few comments, some of which may apply to more files. Please check them and let me know if anything is needed.

Comment on lines +16 to +27
partnerId: {
type: "string",
label: "Partner ID",
description: "Including this ID will limit the event selection to the specific partner.",
optional: true,
},
organizationId: {
type: "string",
label: "Organization ID",
description: "Including this ID will limit the event selection to the specific organization.",
optional: true,
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we not list these with async options?

Comment on lines +44 to +47
options: [
"0",
"1",
],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should use a boolean prop for this, and convert it to 0 or 1 in the component code

includePerformers: {
type: "boolean",
label: "Include Performers",
description: "Returns any associated performers/artists with the event.",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
description: "Returns any associated performers/artists with the event.",
description: "If true, returns any associated performers/artists with the event.",

include_performers: this.includePerformers,
};

return this.ticketsauce.getEventDetails({
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be passing $ to this method - the same applies for all other request methods called in actions

Comment on lines +16 to +27
partnerId: {
type: "string",
label: "Partner ID",
description: "Including this ID will limit the result set to the specific partner.",
optional: true,
},
organizationId: {
type: "string",
label: "Organization ID",
description: "Including this ID will limit the result set to the specific organization.",
optional: true,
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

These are also used in get-event-details, should reuse them with a propDefinition

startAfter: {
type: "string",
label: "Start After",
description: "Only retrieve events that start AFTER the specified UTC date (format: YYYY-MM-DD).",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
description: "Only retrieve events that start AFTER the specified UTC date (format: YYYY-MM-DD).",
description: "Only retrieve events that start AFTER the specified UTC date (format: `YYYY-MM-DD`).",

endBefore: {
type: "string",
label: "End Before",
description: "Only retrieve events that end BEFORE the specified UTC date (format: YYYY-MM-DD).",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
description: "Only retrieve events that end BEFORE the specified UTC date (format: YYYY-MM-DD).",
description: "Only retrieve events that end BEFORE the specified UTC date (format: `YYYY-MM-DD`).",

Comment on lines +80 to +85
includePerformers: {
type: "boolean",
label: "Include Performers",
description: "Returns any associated performers/artists with an event",
optional: true,
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

This one is also duplicated and should also be reused

privacyType: {
type: "string",
label: "Privacy Type",
description: "By default, this will restrict events to only those that are public. Changing to 'all' will remove all restriction, or changing to 'unlisted' will make it only pull those events that are set to unlisted.",
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the description of each item can be in the individual option, instead of all of them in the prop description, e.g.

{
  label: "List only public events",
  value: "public"
}
// etc.

timer: {
type: "$.interface.timer",
default: {
intervalSeconds: 60 * 60, //Ticketsauce API caches response to "List of Events" for 1 hour
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this information about the response caching should be displayed as an alert prop, preferably with a link to the associated documentation

@GTFalcao GTFalcao moved this from Ready for PR Review to Changes Required in Component (Source and Action) Backlog Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

3 participants