Skip to content

feat(api): migrate GET /api/ai/models#491

Merged
sweetmantech merged 20 commits into
testfrom
migrate/misc-reads-group1
Apr 30, 2026
Merged

feat(api): migrate GET /api/ai/models#491
sweetmantech merged 20 commits into
testfrom
migrate/misc-reads-group1

Conversation

@arpitgupta1214
Copy link
Copy Markdown
Collaborator

@arpitgupta1214 arpitgupta1214 commented Apr 28, 2026

Summary

Adds api parity for chat's /api/ai/models so the chat-side cutover can land.

Test plan

  • GET /api/ai/models returns the same model catalog as chat production on the Vercel preview.
  • pnpm lint and pnpm test are green.

…annel-info)

Adds api parity for chat's /api/email, /api/ai/models, /api/youtube/channel-info
ahead of the chat-side cutover.

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

vercel Bot commented Apr 28, 2026

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

Project Deployment Actions Updated (UTC)
api Ready Ready Preview Apr 30, 2026 7:36pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • package.json is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml and included by none

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d2596b13-28d0-4df2-abb4-40719d87b8ad

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds two new API endpoints (AI models and YouTube channel-info) and supporting libraries for retrieving available models, validating and refreshing YouTube OAuth tokens, persisting tokens to Supabase, and request validation with CORS-enabled responses.

Changes

Cohort / File(s) Summary
AI Models API
app/api/ai/models/route.ts, lib/ai/getAvailableModelsHandler.ts
New GET and OPTIONS route returning available AI models via getAvailableModelsHandler; includes CORS headers, error logging, and forced dynamic/no-store behavior.
YouTube Channel Info API
app/api/youtube/channel-info/route.ts, lib/youtube/getYouTubeChannelHandler.ts, lib/youtube/validateYouTubeChannelInfoRequest.ts
New GET and OPTIONS route that validates requests, checks/refreshes tokens, and proxies channel info; validation short-circuits with CORS-enabled error responses.
YouTube Token Validation & Refresh
lib/youtube/validateYouTubeTokens.ts, lib/youtube/refreshStoredYouTubeToken.ts
Load stored tokens, detect expiry, refresh via OAuth when needed, convert expiry to ISO expires_at, and propagate errors for re-auth flows.
Supabase Token Persistence
lib/supabase/youtube_tokens/upsertYouTubeTokens.ts
New upsertYouTubeTokens helper that upserts token rows using artist_account_id conflict key and returns the persisted row or null on failure.
AI Models Data
lib/ai/getAvailableModels.ts
Adjusts model fetching to destructure models from gateway response, logs errors, and returns an empty array on failure (removed explicit TS return type).

Sequence Diagrams

sequenceDiagram
    participant Client
    participant API as GET /api/ai/models
    participant Handler as getAvailableModelsHandler
    participant Models as getAvailableModels

    Client->>API: GET /api/ai/models
    API->>Handler: handle request
    Handler->>Models: fetch available models
    Models-->>Handler: { models } or error
    Handler-->>API: JSON { models } / { message } + CORS
    API-->>Client: HTTP response
Loading
sequenceDiagram
    participant Client
    participant API as GET /api/youtube/channel-info
    participant Validate as validateYouTubeChannelInfoRequest
    participant TokenVal as validateYouTubeTokens
    participant DB as YouTube Tokens DB
    participant Refresh as refreshStoredYouTubeToken
    participant Handler as getYouTubeChannelHandler
    participant YouTube as YouTube Data API

    Client->>API: GET /api/youtube/channel-info?artist_account_id=...
    API->>Validate: validate auth & query
    Validate->>TokenVal: request token validation for artist_account_id
    TokenVal->>DB: select stored tokens
    DB-->>TokenVal: stored token row / none
    alt token expired & has refresh_token
        TokenVal->>Refresh: refreshStoredYouTubeToken
        Refresh->>YouTube: OAuth refresh
        YouTube-->>Refresh: new credentials
        Refresh->>DB: upsert updated tokens
        DB-->>Refresh: confirmation
        Refresh-->>TokenVal: refreshed tokens
    end
    TokenVal-->>Validate: resolved tokens
    Validate-->>API: validated params + tokens
    API->>Handler: fetch channel info with tokens
    Handler->>YouTube: fetch channel data
    YouTube-->>Handler: channel data / error
    Handler-->>API: JSON { status, channels } / error + CORS
    API-->>Client: HTTP response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • sweetmantech

Poem

🎵 New routes hum, tokens spin anew,
Models listed, channels come through,
Refresh and upsert keep secrets bright,
CORS waves open paths for light,
Backend gears sing — small wins in view.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning Pull request violates SOLID and Clean Code principles: unresolved review issues mask errors and expose sensitive data; SRP violations with validateYouTubeChannelInfoRequest combining 5+ responsibilities; handlers exceed 20-line guideline; DRY violations with CORS headers and error responses repeated 7+ times; hardcoded status codes instead of constants. Fix four flagged review issues immediately. Extract CORS-wrapped response helpers to eliminate duplication. Split validateYouTubeChannelInfoRequest into separate concerns. Create constants for HTTP status codes and error messages. Decompose handlers to stay under 20 lines.
✅ 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/misc-reads-group1

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

9 issues found across 19 files

Confidence score: 3/5

  • There is concrete user-facing risk in several handlers (lib/ai/getAvailableModelsHandler.ts, lib/email/trackEmailHandler.ts, lib/youtube/getYouTubeChannelHandler.ts) that return raw exception text in 500 responses, which can leak internal system details.
  • Related tests (lib/ai/__tests__/getAvailableModelsHandler.test.ts, lib/youtube/__tests__/getYouTubeChannelHandler.test.ts) currently enforce that leakage behavior, so the unsafe response pattern is likely to persist unless both code and assertions are updated together.
  • This is not necessarily a merge blocker, but the combination of multiple high-severity/high-confidence findings (plus the GET-vs-POST mutation issue in lib/email/trackEmailHandler.ts) raises meaningful regression and API-contract risk.
  • Pay close attention to lib/ai/getAvailableModelsHandler.ts, lib/email/trackEmailHandler.ts, lib/youtube/getYouTubeChannelHandler.ts, lib/ai/__tests__/getAvailableModelsHandler.test.ts, and lib/youtube/__tests__/getYouTubeChannelHandler.test.ts - align error handling to generic 500 messages and ensure tests no longer codify exception leakage.
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="lib/email/trackEmailHandler.ts">

<violation number="1" location="lib/email/trackEmailHandler.ts:13">
P2: Custom agent: **API Design Consistency and Maintainability**

State-changing contact tracking is exposed via GET instead of POST, violating the API method requirement for mutations.</violation>

<violation number="2" location="lib/email/trackEmailHandler.ts:42">
P1: Do not return raw exception messages in API responses; return a generic server-error message instead.

(Based on your team's feedback about preventing internal exception leakage in error responses.) [FEEDBACK_USED]</violation>
</file>

<file name="lib/youtube/youtubeErrors.ts">

<violation number="1" location="lib/youtube/youtubeErrors.ts:44">
P3: Custom agent: **Module should export a single primary function whose name matches the filename**

Primary exported function name does not match the file basename (`youtubeErrors` vs `buildYouTubeUtilityError`).</violation>
</file>

<file name="lib/email/loopsClient.ts">

<violation number="1" location="lib/email/loopsClient.ts:7">
P2: Custom agent: **Module should export a single primary function whose name matches the filename**

Module exports a singleton `loopsClient` instance instead of a single primary function matching the filename, which conflicts with the module-export rule.</violation>
</file>

<file name="lib/youtube/__tests__/getYouTubeChannelHandler.test.ts">

<violation number="1" location="lib/youtube/__tests__/getYouTubeChannelHandler.test.ts:1">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

Test file exceeds the repository’s 100-line file-length limit.</violation>

<violation number="2" location="lib/youtube/__tests__/getYouTubeChannelHandler.test.ts:44">
P1: This test currently codifies leaking raw exception text (`details: "db dead"`) in API responses. Expect a generic internal error message instead and assert exception text is not exposed.

(Based on your team's feedback about never returning raw exception messages in API 500 responses.) [FEEDBACK_USED]</violation>
</file>

<file name="lib/ai/__tests__/getAvailableModelsHandler.test.ts">

<violation number="1" location="lib/ai/__tests__/getAvailableModelsHandler.test.ts:40">
P2: This test locks in returning raw exception text in a 500 response. Use a fixed generic message so internal error details are not exposed to API clients.

(Based on your team's feedback about not exposing raw exception messages in 500 responses.) [FEEDBACK_USED]</violation>
</file>

<file name="lib/ai/getAvailableModelsHandler.ts">

<violation number="1" location="lib/ai/getAvailableModelsHandler.ts:23">
P1: Do not return raw exception messages in 500 responses; this leaks internal error details to clients. Return a fixed generic message instead.

(Based on your team's feedback about not exposing exception text in 500 API responses.) [FEEDBACK_USED]</violation>
</file>

<file name="lib/youtube/getYouTubeChannelHandler.ts">

<violation number="1" location="lib/youtube/getYouTubeChannelHandler.ts:77">
P1: Do not expose raw exception messages in API responses; return a fixed generic error string instead.

(Based on your team's feedback about not exposing raw exception details in API responses.) [FEEDBACK_USED]</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Client as Client (Chat UI)
    participant API as API Route Handler
    participant Loops as Loops.so API
    participant AI as AI Model Gateway
    participant DB as Supabase (youtube_tokens)
    participant Google as Google/YouTube API

    Note over Client, Google: NEW: Chat Parity API Migration

    %% Flow 1: Email Tracking
    rect rgb(240, 240, 240)
    Note right of Client: GET /api/email
    Client->>API: trackEmail(email)
    API->>API: NEW: validateTrackEmailQuery()
    API->>Loops: NEW: loopsClient.updateContact()
    Loops-->>API: { success, id, message }
    API-->>Client: { success, message, id }
    end

    %% Flow 2: AI Models Catalog
    rect rgb(230, 230, 230)
    Note right of Client: GET /api/ai/models
    Client->>API: getAvailableModels()
    API->>AI: NEW: getAvailableModels()
    AI-->>API: Model list
    API->>API: Filter embed models
    API-->>Client: { models }
    end

    %% Flow 3: YouTube Channel Info
    rect rgb(220, 220, 220)
    Note right of Client: GET /api/youtube/channel-info
    Client->>API: getYouTubeChannelInfo(artist_id)
    API->>API: NEW: validateYouTubeChannelQuery()
    API->>DB: NEW: selectYouTubeTokens(artist_id)
    DB-->>API: Token record

    alt Token Expired
        API->>Google: NEW: refreshAccessToken(refresh_token)
        Google-->>API: New access_token
        API->>DB: NEW: upsertYouTubeTokens(new_tokens)
    else Invalid/Missing Tokens
        API-->>Client: 200 { success: false, tokenStatus: "invalid" }
    end

    opt Token is Valid (or refreshed)
        API->>Google: NEW: fetchYouTubeChannelInfo(access_token)
        alt API Success
            Google-->>API: Channel metadata
            API-->>Client: { success: true, channels, tokenStatus: "valid" }
        else API Error
            Google-->>API: Error response
            API-->>Client: { success: false, error, tokenStatus: "api_error" }
        end
    end
    end
Loading

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

Comment thread lib/ai/getAvailableModelsHandler.ts Outdated
Comment thread lib/youtube/__tests__/getYouTubeChannelHandler.test.ts Outdated
Comment thread lib/email/trackEmailHandler.ts Outdated
Comment thread lib/youtube/getYouTubeChannelHandler.ts Outdated
Comment thread lib/email/trackEmailHandler.ts Outdated
Comment thread lib/email/loopsClient.ts Outdated
Comment thread lib/youtube/__tests__/getYouTubeChannelHandler.test.ts Outdated
Comment thread lib/ai/__tests__/getAvailableModelsHandler.test.ts Outdated
Comment thread lib/youtube/buildYouTubeUtilityError.ts Outdated
* @param message - The human-readable error message.
* @returns A YouTubeUtilityError object.
*/
export function buildYouTubeUtilityError(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Custom agent: Module should export a single primary function whose name matches the filename

Primary exported function name does not match the file basename (youtubeErrors vs buildYouTubeUtilityError).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/youtube/youtubeErrors.ts, line 44:

<comment>Primary exported function name does not match the file basename (`youtubeErrors` vs `buildYouTubeUtilityError`).</comment>

<file context>
@@ -0,0 +1,52 @@
+ * @param message - The human-readable error message.
+ * @returns A YouTubeUtilityError object.
+ */
+export function buildYouTubeUtilityError(
+  code: YouTubeUtilityErrorCode,
+  message: string,
</file context>

- updateContact: switch to loops v6 object-arg signature (fixes Vercel build)
- handlers: stop leaking raw exception text in 500 responses
- loopsClient: convert singleton to factory function matching filename
- youtubeErrors: align export name with filename
- getYouTubeChannelHandler: explicit boolean discriminator narrowing for build

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.

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

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

Email tracking upserts a Loops contact — a write — so it should not be
exposed as GET with email in query params (PII in URLs, cacheable
responses). Switches to POST with `{ email }` JSON body.

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="app/api/email/route.ts">

<violation number="1" location="app/api/email/route.ts:27">
P1: This route no longer handles GET requests, which breaks the documented `/api/email` GET parity and will return 405 for existing callers.</violation>
</file>

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

Comment thread app/api/email/route.ts
Loops is no longer used; the email tracking endpoint is removed
from this migration entirely.

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.

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

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

- Fold token validation into validateYouTubeChannelInfoRequest so the
  handler is a thin fetch+respond orchestrator
- Rename validateYouTubeChannelQuery → validateYouTubeChannelInfoRequest
  (matches validateArtistRequest / validateChatRequest convention)
- Drop buildYouTubeUtilityError + error code catalog: every token-level
  failure collapses to the same {success:false, tokenStatus:"invalid"}
  response, so the typed codes carried no information out

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 8 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="lib/youtube/__tests__/validateYouTubeChannelInfoRequest.test.ts">

<violation number="1" location="lib/youtube/__tests__/validateYouTubeChannelInfoRequest.test.ts:1">
P3: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

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

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

Comment thread lib/youtube/__tests__/validateYouTubeChannelInfoRequest.test.ts Outdated
- refreshStoredYouTubeToken now throws on every failure (no more
  catch-log-return-null); the deep invalid_grant type guard is gone
  since the general console.error already logs the full error
- validateYouTubeTokens lets errors propagate; null is reserved for
  the legitimate "no tokens row / no refresh_token" cases
- validateYouTubeChannelInfoRequest is the single catch boundary;
  thrown errors and null both collapse to the same tokenStatus:invalid
  response, matching chat parity

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.

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

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

TS inference already produces the same types for these helpers; explicit
annotations were noise. Kept annotations on discriminated-union returns
(validators, route handlers) and anywhere inference would widen.

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.

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

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

Continues 7f64027 — TS inference produces the same types for these
helpers; explicit annotations were noise. Kept the discriminated-union
annotation on validateYouTubeChannelInfoRequest where it documents an
intentional contract.

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.

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

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

- drop response fields that no chat consumer reads
- validateYouTubeTokens throws on every unusable case; the request
  validator's catch is the single failure boundary (no more let/null)
- drop now-unnecessary explicit return types

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.

4 issues 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="lib/youtube/__tests__/getYouTubeChannelHandler.test.ts">

<violation number="1" location="lib/youtube/__tests__/getYouTubeChannelHandler.test.ts:61">
P2: These assertions removed `tokenStatus` from the expected response, so the tests no longer enforce the endpoint response contract.</violation>
</file>

<file name="lib/youtube/getYouTubeChannelHandler.ts">

<violation number="1" location="lib/youtube/getYouTubeChannelHandler.ts:35">
P1: The handler removed `tokenStatus` from its JSON payloads, which breaks the documented `/api/youtube/channel-info` response contract and removes state needed by clients to branch on token validity vs API failure.</violation>
</file>

<file name="lib/youtube/validateYouTubeChannelInfoRequest.ts">

<violation number="1" location="lib/youtube/validateYouTubeChannelInfoRequest.ts:33">
P2: Missing-param responses no longer include `tokenStatus`, breaking the documented `/api/youtube/channel-info` response contract.</violation>

<violation number="2" location="lib/youtube/validateYouTubeChannelInfoRequest.ts:50">
P1: Token validation failures now omit `tokenStatus`, making auth failures indistinguishable from generic channel fetch failures.</violation>
</file>

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

Comment thread lib/youtube/getYouTubeChannelHandler.ts Outdated
Comment thread lib/youtube/validateYouTubeChannelInfoRequest.ts Outdated
Comment thread lib/youtube/__tests__/getYouTubeChannelHandler.test.ts Outdated
Comment thread lib/youtube/validateYouTubeChannelInfoRequest.ts Outdated
- Drop `success` from /api/youtube/channel-info; conform to the
  `{ status: "success", channels }` envelope used across the rest of
  the api (lib/networking/successResponse.ts, songs, posts, accounts,
  chats, artists). Clients infer "needs re-auth" from
  `channels === null`.
- Keep only validator + handler tests; cover no-token, expired-no-refresh,
  refresh-failure, and db-update-failure cases at the validator boundary
  via it.each on the thrown-error contract.
- Trim jsdocs to information-bearing lines only; drop stale
  "mirrors chat" notes and self-evident @param/@returns lines on lib
  helpers.
- Dedupe YouTubeTokensRow: keep the export in validateYouTubeTokens.ts
  (the contract owner) and import it in refreshStoredYouTubeToken.ts.

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

cubic-dev-ai Bot commented Apr 29, 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.

The SDK's getAvailableModels() rejects valid responses with a Zod error
("expected error.object"), which silenced 194 models behind an empty
array. Match chat's direct fetch to /v1/ai/config — same approach,
same payload, same parity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 3.x SDK requires specificationVersion:"v3" via a strict Zod literal,
but the live /v1/ai/config endpoint still emits "v2" descriptors. Pin
to 2.0.83 (latest 2.x, expects "v2") so gateway.getAvailableModels()
works as designed. This is a catalog-read-only consumer; api never uses
gateway() as a model factory, so 2.x's LanguageModelV2 surface doesn't
collide with the rest of the codebase on @ai-sdk/provider@3.

Restore the SDK call site (no more direct fetch hack); a comment
flags when to bump back to 3.x.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arpitgupta1214 and others added 2 commits April 30, 2026 04:01
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arpitgupta1214 arpitgupta1214 changed the title feat(api): migrate GET /api/email, /api/ai/models, /api/youtube/channel-info feat(api): migrate GET /api/ai/models, GET /api/youtube/channel-info Apr 29, 2026
arpitgupta1214 and others added 2 commits April 30, 2026 04:24
Layers in validateAuthContext + checkAccountArtistAccess so anonymous
callers can no longer probe stored YouTube tokens by guessing UUIDs.
Returns 401 on missing/invalid auth, 403 when the authed caller has no
access to the requested artist.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
lib/youtube/getYouTubeChannelHandler.ts (1)

17-48: ⚡ Quick win

Refactor the handler into smaller helpers to meet function-size and SRP guidelines.

This function currently handles validation orchestration, upstream invocation, and response mapping in one >20-line block. Splitting error/response mapping into helpers will make this easier to maintain and test.
As per coding guidelines, "Flag functions longer than 20 lines" and "Apply Single Responsibility Principle (SRP): one exported function per file; each file should do one thing well".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/youtube/getYouTubeChannelHandler.ts` around lines 17 - 48, Split
getYouTubeChannelHandler into a thin orchestration that calls small non-exported
helpers: move response mapping into a helper like
mapChannelSuccessResponse(channelData) that returns the NextResponse with
getCorsHeaders(), move error mapping into mapChannelErrorResponse(statusCode?)
or handleChannelError(error) that logs and returns the 502 JSON response, and
move any token parsing into a small helper (e.g., extractTokens(validated)) so
the handler only validates, invokes fetchYouTubeChannelInfo, then delegates to
these helpers; keep validateYouTubeChannelInfoRequest and
fetchYouTubeChannelInfo calls unchanged and ensure only getYouTubeChannelHandler
remains exported from this file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/ai/getAvailableModels.ts`:
- Around line 12-15: The catch block in getAvailableModels (the function
handling the gateway fetch) currently logs errors and returns an empty array,
which masks upstream failures; change it to preserve failure semantics by either
removing the try/catch so the error bubbles to the caller, or re-throw the
caught error after logging (e.g., log via console.error and then throw error) so
the handler can perform proper HTTP mapping instead of silently returning [].

In `@lib/youtube/getYouTubeChannelHandler.ts`:
- Line 42: Replace the raw error logging in getYouTubeChannelHandler that
currently does console.error("Error in YouTube channel info API:", error) with a
sanitized log containing only non-sensitive fields (e.g., error.message,
error.name and any safe error.code or status) to avoid leaking OAuth tokens or
request metadata; locate the console.error call in getYouTubeChannelHandler and
update it to construct a safe message (include a short context string plus the
selected sanitized fields) and log that instead (use the existing logger if
available, otherwise console.error) so no raw error object is emitted.
- Line 26: The code sets refreshToken to an empty string which can be
interpreted as an invalid credential; change the assignment in
getYouTubeChannelHandler (where refreshToken: validated.tokens.refresh_token ||
"") to pass undefined when there is no refresh token so fetchYouTubeChannelInfo
receives an absent optional value (e.g., set refreshToken to
validated.tokens.refresh_token ?? undefined or conditionally include the
property) — update the refreshToken property at the call site in
getYouTubeChannelHandler.ts accordingly.

In `@lib/youtube/validateYouTubeTokens.ts`:
- Around line 13-17: The code treats any null from selectYouTubeTokens as
“tokens not found”, but selectYouTubeTokens currently returns null for both
missing rows and DB/query errors; update selectYouTubeTokens to throw on actual
query failures (or return a distinct error result) and return null only when no
row exists, then update validateYouTubeTokens (the branch using storedTokens for
artist_account_id) to catch/re-throw DB errors as 5xx (or let the thrown error
bubble) and only throw the 401-style "youtube tokens not found" when
selectYouTubeTokens legitimately returns null; use the function names
selectYouTubeTokens and validateYouTubeTokens and the storedTokens variable to
locate the changes.

---

Nitpick comments:
In `@lib/youtube/getYouTubeChannelHandler.ts`:
- Around line 17-48: Split getYouTubeChannelHandler into a thin orchestration
that calls small non-exported helpers: move response mapping into a helper like
mapChannelSuccessResponse(channelData) that returns the NextResponse with
getCorsHeaders(), move error mapping into mapChannelErrorResponse(statusCode?)
or handleChannelError(error) that logs and returns the 502 JSON response, and
move any token parsing into a small helper (e.g., extractTokens(validated)) so
the handler only validates, invokes fetchYouTubeChannelInfo, then delegates to
these helpers; keep validateYouTubeChannelInfoRequest and
fetchYouTubeChannelInfo calls unchanged and ensure only getYouTubeChannelHandler
remains exported from this file.
🪄 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: 3625b627-e8a0-49b2-b018-49841d6c7e7e

📥 Commits

Reviewing files that changed from the base of the PR and between 8b46485 and 020a1b2.

⛔ Files ignored due to path filters (5)
  • lib/ai/__tests__/getAvailableModels.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/youtube/__tests__/getYouTubeChannelHandler.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/youtube/__tests__/validateYouTubeChannelInfoRequest.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • package.json is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml and included by none
📒 Files selected for processing (5)
  • lib/ai/getAvailableModels.ts
  • lib/youtube/getYouTubeChannelHandler.ts
  • lib/youtube/refreshStoredYouTubeToken.ts
  • lib/youtube/validateYouTubeChannelInfoRequest.ts
  • lib/youtube/validateYouTubeTokens.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/youtube/validateYouTubeChannelInfoRequest.ts
  • lib/youtube/refreshStoredYouTubeToken.ts

Comment on lines +12 to 15
} catch (error) {
console.error("[getAvailableModels] gateway fetch failed:", error);
return [];
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve failure semantics instead of returning an empty catalog on gateway errors.

At Line 14, return [] converts upstream failures into a false-success response path, which can hide outages and bypass intended handler-level error mapping. Re-throw after logging (or remove this catch and let the handler own HTTP translation).

Suggested fix
 export const getAvailableModels = async () => {
   try {
     const { models } = await gateway.getAvailableModels();
     return models.filter(m => !isEmbedModel(m));
   } catch (error) {
     console.error("[getAvailableModels] gateway fetch failed:", error);
-    return [];
+    throw error;
   }
 };

As per coding guidelines, "For domain functions, ensure: ... Proper error handling".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/ai/getAvailableModels.ts` around lines 12 - 15, The catch block in
getAvailableModels (the function handling the gateway fetch) currently logs
errors and returns an empty array, which masks upstream failures; change it to
preserve failure semantics by either removing the try/catch so the error bubbles
to the caller, or re-throw the caught error after logging (e.g., log via
console.error and then throw error) so the handler can perform proper HTTP
mapping instead of silently returning [].

Comment thread lib/youtube/getYouTubeChannelHandler.ts Outdated
Comment thread lib/youtube/getYouTubeChannelHandler.ts Outdated
Comment thread lib/youtube/validateYouTubeTokens.ts Outdated
Comment on lines +13 to +17
const storedTokens = await selectYouTubeTokens(artist_account_id);

if (!storedTokens) {
throw new Error("youtube tokens not found");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Differentiate missing token rows from database read failures.

selectYouTubeTokens returns null for both “row not found” and query errors (see lib/supabase/youtube_tokens/selectYouTubeTokens.ts:10-23), but this branch throws a single “not found” error. Downstream, that collapses operational DB failures into 401 re-auth responses instead of a 5xx path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/youtube/validateYouTubeTokens.ts` around lines 13 - 17, The code treats
any null from selectYouTubeTokens as “tokens not found”, but selectYouTubeTokens
currently returns null for both missing rows and DB/query errors; update
selectYouTubeTokens to throw on actual query failures (or return a distinct
error result) and return null only when no row exists, then update
validateYouTubeTokens (the branch using storedTokens for artist_account_id) to
catch/re-throw DB errors as 5xx (or let the thrown error bubble) and only throw
the 401-style "youtube tokens not found" when selectYouTubeTokens legitimately
returns null; use the function names selectYouTubeTokens and
validateYouTubeTokens and the storedTokens variable to locate the changes.

YouTube channel-info will migrate via Composio in a separate PR.
Reduces Group 1 scope to just /api/ai/models.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arpitgupta1214 arpitgupta1214 changed the title feat(api): migrate GET /api/ai/models, GET /api/youtube/channel-info feat(api): migrate GET /api/ai/models Apr 29, 2026
@arpitgupta1214
Copy link
Copy Markdown
Collaborator Author

Browser-verified smoke (chat preview → api preview)

Chat preview at recoup-chat-git-migrate-misc-reads-group1-recoupable-ad724970.vercel.app was overridden to hit this PR's api preview via sessionStorage.setItem("recoup_api_override", "<api-preview-url>") + reload.

  • Network: GET https://api-git-migrate-misc-reads-group1-recoupable-ad724970.vercel.app/api/ai/models → 200
  • Response: 194 models (matches chat.recoupable.com/api/ai/models exactly)
  • Model picker dropdown rendered all 194 entries with names, descriptions, and New/Fast tags. First five: GPT-5.2 (New), GPT-5.4 Mini (Fast), Claude Opus 4.5 (New), Claude Sonnet 4.5, Gemini 2.5 Flash (Fast).

CLI smoke for the validation/error paths is also clean:

  • GET /api/ai/models → 200, { models: [...194 entries] }
  • GET /api/youtube/channel-info → 404 (intentionally — that endpoint was reverted out of this PR; migrating via Composio in a follow-up).

@sweetmantech
Copy link
Copy Markdown
Contributor

Manual verification on preview deployment

Tested GET /api/ai/models against https://api-git-migrate-misc-reads-group1-recoupable-ad724970.vercel.app. PR's stated goal — "returns the same model catalog as chat production" — is satisfied at the model-id level.

Test cases

# Case Expected Actual
1 OPTIONS preflight 200 + CORS headers 200 with access-control-allow-origin: *, methods GET POST PUT DELETE OPTIONS PATCH, allow-headers includes x-api-key
2 GET (unauthenticated) 200 {models: [...]} 200, payload size 100147 bytes ✓
3 Model count matches chat 194 models
4 Embed-model filter none in response 0 embed/embedding models ✓
5 Provider coverage 22 providers alibaba, amazon, anthropic, arcee-ai, bytedance, cohere, deepseek, google, inception, interfaze, kwaipilot, meta, minimax, mistral, moonshotai, morph, nvidia, openai, prime-intellect, xai, xiaomi, zai
6 Model-id parity vs https://chat.recoupable.com/api/ai/models identical id sets 194/194 ids match — zero diff in either direction

Schema gap (not blocking)

Chat prod payload is 121563 bytes, api preview is 100147 bytes — same model ids, ~21 KB difference. Per-model object diff:

api keys : ['description', 'id', 'modelType', 'name', 'pricing', 'specification']
chat keys: ['description', 'id', 'modelType', 'name', 'pricing', 'specification', 'tags']
only in chat: ['tags']

Root cause:

Repo @ai-sdk/gateway version
chat ^3.0.96
api 2.0.83

The 3.x client returns a tags field per model that 2.x doesn't. Not a logic gap in this PR — just a transitive consequence of the older gateway version on api.

Functional impact on the chat-side cutover: none. Chat's useAvailableModels hook (hooks/useAvailableModels.ts) types the response as GatewayLanguageModelEntry[] from the AI SDK and grepping the chat repo, no consumer reads model.tags (the .tags references are all on Agent objects in components/Agents/*, which is a different schema). So the cutover where chat's frontend calls api's endpoint instead of chat's own will work.

Optional follow-up if strict byte-parity is desired: bump api's @ai-sdk/gateway to ^3.0.x so the per-model field set matches exactly.

Sample data

First model in api response:

{ "id": "alibaba/qwen-3-14b", "name": "Qwen3-14B" }

Same id appears at the same position in chat prod (sorted by gateway), confirming consistent ordering. You can re-run the comparison yourself:

PREVIEW="https://api-git-migrate-misc-reads-group1-recoupable-ad724970.vercel.app"
diff <(curl -sS "$PREVIEW/api/ai/models" | jq -r '.models[].id' | sort) \
     <(curl -sS "https://chat.recoupable.com/api/ai/models" | jq -r '.models[].id' | sort)
# expected: empty diff

@sweetmantech sweetmantech merged commit 8774759 into test Apr 30, 2026
6 checks passed
@sweetmantech sweetmantech deleted the migrate/misc-reads-group1 branch April 30, 2026 19:38
sweetmantech added a commit that referenced this pull request Apr 30, 2026
* Migrate stripe subscription checkout sessions (#493)

* chore: update Prettier configuration and add new dependencies

- Added "endOfLine": "lf" to the Prettier configuration for consistent line endings.
- Introduced "stripe" and "uuid" packages in package.json for enhanced functionality.
- Updated pnpm-lock.yaml to reflect the addition of new dependencies.

* refactor(stripe): rename mapToSubscriptionSessionErrorResponse to mapToSubscriptionSessionError

- Updated the function name from `mapToSubscriptionSessionErrorResponse` to `mapToSubscriptionSessionError` for consistency and clarity.
- Adjusted import statements and references in related files to reflect the new function name.

* fix(tests): update ACCOUNT UUID in route.test.ts for consistency

- Changed the ACCOUNT constant in route.test.ts from "123e4567-e89b-12d3-a456-426614174000" to "123e4567-e89b-12d3-a456-426614174001" to ensure consistency in test cases.

* feat(stripe): add STRIPE_SK environment variable and improve error handling

- Introduced the STRIPE_SK environment variable in .env.example to ensure proper configuration for Stripe integration.
- Updated the Stripe client initialization to throw an error if STRIPE_SK is not set, enhancing robustness.
- Modified error handling in createSubscriptionSessionHandler to return a 500 status with a generic error message for internal server errors.
- Adjusted validation logic in validateCreateSubscriptionSessionRequest to remove the optional accountId field, simplifying the request structure.
- Enhanced mapToSubscriptionSessionError to mask upstream error messages for 5xx responses, improving security.
- Updated tests to reflect changes in error handling and validation logic.

* fix(connectors): unify action catalog and execution paths for consistent access

- Merged shared and artist toolkits into the actions catalog to ensure all executable actions are listed, reflecting the full access available to the chat agent.
- Updated the executeConnectorAction function to also utilize the merged toolkit, ensuring that all actions listed in the catalog are executable.
- Extracted ConnectorActionNotFoundError into a separate file for cleaner error handling and improved test organization.
- Rewritten tests to mock the new toolkit structure, ensuring comprehensive coverage of the updated functionality.

* feat(stripe): refactor createStripeSession to use configuration constants

- Updated createStripeSession to utilize STRIPE_SUBSCRIPTION_PRICE_ID and STRIPE_SUBSCRIPTION_TRIAL_PERIOD_DAYS constants for better maintainability and configuration management.
- Enhanced tests for createStripeSession to reflect these changes, ensuring consistency in the subscription parameters.
- Improved error handling in client tests by refining the management of the STRIPE_SK environment variable.

* chore: remove .gitattributes and update Prettier configuration

- Deleted the .gitattributes file to simplify project configuration.
- Updated .prettierrc by removing the "endOfLine" setting for cleaner formatting consistency.

* chore(stripe): drop uuid dep, use accountId as client_reference_id

YAGNI: client_reference_id is a soft-convenience pointer string with no
readers in either api or chat — never round-trips, never queried via the
sessions.list API (it isn't a filterable param). The migration was
generating a throwaway random uuid that mapped to nothing internally.

Setting it to accountId instead:
- removes the uuid dep entirely (only callsite in this repo)
- makes the Stripe dashboard's "Client reference" column actually
  useful for support/debugging
- matches metadata.accountId so reconciliation is consistent

Drop the uuid mock from createStripeSession.test.ts and flip the
not.toBe("acc-1") assertion to toBe("acc-1") — encoding the new
contract instead of the old "value must be a random UUID" stance.

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

---------

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

* feat(api): migrate GET /api/ai/models (#491)

* feat(api): migrate misc-reads endpoints (email, ai/models, youtube/channel-info)

Adds api parity for chat's /api/email, /api/ai/models, /api/youtube/channel-info
ahead of the chat-side cutover.

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

* fix(api): address AI review on misc-reads PR

- updateContact: switch to loops v6 object-arg signature (fixes Vercel build)
- handlers: stop leaking raw exception text in 500 responses
- loopsClient: convert singleton to factory function matching filename
- youtubeErrors: align export name with filename
- getYouTubeChannelHandler: explicit boolean discriminator narrowing for build

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

* fix(api): change /api/email from GET to POST

Email tracking upserts a Loops contact — a write — so it should not be
exposed as GET with email in query params (PII in URLs, cacheable
responses). Switches to POST with `{ email }` JSON body.

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

* revert(api): drop /api/email endpoint

Loops is no longer used; the email tracking endpoint is removed
from this migration entirely.

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

* refactor(api): simplify youtube channel-info flow

- Fold token validation into validateYouTubeChannelInfoRequest so the
  handler is a thin fetch+respond orchestrator
- Rename validateYouTubeChannelQuery → validateYouTubeChannelInfoRequest
  (matches validateArtistRequest / validateChatRequest convention)
- Drop buildYouTubeUtilityError + error code catalog: every token-level
  failure collapses to the same {success:false, tokenStatus:"invalid"}
  response, so the typed codes carried no information out

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

* refactor(api): throw from youtube libs, single catch at validator

- refreshStoredYouTubeToken now throws on every failure (no more
  catch-log-return-null); the deep invalid_grant type guard is gone
  since the general console.error already logs the full error
- validateYouTubeTokens lets errors propagate; null is reserved for
  the legitimate "no tokens row / no refresh_token" cases
- validateYouTubeChannelInfoRequest is the single catch boundary;
  thrown errors and null both collapse to the same tokenStatus:invalid
  response, matching chat parity

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

* refactor(api): drop redundant explicit return types from misc-reads libs

TS inference already produces the same types for these helpers; explicit
annotations were noise. Kept annotations on discriminated-union returns
(validators, route handlers) and anywhere inference would widen.

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

* refactor(api): drop more redundant return types from misc-reads libs

Continues 7f64027 — TS inference produces the same types for these
helpers; explicit annotations were noise. Kept the discriminated-union
annotation on validateYouTubeChannelInfoRequest where it documents an
intentional contract.

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

* refactor(api): slim youtube channel-info response and validator

- drop response fields that no chat consumer reads
- validateYouTubeTokens throws on every unusable case; the request
  validator's catch is the single failure boundary (no more let/null)
- drop now-unnecessary explicit return types

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

* refactor(api): trim youtube tests, jsdocs, type duplication, response

- Drop `success` from /api/youtube/channel-info; conform to the
  `{ status: "success", channels }` envelope used across the rest of
  the api (lib/networking/successResponse.ts, songs, posts, accounts,
  chats, artists). Clients infer "needs re-auth" from
  `channels === null`.
- Keep only validator + handler tests; cover no-token, expired-no-refresh,
  refresh-failure, and db-update-failure cases at the validator boundary
  via it.each on the thrown-error contract.
- Trim jsdocs to information-bearing lines only; drop stale
  "mirrors chat" notes and self-evident @param/@returns lines on lib
  helpers.
- Dedupe YouTubeTokensRow: keep the export in validateYouTubeTokens.ts
  (the contract owner) and import it in refreshStoredYouTubeToken.ts.

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

* fix(api): return proper status codes for youtube channel-info errors

- 401 + {status:"error",message} when stored YouTube tokens can't be
  validated/refreshed (re-auth needed)
- 502 + {status:"error",message} for upstream YouTube API failures
- Drops the inconsistent "200 status:success channels:null" shape

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

* refactor(api): drop YouTubeTokensRow alias and return type

validateYouTubeTokens lets TS infer the return type; the alias is gone
(only refreshStoredYouTubeToken used it, now inlined as Tables<>).

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

* fix(api): bypass @ai-sdk/gateway SDK for model catalog

The SDK's getAvailableModels() rejects valid responses with a Zod error
("expected error.object"), which silenced 194 models behind an empty
array. Match chat's direct fetch to /v1/ai/config — same approach,
same payload, same parity.

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

* fix(api): pin @ai-sdk/gateway to 2.x for catalog reads

The 3.x SDK requires specificationVersion:"v3" via a strict Zod literal,
but the live /v1/ai/config endpoint still emits "v2" descriptors. Pin
to 2.0.83 (latest 2.x, expects "v2") so gateway.getAvailableModels()
works as designed. This is a catalog-read-only consumer; api never uses
gateway() as a model factory, so 2.x's LanguageModelV2 surface doesn't
collide with the rest of the codebase on @ai-sdk/provider@3.

Restore the SDK call site (no more direct fetch hack); a comment
flags when to bump back to 3.x.

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

* refactor(api): drop redundant jsdoc on getAvailableModels

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

* refactor(api): restore original jsdoc on getAvailableModels

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

* feat(api): gate /api/youtube/channel-info behind auth + artist access

Layers in validateAuthContext + checkAccountArtistAccess so anonymous
callers can no longer probe stored YouTube tokens by guessing UUIDs.
Returns 401 on missing/invalid auth, 403 when the authed caller has no
access to the requested artist.

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

* revert(api): drop /api/youtube/channel-info from this migration

YouTube channel-info will migrate via Composio in a separate PR.
Reduces Group 1 scope to just /api/ai/models.

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>

---------

Co-authored-by: ahmednahima0-beep <ahmednahima0@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Arpit Gupta <arpitgupta1214@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.

2 participants