Skip to content

chore(chat): migrate YouTube connector to Composio#1719

Merged
sweetmantech merged 14 commits intotestfrom
migrate/youtube-composio
May 1, 2026
Merged

chore(chat): migrate YouTube connector to Composio#1719
sweetmantech merged 14 commits intotestfrom
migrate/youtube-composio

Conversation

@arpitgupta1214
Copy link
Copy Markdown
Collaborator

@arpitgupta1214 arpitgupta1214 commented Apr 30, 2026

Summary

Replaces the chat-side custom YouTube OAuth flow with the existing Composio connector path. Connect/disconnect/channel-info all go through `/api/connectors` and `/api/connectors/actions`. The legacy `/api/youtube/*` routes, the `youtube_tokens` Supabase helpers, and the four LLM-tool result components for login/channels/playlist/thumbnail are deleted (Composio's toolkit covers them). Revenue dispatch is kept since the api-side `get_youtube_revenue` MCP tool stays.

Pairs with api#494 and docs#XXX.

Test plan

  • On preview, click Connect YouTube on an artist → Composio OAuth → returns to settings with the YouTube card showing connected
  • ChannelInfo + ChatInputYoutubeButtonPopover render the artist's channel name, thumbnail, and stats
  • Click logout → Composio reports disconnected, channel-info query invalidates
  • In chat, ask the agent for YouTube channel stats / playlist videos / thumbnail upload — verify Composio actions fire
  • Ask for YouTube revenue — verify the retained `get_youtube_revenue` MCP tool returns data
  • `pnpm test` (53/53 green)
  • `npx tsc --noEmit` clean for changed files

Summary by cubic

Migrates YouTube to Composio for auth and channel stats, removes legacy OAuth/UI, unwraps Composio responses, and moves connector state to React Query; keeps the custom revenue tool. Adds proper “YouTube” naming and a connector description so the settings card reads correctly.

  • Refactors

    • Enable YouTube in ALLOWED_ARTIST_CONNECTORS; connect/disconnect now use useConnectors + useConnectorHandlers (shared React Query cache, in-flight disable, aria-labels). Adds onDisconnectSuccess to also invalidate ["youtube-channel-info", accountId] and restores authorize to return null on failure.
    • useYoutubeChannel calls YOUTUBE_GET_CHANNEL_STATISTICS via executeConnectorActionApi with part: "snippet,statistics"; extracts lib/youtube/fetchYoutubeChannel; query gated on Privy authenticated. useYoutubeStatus now derives from connectors and surfaces errors.
    • Adds lib/composio/api/executeConnectorActionApi to unwrap Composio’s ToolExecuteResponse. Maps youtube to “YouTube” in formatConnectorName and adds a YouTube description in connectorMetadata.
    • Removes legacy /api/auth/callback/google, /api/youtube/*, Supabase youtube_tokens, OAuth/analytics libs, types/youtube.ts, and unused chat UIs; keeps get_youtube_revenue MCP tool/UI with an inlined result type and fallback error message.
  • Migration

    • Requires api#494 (Composio actions endpoint). Ensure the Composio YouTube connector is enabled; users must reconnect via settings. Legacy Supabase youtube_tokens are no longer used and can be cleaned up separately.

Written for commit 8cfe958. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor

    • YouTube integration now uses the connector system for auth, status, and channel data.
    • Connect/disconnect flows and status checks moved to connector-driven behavior; UI now reacts to connector state.
  • Bug Fixes / Chores

    • Removed legacy YouTube server endpoints and many legacy YouTube UI pieces (video dialogs, stats, channel displays, skeletons).
    • Added YouTube to supported account connectors; connect button updated to use the connector flow.

- Add youtube to allowedArtistConnectors so the YouTube card appears in
  the artist settings Connectors tab alongside TikTok/Instagram
- Rewrite useYoutubeChannel to call POST /api/connectors/actions with
  YOUTUBE_GET_CHANNEL_STATISTICS; consume the raw Google channels.list
  response (snippet/statistics/thumbnails) directly, no remapping
- Rewrite useYoutubeStatus to derive connection state from the Composio
  connectors list instead of the legacy channel-info endpoint
- Rewrite ConnectYouTubeButton + YoutubeLogoutButton to use the Composio
  authorize/disconnect flow already used by TikTok/Instagram
- Drop legacy chat-side OAuth surface: /api/youtube/*,
  /api/auth/callback/google, lib/youtube OAuth/token helpers,
  lib/supabase/youtube_tokens, types/youtube.ts, useYouTubeLoginSuccess,
  the four LLM-tool result components for login/channels/playlist/thumb
  (those tools now come from Composio's YouTube toolkit)

Keeps the get_youtube_revenue MCP tool dispatch in ToolComponents and the
matching VercelChat result components — Composio has no YouTube
Analytics action, so revenue stays custom on the api side.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 30, 2026

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

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview May 1, 2026 7:50pm
recoup-chat Ready Ready Preview May 1, 2026 7:50pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Warning

Rate limit exceeded

@sweetmantech has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 58 minutes and 34 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c777676b-2b2a-4aa0-8dbe-c31fbcd84d3a

📥 Commits

Reviewing files that changed from the base of the PR and between e4c3cf3 and 8cfe958.

📒 Files selected for processing (2)
  • lib/composio/connectorMetadata.ts
  • lib/composio/formatConnectorName.ts
📝 Walkthrough

Walkthrough

Migrates YouTube integration from bespoke OAuth/Supabase utilities to Composio connectors and Privy: removes local OAuth routes, token storage/validation/refresh utilities, and many YouTube UI components; adds connector-driven authorization, a connector action API helper, and refactored hooks/components to use connectors and runtime access tokens.

Changes

Cohort / File(s) Summary
API routes removed
app/api/auth/callback/google/route.ts, app/api/youtube/channel-info/route.ts, app/api/youtube/logout/route.ts
Removed server-side OAuth callback and YouTube API endpoints; server token handling and routes deleted in favor of connector flows.
Supabase token helpers removed
lib/supabase/youtube_tokens/* (getYouTubeTokens.ts, insertYouTubeTokens.ts, deleteYouTubeTokens.ts)
Deleted helpers for persisting/reading/deleting YouTube tokens from Supabase.
YouTube client & utilities removed
lib/youtube/... (deleted: channel-fetcher.ts, token-validator.ts, token-refresher.ts, oauth-client.ts, queryAnalyticsReports.ts, channel-monetization-by-id.ts, authenticated-channel-monetization.ts, getYoutubePlaylistVideos.ts, getResizedImageBuffer.ts, formatDuration.ts, fetchYouTubeChannel.ts (old), youtubeLogin.ts, is-token-expired.ts, error-builder.ts, revenue-error-handler.ts, token-refresher.ts)
Removed direct Google API clients, token lifecycle, analytics helpers, image resizing, duration formatting, error builders, and legacy fetch/login utilities.
Composio connector additions/changes
lib/composio/allowedArtistConnectors.ts, lib/composio/api/executeConnectorActionApi.ts
Added "youtube" to allowed connectors and introduced executeConnectorActionApi for authenticated connector action POSTs.
Connector-backed fetcher added
lib/youtube/fetchYoutubeChannel.ts
Added connector-based channel statistics fetcher that calls executeConnectorActionApi with a bearer token and artistAccountId.
Hooks: connector-driven refactor
hooks/useYoutubeChannel.tsx, hooks/useYoutubeStatus.ts, hooks/useConnectors.ts, hooks/useArtistConnectorCallback.ts, hooks/useConnectorHandlers.ts
Refactored hooks to use Composio connectors, React Query, and Privy access tokens; useConnectors now shares cache via React Query; useYoutubeStatus derives status from connectors; useConnectorHandlers adds optional onDisconnectSuccess.
Connect & disconnect flows updated
components/common/ConnectYouTubeButton.tsx, components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx
Connect button and logout now use connector authorize/disconnect flows instead of direct youtubeLogin/DELETE endpoint; invalidation targets updated to connector-backed queries.
YouTube UI components removed or simplified
components/VercelChat/... (many youtube files removed: channel display, video card, dialogs, skeletons, results), components/YouTube/... (PopoverContent, index, StatCard), components/VercelChat/ChatInputYoutubeButton.tsx
Removed numerous YouTube-specific UI pieces; retained/reworked only ChannelInfo mapping and revenue flow adjustments.
YouTube revenue type localized & formatting
components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx
Replaced external revenue type import with a local exported interface and adjusted component formatting/JSX.
Miscellaneous formatting & refactors
components/VercelChat/ToolComponents.tsx, other small files
Removed specific YouTube tool branches and applied formatting/refactors across tool rendering and imports.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as App UI
    participant Connectors as Composio Connectors
    participant API as executeConnectorActionApi
    participant OAuth as OAuth Provider

    User->>UI: Click "Connect YouTube"
    UI->>Connectors: authorize(config) (useConnectors)
    Connectors->>API: POST /connectors/actions (Bearer access token)
    API->>OAuth: Request auth/redirect URL
    OAuth-->>API: Return redirect URL
    API-->>Connectors: Return URL
    Connectors-->>UI: Provide redirect / open URL
    User->>OAuth: Complete consent (provider)
    OAuth-->>Connectors: Callback, persist connector state
    Connectors-->>UI: Redirect back to app with connected state
    UI->>API: executeConnectorActionApi (YOUTUBE_GET_CHANNEL_STATISTICS)
    API->>Connectors: Request channel statistics (artistAccountId)
    Connectors-->>API: Return channel items
    API-->>UI: Channel statistics response
    UI->>UI: Render channel info / update caches
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • sweetmantech

"Old tokens gone, new connectors sing,
OAuth steps now ride a centralized wing.
UI trimmed neat, the hooks rearranged,
Privy hands the token, flows exchanged.
A tidy refactor — small storms, new spring."

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning Pull request contains case-sensitivity defects, hardcoded string literals violating DRY, unsafe URL string interpolation, and duplicated connector configuration patterns. Normalize slugs during Set creation, extract hardcoded 'youtube' into a constant, use URLSearchParams for safe URL encoding, and create a reusable factory function for connector configuration.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch migrate/youtube-composio

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
Review rate limit: 0/1 reviews remaining, refill in 58 minutes and 34 seconds.

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

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 48 files

Confidence score: 4/5

  • This PR is likely safe to merge, with issues limited to repository structure/readability rules rather than functional or user-facing defects.
  • The most severe finding is in components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx (4/10): the file exceeds the 100-line single-responsibility guideline, which increases maintenance risk but does not indicate a concrete runtime regression.
  • components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx also exceeds the 100-line limit (3/10), reinforcing a mild maintainability concern rather than an immediate behavior break.
  • Pay close attention to components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx, components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx - oversized modules may become harder to reason about and safely modify.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx">

<violation number="1" location="components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx:101">
P3: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**

This module exceeds the repository’s 100-line file limit.</violation>
</file>

<file name="components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx">

<violation number="1" location="components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx:10">
P2: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**

File exceeds the 100-line limit required by the repository's readability/single-responsibility rule.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -1,26 +1,46 @@
import React from 'react';
import React from "react";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Custom agent: Code Structure and Size Limits for Readability and Single Responsibility

File exceeds the 100-line limit required by the repository's readability/single-responsibility rule.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx, line 10:

<comment>File exceeds the 100-line limit required by the repository's readability/single-responsibility rule.</comment>

<file context>
@@ -1,26 +1,46 @@
 import YouTubeRevenueDaily from "./YouTubeRevenueDaily";
 import { formatDate } from "@/lib/utils/formatDate";
 
+export interface YouTubeRevenueResult {
+  success: boolean;
+  status: string;
</file context>

Comment thread components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c9266b77b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +35 to +39
const ok = await disconnect(youtube.connectedAccountId);
if (ok) {
queryClient.invalidateQueries({
queryKey: ["youtube-channel-info", artistAccountId],
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Refresh connector status after YouTube disconnect

YoutubeLogoutButton disconnects using its own useConnectors instance and then only invalidates the youtube-channel-info React Query key. The connected/disconnected UI in StandaloneYoutubeComponent is driven by useYoutubeStatus, which uses a separate local useConnectors state (not that query key), so it does not update after logout and can keep showing YouTube as connected until the modal/page remounts. This reproduces in the artist settings flow where both components are siblings (components/ArtistSetting/Inputs.tsx).

Useful? React with 👍 / 👎.

…TICS

Composio's action defaults the `part` parameter to "statistics" only,
so the response had `snippet: null` and the UI rendered without title
or thumbnail. Pass `part: "snippet,statistics"` so the channel name,
description, and thumbnail come back too.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 48 files

Confidence score: 4/5

  • This PR is likely safe to merge with minimal risk: the reported issue is moderate-low severity (4/10) and focused on one interaction path.
  • In components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx, the disconnect action can be triggered multiple times while a request is still in flight, which may cause duplicate logout/disconnect requests for fast repeat clicks.
  • The impact appears user-facing but contained (request duplication rather than core flow breakage), so this is a polish/stability fix rather than a merge blocker.
  • Pay close attention to components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx - prevent repeated clicks during pending disconnect to avoid duplicate requests.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx">

<violation number="1" location="components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx:49">
P2: The logout button is clickable during an in-flight disconnect, so users can fire duplicate disconnect requests by clicking rapidly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx Outdated
Copy link
Copy Markdown
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: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/ArtistSetting/StandaloneYoutubeComponent/ChannelInfo.tsx`:
- Line 22: The caption for the YouTube section is rendered with a form <label>
element in ChannelInfo.tsx (the element using className cn("text-sm", { hidden:
dense })), which is semantically incorrect for static UI; replace that <label>
with a non-form text element such as a <p> or <span> (keeping the same className
and conditional hidden logic) so the visual styling and hide behavior remain
unchanged but assistive technology receives correct semantics for static text.

In `@components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx`:
- Around line 46-52: The icon-only disconnect button lacks an accessible name;
update the Button (the component rendering the XIcon and using
onClick={handleClick}) to include an accessible label—e.g., add
aria-label="Disconnect YouTube" or aria-label="Logout" (or include an offscreen
span with visually-hidden text) so screen readers announce the button purpose
while keeping the XIcon for visual users.
- Around line 33-50: The click handler handleClick can fire multiple times while
disconnect() is in flight; add a local boolean state (e.g., isDisconnecting) in
the YoutubeLogoutButton component, set it true before awaiting
disconnect(youtube.connectedAccountId) and false after, and guard early returns
with it so duplicate requests are prevented; also pass isDisconnecting to the
Button (disabled prop or conditional class) so the UI is disabled during the
in-flight request and still call
queryClient.invalidateQueries(["youtube-channel-info", artistAccountId]) only
when the disconnect completes successfully.

In `@components/common/ConnectYouTubeButton.tsx`:
- Around line 52-65: The ConnectYouTubeButton component currently hides its
visible label when the dense prop is true, leaving the button unlabeled for
assistive tech; update the Button rendered in ConnectYouTubeButton to provide an
accessible name when dense is true by adding an aria-label (e.g., "Connect
YouTube Account") or including a visually hidden element (sr-only) with the same
text that is conditionally rendered when dense is true, ensuring the existing
visible text remains for non-dense mode and that the aria-label/text matches the
visible label for consistency.

In `@components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx`:
- Around line 33-39: YouTubeRevenueResult currently passes result.message (which
is optional) directly to YouTubeRevenueError and can render an empty message;
update the error branch in YouTubeRevenueResult to pass a fallback user-facing
string (e.g. "An error occurred while fetching revenue.") when result.message is
undefined or empty so YouTubeRevenueError always receives a non-empty message;
locate the conditional in YouTubeRevenueResult and replace the direct
result.message usage with the fallback.

In `@components/YouTube/ChatInputYoutubeButtonPopover/index.tsx`:
- Around line 37-44: The trigger currently uses a non-semantic <div> with
onClick to toggle isOpen, which prevents keyboard activation; replace that
clickable div with a semantic, focusable trigger (preferably a <button>) or, if
children are already interactive, render a separate dedicated trigger element
wrapping children so you don't nest interactive controls; ensure the toggle
logic uses setIsOpen(!isOpen), add keyboard handlers to activate on Enter/Space
(or rely on native button behavior), and keep aria-expanded/aria-controls or
appropriate roles in sync with isOpen to support accessibility.

In `@components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx`:
- Around line 35-43: The img tag in PopoverContent.tsx uses
thumbnails?.high?.url || thumbnails?.medium?.url || thumbnails?.default?.url ||
"" which can produce an empty src; change the rendering to only output the <img>
when a non-empty URL exists (check the computed thumbnailUrl variable derived
from thumbnails), and otherwise render a fallback (e.g., an avatar
placeholder/div or an accessible aria-label using title) so no <img> is created
with an empty src; update the JSX around the img (same className used currently)
to conditionally render based on thumbnailUrl and keep title/alt behavior.

In `@hooks/useYoutubeStatus.ts`:
- Line 38: The return value currently hard-codes error: null which hides real
errors from useConnectors; update the hook (hooks/useYoutubeStatus.ts) to
propagate the actual error from the connector call instead of null—use the error
variable returned by useConnectors (or the connector error name in this file)
and return { data, isLoading, error } so consumers can detect failures
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ec06b559-55a2-4735-9ee0-790169f55f78

📥 Commits

Reviewing files that changed from the base of the PR and between 5a6e03f and fd05539.

⛔ Files ignored due to path filters (1)
  • types/youtube.ts is excluded by none and included by none
📒 Files selected for processing (47)
  • app/api/auth/callback/google/route.ts
  • app/api/youtube/channel-info/route.ts
  • app/api/youtube/logout/route.ts
  • components/ArtistSetting/StandaloneYoutubeComponent/ChannelInfo.tsx
  • components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx
  • components/VercelChat/ToolComponents.tsx
  • components/VercelChat/YoutubeVideoStats.tsx
  • components/VercelChat/dialogs/YoutubeVideoDialog.tsx
  • components/VercelChat/tools/youtube/YouTubeAccessSkeleton.tsx
  • components/VercelChat/tools/youtube/YouTubeChannelDisplay.tsx
  • components/VercelChat/tools/youtube/YouTubeChannelVideosListSkeleton.tsx
  • components/VercelChat/tools/youtube/YouTubeChannelsResult.tsx
  • components/VercelChat/tools/youtube/YouTubeErrorDisplay.tsx
  • components/VercelChat/tools/youtube/YouTubeLoginResult.tsx
  • components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx
  • components/VercelChat/tools/youtube/YouTubeSetThumbnailResult.tsx
  • components/VercelChat/tools/youtube/YouTubeSetThumbnailSkeleton.tsx
  • components/VercelChat/tools/youtube/YoutubeChannelVideosListResult.tsx
  • components/VercelChat/tools/youtube/YoutubeVideoCard.tsx
  • components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx
  • components/YouTube/ChatInputYoutubeButtonPopover/index.tsx
  • components/common/ConnectYouTubeButton.tsx
  • hooks/useArtistConnectorCallback.ts
  • hooks/useYouTubeLoginSuccess.ts
  • hooks/useYoutubeChannel.tsx
  • hooks/useYoutubeStatus.ts
  • lib/composio/allowedArtistConnectors.ts
  • lib/composio/api/executeConnectorActionApi.ts
  • lib/supabase/youtube_tokens/deleteYouTubeTokens.ts
  • lib/supabase/youtube_tokens/getYouTubeTokens.ts
  • lib/supabase/youtube_tokens/insertYouTubeTokens.ts
  • lib/youtube/authenticated-channel-monetization.ts
  • lib/youtube/channel-fetcher.ts
  • lib/youtube/channel-monetization-by-id.ts
  • lib/youtube/error-builder.ts
  • lib/youtube/fetchYouTubeChannel.ts
  • lib/youtube/formatDuration.ts
  • lib/youtube/getResizedImageBuffer.ts
  • lib/youtube/getYoutubePlaylistVideos.ts
  • lib/youtube/is-token-expired.ts
  • lib/youtube/oauth-client.ts
  • lib/youtube/queryAnalyticsReports.ts
  • lib/youtube/revenue-error-handler.ts
  • lib/youtube/token-refresher.ts
  • lib/youtube/token-validator.ts
  • lib/youtube/youtube-analytics-oauth-client.ts
  • lib/youtube/youtubeLogin.ts
💤 Files with no reviewable changes (35)
  • components/VercelChat/tools/youtube/YouTubeChannelVideosListSkeleton.tsx
  • lib/youtube/youtube-analytics-oauth-client.ts
  • components/VercelChat/tools/youtube/YouTubeSetThumbnailSkeleton.tsx
  • lib/youtube/is-token-expired.ts
  • app/api/youtube/logout/route.ts
  • lib/youtube/formatDuration.ts
  • lib/supabase/youtube_tokens/deleteYouTubeTokens.ts
  • components/VercelChat/tools/youtube/YouTubeLoginResult.tsx
  • components/VercelChat/tools/youtube/YouTubeAccessSkeleton.tsx
  • hooks/useYouTubeLoginSuccess.ts
  • components/VercelChat/tools/youtube/YoutubeChannelVideosListResult.tsx
  • components/VercelChat/tools/youtube/YouTubeChannelDisplay.tsx
  • lib/supabase/youtube_tokens/insertYouTubeTokens.ts
  • components/VercelChat/tools/youtube/YouTubeSetThumbnailResult.tsx
  • components/VercelChat/YoutubeVideoStats.tsx
  • lib/supabase/youtube_tokens/getYouTubeTokens.ts
  • lib/youtube/youtubeLogin.ts
  • lib/youtube/getYoutubePlaylistVideos.ts
  • lib/youtube/error-builder.ts
  • lib/youtube/getResizedImageBuffer.ts
  • app/api/youtube/channel-info/route.ts
  • lib/youtube/oauth-client.ts
  • components/VercelChat/tools/youtube/YouTubeChannelsResult.tsx
  • lib/youtube/revenue-error-handler.ts
  • lib/youtube/queryAnalyticsReports.ts
  • lib/youtube/channel-fetcher.ts
  • lib/youtube/token-refresher.ts
  • app/api/auth/callback/google/route.ts
  • lib/youtube/channel-monetization-by-id.ts
  • lib/youtube/token-validator.ts
  • components/VercelChat/tools/youtube/YouTubeErrorDisplay.tsx
  • lib/youtube/authenticated-channel-monetization.ts
  • components/VercelChat/tools/youtube/YoutubeVideoCard.tsx
  • lib/youtube/fetchYouTubeChannel.ts
  • components/VercelChat/dialogs/YoutubeVideoDialog.tsx

Comment thread components/ArtistSetting/StandaloneYoutubeComponent/ChannelInfo.tsx Outdated
Comment thread components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx Outdated
Comment thread components/common/ConnectYouTubeButton.tsx
Comment thread components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx
Comment thread components/YouTube/ChatInputYoutubeButtonPopover/index.tsx Outdated
Comment thread components/YouTube/ChatInputYoutubeButtonPopover/PopoverContent.tsx Outdated
Comment thread hooks/useYoutubeStatus.ts Outdated
Both components were orphaned — ChatInputYoutubeButton had zero callers,
which made ChatInputYoutubeButtonPopover and its StatCard / PopoverContent
unreachable too. Drop them entirely.
api now passes Composio's ToolExecuteResponse through unchanged
({successful, data, error}). Consumer adapter unwraps once so all
chat-side callers get the underlying provider payload directly
(e.g. youtube.channels.list with `items`); upstream failures throw.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.

- Share connector refresh across useConnectors instances so logout updates
  sibling status (P1: useYoutubeStatus stale after disconnect)
- Disable disconnect button while in-flight to prevent duplicate requests
- Add aria-label to icon-only disconnect button
- Add aria-label to ConnectYouTubeButton for dense (icon-only) mode
- Propagate connector errors from useYoutubeStatus instead of hard-coded null
- Use semantic <span> for static section caption in ChannelInfo
- Provide fallback message in YouTubeRevenueResult when error text missing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="hooks/useConnectors.ts">

<violation number="1" location="hooks/useConnectors.ts:9">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

File exceeds the 100-line limit required by the maintainability rule.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread hooks/useConnectors.ts
The api endpoint always returns Composio's ToolExecuteResponse envelope
(`{ successful, data, error }`) — every Composio Vercel-AI-SDK tool returns
that shape. Drop the defensive non-envelope branch and read the typed shape
directly, removing the `as unknown` casts and inline type guards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hannel

- useConnectors now uses React Query so all instances share one cache;
  disconnect/authorize invalidate the connectors key and sibling instances
  re-render automatically. Drops the module-level Set<()=>void> broadcast.
- Extract fetchYoutubeChannel + types to lib/youtube/fetchYoutubeChannel.ts,
  matching the fetchConnectorsApi / authorizeConnectorApi pattern. The hook
  is now ~20 lines and just wires React Query to the helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fetchConnectorsApi already returns Promise<ConnectorInfo[]>, so TS infers
the queryFn type correctly without the explicit annotation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/useYoutubeChannel.tsx`:
- Around line 9-19: The query in useYoutubeChannel (the useQuery call) is
currently only gated by artistAccountId so it can run unauthenticated; update
the hook to also read the authenticated flag from usePrivy (alongside
getAccessToken) and change the enabled option to `!!artistAccountId &&
authenticated` so the query won't execute when `getAccessToken()` would return
null; keep the fetchYoutubeChannel call and the existing error handling intact.

In `@lib/youtube/fetchYoutubeChannel.ts`:
- Around line 35-56: fetchYoutubeChannel currently returns a possibly-empty
YouTubeChannelStatisticsResponse and lets undefined/empty items propagate;
update fetchYoutubeChannel to validate the response from
executeConnectorActionApi (the call inside fetchYoutubeChannel) and throw a
clear error if result.items is missing or an empty array (e.g., after awaiting
executeConnectorActionApi<YouTubeChannelStatisticsResponse>(...), check
response.items && response.items.length > 0 and throw a descriptive Error like
"YouTube channel not found for account {artistAccountId}" when the check fails)
so callers get a fast, explicit failure instead of silently handling undefined
data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6e616f37-6470-491d-90ad-b59c7221b677

📥 Commits

Reviewing files that changed from the base of the PR and between e56fbf9 and e916401.

📒 Files selected for processing (9)
  • components/ArtistSetting/StandaloneYoutubeComponent/ChannelInfo.tsx
  • components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx
  • components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx
  • components/common/ConnectYouTubeButton.tsx
  • hooks/useConnectors.ts
  • hooks/useYoutubeChannel.tsx
  • hooks/useYoutubeStatus.ts
  • lib/composio/api/executeConnectorActionApi.ts
  • lib/youtube/fetchYoutubeChannel.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • hooks/useYoutubeStatus.ts
  • components/ArtistSetting/StandaloneYoutubeComponent/ChannelInfo.tsx
  • components/common/ConnectYouTubeButton.tsx
  • components/VercelChat/tools/youtube/YouTubeRevenueResult.tsx
  • components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx

Comment thread hooks/useYoutubeChannel.tsx Outdated
Comment thread lib/youtube/fetchYoutubeChannel.ts
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="hooks/useConnectors.ts">

<violation number="1" location="hooks/useConnectors.ts:78">
P2: `authorize` no longer handles API failures, so it can reject instead of returning `null` as the hook contract implies.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread hooks/useConnectors.ts Outdated
arpitgupta1214 and others added 2 commits May 1, 2026 21:41
…ntract

Dropped during the React Query refactor — without the catch, an API failure
rejects the promise instead of returning null, which the only caller
(ConnectYouTubeButton) doesn't handle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the codebase convention (useTaskRunStatus, useCatalogs, useArtistPosts,
etc.) — without it, the query runs and immediately throws "Not authenticated"
when the user isn't signed in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="hooks/useConnectors.ts">

<violation number="1" location="hooks/useConnectors.ts:78">
P2: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**

File exceeds the 100-line limit required for readability and single-responsibility.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread hooks/useConnectors.ts
@@ -1,6 +1,7 @@
"use client";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Custom agent: Code Structure and Size Limits for Readability and Single Responsibility

File exceeds the 100-line limit required for readability and single-responsibility.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At hooks/useConnectors.ts, line 78:

<comment>File exceeds the 100-line limit required for readability and single-responsibility.</comment>

<file context>
@@ -75,11 +75,15 @@ export function useConnectors(config?: UseConnectorsConfig) {
-        accountId,
-        callbackUrl,
-      });
+      try {
+        return await authorizeConnectorApi(accessToken, {
+          connector,
</file context>

} finally {
setIsDisconnecting(false);
}
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

DRY - is there an existing, shared, hook for managing disconnection of a connector?

Comment on lines +38 to +49
const handleClick = async () => {
if (!accountId || isConnecting) return;
setIsConnecting(true);
try {
const redirectUrl = await authorize("youtube");
if (redirectUrl) {
window.location.href = redirectUrl;
}
} finally {
setIsConnecting(false);
}
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

DRY - is there an existing hook for connecting a connector?

Address sweetman's DRY review feedback on PR #1719: both ConnectYouTubeButton
and YoutubeLogoutButton open-coded the connect/disconnect state machine that
useConnectorHandlers (and ConnectorCard) already provide. Add an optional
onDisconnectSuccess callback to the hook so the logout button can still
invalidate the youtube-channel-info query after a successful disconnect.
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/common/ConnectYouTubeButton.tsx`:
- Around line 29-32: The callbackUrl construction in ConnectYouTubeButton uses
manual string interpolation for query params (callbackUrl, accountId) which can
produce malformed URLs; update the callbackUrl logic in the ConnectYouTubeButton
component to build query parameters with URLSearchParams (or new URL) and append
artist_connected=true and artist_id set to accountId (or empty string) so
artist_id is properly URL-encoded before concatenation; keep the window
origin/pathname usage but replace the template string assembly with
URLSearchParams (or URL) to generate the final URL.

In `@hooks/useConnectors.ts`:
- Around line 60-63: The connector filtering builds allowed = new
Set(slugFilter) but compares against c.slug.toLowerCase(), so mixed-case inputs
in slugFilter (e.g., "YouTube") will fail; update the useMemo in
useConnectors.ts where connectors is computed to normalize slugFilter items to
lower case when building the Set (e.g., map each entry to .toLowerCase() and
then new Set(...)) so membership checks against c.slug.toLowerCase() succeed;
keep the same dependencies [query.data, slugFilter].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ceec2eff-2b68-4553-b1ec-008dbc29a11e

📥 Commits

Reviewing files that changed from the base of the PR and between e916401 and e4c3cf3.

📒 Files selected for processing (5)
  • components/ArtistSetting/StandaloneYoutubeComponent/YoutubeLogoutButton.tsx
  • components/common/ConnectYouTubeButton.tsx
  • hooks/useConnectorHandlers.ts
  • hooks/useConnectors.ts
  • hooks/useYoutubeChannel.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • hooks/useYoutubeChannel.tsx

Comment on lines +29 to +32
callbackUrl:
typeof window !== "undefined"
? `${window.location.origin}${window.location.pathname}?artist_connected=true&artist_id=${accountId ?? ""}`
: undefined,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Build callbackUrl with URLSearchParams instead of manual string concat.

At Line 31, artist_id is interpolated directly into the query string. If accountId contains reserved characters, the callback URL can be malformed.

Proposed fix
       callbackUrl:
         typeof window !== "undefined"
-          ? `${window.location.origin}${window.location.pathname}?artist_connected=true&artist_id=${accountId ?? ""}`
+          ? (() => {
+              const url = new URL(
+                window.location.pathname,
+                window.location.origin,
+              );
+              url.searchParams.set("artist_connected", "true");
+              url.searchParams.set("artist_id", accountId ?? "");
+              return url.toString();
+            })()
           : undefined,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/common/ConnectYouTubeButton.tsx` around lines 29 - 32, The
callbackUrl construction in ConnectYouTubeButton uses manual string
interpolation for query params (callbackUrl, accountId) which can produce
malformed URLs; update the callbackUrl logic in the ConnectYouTubeButton
component to build query parameters with URLSearchParams (or new URL) and append
artist_connected=true and artist_id set to accountId (or empty string) so
artist_id is properly URL-encoded before concatenation; keep the window
origin/pathname usage but replace the template string assembly with
URLSearchParams (or URL) to generate the final URL.

Comment thread hooks/useConnectors.ts
Comment on lines +60 to +63
const connectors = useMemo(() => {
const allowed = new Set(slugFilter);
return (query.data ?? []).filter((c) => allowed.has(c.slug.toLowerCase()));
}, [query.data, slugFilter]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize allowedSlugs before membership checks.

At Line 61, allowedSlugs are added as-is, while connector slugs are lowercased at Line 62. Mixed-case inputs (e.g., "YouTube") will be incorrectly filtered out.

Proposed fix
   const connectors = useMemo(() => {
-    const allowed = new Set(slugFilter);
+    const allowed = new Set(slugFilter.map((slug) => slug.toLowerCase()));
     return (query.data ?? []).filter((c) => allowed.has(c.slug.toLowerCase()));
   }, [query.data, slugFilter]);
📝 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
const connectors = useMemo(() => {
const allowed = new Set(slugFilter);
return (query.data ?? []).filter((c) => allowed.has(c.slug.toLowerCase()));
}, [query.data, slugFilter]);
const connectors = useMemo(() => {
const allowed = new Set(slugFilter.map((slug) => slug.toLowerCase()));
return (query.data ?? []).filter((c) => allowed.has(c.slug.toLowerCase()));
}, [query.data, slugFilter]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useConnectors.ts` around lines 60 - 63, The connector filtering builds
allowed = new Set(slugFilter) but compares against c.slug.toLowerCase(), so
mixed-case inputs in slugFilter (e.g., "YouTube") will fail; update the useMemo
in useConnectors.ts where connectors is computed to normalize slugFilter items
to lower case when building the Set (e.g., map each entry to .toLowerCase() and
then new Set(...)) so membership checks against c.slug.toLowerCase() succeed;
keep the same dependencies [query.data, slugFilter].

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.

sweetmantech and others added 2 commits May 1, 2026 14:47
Why: the formatConnectorName fallback regex inserts a space before
each capital, turning the API's "YouTube" into "You Tube". Add
youtube to the explicit display-name map alongside the other
multi-cap brands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without an explicit metadata entry, the YouTube card showed the
generic "Connect to enable this connector" placeholder. Match the
TikTok/Instagram pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented May 1, 2026

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

@sweetmantech sweetmantech merged commit 8688505 into test May 1, 2026
3 checks passed
@sweetmantech sweetmantech deleted the migrate/youtube-composio branch May 1, 2026 19:58
sweetmantech added a commit that referenced this pull request May 1, 2026
* chore(chat): migrate YouTube connector to Composio

- Add youtube to allowedArtistConnectors so the YouTube card appears in
  the artist settings Connectors tab alongside TikTok/Instagram
- Rewrite useYoutubeChannel to call POST /api/connectors/actions with
  YOUTUBE_GET_CHANNEL_STATISTICS; consume the raw Google channels.list
  response (snippet/statistics/thumbnails) directly, no remapping
- Rewrite useYoutubeStatus to derive connection state from the Composio
  connectors list instead of the legacy channel-info endpoint
- Rewrite ConnectYouTubeButton + YoutubeLogoutButton to use the Composio
  authorize/disconnect flow already used by TikTok/Instagram
- Drop legacy chat-side OAuth surface: /api/youtube/*,
  /api/auth/callback/google, lib/youtube OAuth/token helpers,
  lib/supabase/youtube_tokens, types/youtube.ts, useYouTubeLoginSuccess,
  the four LLM-tool result components for login/channels/playlist/thumb
  (those tools now come from Composio's YouTube toolkit)

Keeps the get_youtube_revenue MCP tool dispatch in ToolComponents and the
matching VercelChat result components — Composio has no YouTube
Analytics action, so revenue stays custom on the api side.

* fix(chat): request snippet+statistics from YOUTUBE_GET_CHANNEL_STATISTICS

Composio's action defaults the `part` parameter to "statistics" only,
so the response had `snippet: null` and the UI rendered without title
or thumbnail. Pass `part: "snippet,statistics"` so the channel name,
description, and thumbnail come back too.

* chore(chat): remove unused ChatInputYoutubeButton + popover

Both components were orphaned — ChatInputYoutubeButton had zero callers,
which made ChatInputYoutubeButtonPopover and its StatCard / PopoverContent
unreachable too. Drop them entirely.

* fix(chat): unwrap Composio envelope in executeConnectorActionApi

api now passes Composio's ToolExecuteResponse through unchanged
({successful, data, error}). Consumer adapter unwraps once so all
chat-side callers get the underlying provider payload directly
(e.g. youtube.channels.list with `items`); upstream failures throw.

* fix(chat): address AI review feedback on youtube migration

- Share connector refresh across useConnectors instances so logout updates
  sibling status (P1: useYoutubeStatus stale after disconnect)
- Disable disconnect button while in-flight to prevent duplicate requests
- Add aria-label to icon-only disconnect button
- Add aria-label to ConnectYouTubeButton for dense (icon-only) mode
- Propagate connector errors from useYoutubeStatus instead of hard-coded null
- Use semantic <span> for static section caption in ChannelInfo
- Provide fallback message in YouTubeRevenueResult when error text missing



* refactor(chat): simplify executeConnectorActionApi envelope handling

The api endpoint always returns Composio's ToolExecuteResponse envelope
(`{ successful, data, error }`) — every Composio Vercel-AI-SDK tool returns
that shape. Drop the defensive non-envelope branch and read the typed shape
directly, removing the `as unknown` casts and inline type guards.



* refactor(chat): React Query for useConnectors + extract fetchYoutubeChannel

- useConnectors now uses React Query so all instances share one cache;
  disconnect/authorize invalidate the connectors key and sibling instances
  re-render automatically. Drops the module-level Set<()=>void> broadcast.
- Extract fetchYoutubeChannel + types to lib/youtube/fetchYoutubeChannel.ts,
  matching the fetchConnectorsApi / authorizeConnectorApi pattern. The hook
  is now ~20 lines and just wires React Query to the helper.



* chore(chat): drop redundant queryFn return-type annotation

fetchConnectorsApi already returns Promise<ConnectorInfo[]>, so TS infers
the queryFn type correctly without the explicit annotation.



* fix(chat): restore authorize catch to honor Promise<string | null> contract

Dropped during the React Query refactor — without the catch, an API failure
rejects the promise instead of returning null, which the only caller
(ConnectYouTubeButton) doesn't handle.



* fix(chat): gate useYoutubeChannel on Privy authenticated flag

Matches the codebase convention (useTaskRunStatus, useCatalogs, useArtistPosts,
etc.) — without it, the query runs and immediately throws "Not authenticated"
when the user isn't signed in.



* refactor(chat): use shared useConnectorHandlers in YouTube buttons

Address sweetman's DRY review feedback on PR #1719: both ConnectYouTubeButton
and YoutubeLogoutButton open-coded the connect/disconnect state machine that
useConnectorHandlers (and ConnectorCard) already provide. Add an optional
onDisconnectSuccess callback to the hook so the logout button can still
invalidate the youtube-channel-info query after a successful disconnect.

* fix(chat): display "YouTube" as one word in connectors UI

Why: the formatConnectorName fallback regex inserts a space before
each capital, turning the API's "YouTube" into "You Tube". Add
youtube to the explicit display-name map alongside the other
multi-cap brands.



* fix(chat): add YouTube connector description

Without an explicit metadata entry, the YouTube card showed the
generic "Connect to enable this connector" placeholder. Match the
TikTok/Instagram pattern.



---------

Co-authored-by: Arpit Gupta <arpitgupta1214@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@desiorac
Copy link
Copy Markdown

desiorac commented May 4, 2026

executeConnectorActionApi cleanly centralizes Composio dispatch. One edge case: return result.data as T silently passes undefined to callers when Composio responds successful: true with no data (e.g., unlinked account). Adding if (result.data == null) throw new Error("Empty connector response") before return makes the failure explicit rather than surfacing as a downstream null deref.

Also, onDisconnectSuccess invalidating ["youtube-channel-info"] is a clean pattern for derived cache invalidation, worth carrying forward when other connectors add their own query keys.

sweetmantech added a commit that referenced this pull request May 6, 2026
* chore(chat): migrate YouTube connector to Composio (#1719)

* chore(chat): migrate YouTube connector to Composio

- Add youtube to allowedArtistConnectors so the YouTube card appears in
  the artist settings Connectors tab alongside TikTok/Instagram
- Rewrite useYoutubeChannel to call POST /api/connectors/actions with
  YOUTUBE_GET_CHANNEL_STATISTICS; consume the raw Google channels.list
  response (snippet/statistics/thumbnails) directly, no remapping
- Rewrite useYoutubeStatus to derive connection state from the Composio
  connectors list instead of the legacy channel-info endpoint
- Rewrite ConnectYouTubeButton + YoutubeLogoutButton to use the Composio
  authorize/disconnect flow already used by TikTok/Instagram
- Drop legacy chat-side OAuth surface: /api/youtube/*,
  /api/auth/callback/google, lib/youtube OAuth/token helpers,
  lib/supabase/youtube_tokens, types/youtube.ts, useYouTubeLoginSuccess,
  the four LLM-tool result components for login/channels/playlist/thumb
  (those tools now come from Composio's YouTube toolkit)

Keeps the get_youtube_revenue MCP tool dispatch in ToolComponents and the
matching VercelChat result components — Composio has no YouTube
Analytics action, so revenue stays custom on the api side.

* fix(chat): request snippet+statistics from YOUTUBE_GET_CHANNEL_STATISTICS

Composio's action defaults the `part` parameter to "statistics" only,
so the response had `snippet: null` and the UI rendered without title
or thumbnail. Pass `part: "snippet,statistics"` so the channel name,
description, and thumbnail come back too.

* chore(chat): remove unused ChatInputYoutubeButton + popover

Both components were orphaned — ChatInputYoutubeButton had zero callers,
which made ChatInputYoutubeButtonPopover and its StatCard / PopoverContent
unreachable too. Drop them entirely.

* fix(chat): unwrap Composio envelope in executeConnectorActionApi

api now passes Composio's ToolExecuteResponse through unchanged
({successful, data, error}). Consumer adapter unwraps once so all
chat-side callers get the underlying provider payload directly
(e.g. youtube.channels.list with `items`); upstream failures throw.

* fix(chat): address AI review feedback on youtube migration

- Share connector refresh across useConnectors instances so logout updates
  sibling status (P1: useYoutubeStatus stale after disconnect)
- Disable disconnect button while in-flight to prevent duplicate requests
- Add aria-label to icon-only disconnect button
- Add aria-label to ConnectYouTubeButton for dense (icon-only) mode
- Propagate connector errors from useYoutubeStatus instead of hard-coded null
- Use semantic <span> for static section caption in ChannelInfo
- Provide fallback message in YouTubeRevenueResult when error text missing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(chat): simplify executeConnectorActionApi envelope handling

The api endpoint always returns Composio's ToolExecuteResponse envelope
(`{ successful, data, error }`) — every Composio Vercel-AI-SDK tool returns
that shape. Drop the defensive non-envelope branch and read the typed shape
directly, removing the `as unknown` casts and inline type guards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(chat): React Query for useConnectors + extract fetchYoutubeChannel

- useConnectors now uses React Query so all instances share one cache;
  disconnect/authorize invalidate the connectors key and sibling instances
  re-render automatically. Drops the module-level Set<()=>void> broadcast.
- Extract fetchYoutubeChannel + types to lib/youtube/fetchYoutubeChannel.ts,
  matching the fetchConnectorsApi / authorizeConnectorApi pattern. The hook
  is now ~20 lines and just wires React Query to the helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(chat): drop redundant queryFn return-type annotation

fetchConnectorsApi already returns Promise<ConnectorInfo[]>, so TS infers
the queryFn type correctly without the explicit annotation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(chat): restore authorize catch to honor Promise<string | null> contract

Dropped during the React Query refactor — without the catch, an API failure
rejects the promise instead of returning null, which the only caller
(ConnectYouTubeButton) doesn't handle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(chat): gate useYoutubeChannel on Privy authenticated flag

Matches the codebase convention (useTaskRunStatus, useCatalogs, useArtistPosts,
etc.) — without it, the query runs and immediately throws "Not authenticated"
when the user isn't signed in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(chat): use shared useConnectorHandlers in YouTube buttons

Address sweetman's DRY review feedback on PR #1719: both ConnectYouTubeButton
and YoutubeLogoutButton open-coded the connect/disconnect state machine that
useConnectorHandlers (and ConnectorCard) already provide. Add an optional
onDisconnectSuccess callback to the hook so the logout button can still
invalidate the youtube-channel-info query after a successful disconnect.

* fix(chat): display "YouTube" as one word in connectors UI

Why: the formatConnectorName fallback regex inserts a space before
each capital, turning the API's "YouTube" into "You Tube". Add
youtube to the explicit display-name map alongside the other
multi-cap brands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(chat): add YouTube connector description

Without an explicit metadata entry, the YouTube card showed the
generic "Connect to enable this connector" placeholder. Match the
TikTok/Instagram pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Sweets Sweetman <sweetmantech@gmail.com>

* Remove deprecated Stripe session handling and refactor checkout session creation to use access tokens. Update subscription handling in the useSubscribeClick hook to ensure proper authentication flow. (#1728)

---------

Co-authored-by: Arpit Gupta <arpitgupta1214@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: ahmednahima0-beep <ahmednahima0@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants