From 867d5a92aa29adae50fd130c54cebb2e576f7e8b Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Sun, 15 Mar 2026 20:57:35 +0000 Subject: [PATCH] agent: @U0AJM7X8FBR Admin - please update the mono/admin repo with a table show --- app/api/accounts/[id]/route.ts | 7 +- .../admins/sandboxes/__tests__/route.test.ts | 13 +- app/api/artists/route.ts | 1 - app/api/chat/slack/route.ts | 35 - app/api/coding-agent/[platform]/route.ts | 14 +- .../callback/__tests__/route.test.ts | 4 +- app/api/content/create/route.ts | 1 - app/api/content/estimate/route.ts | 1 - app/api/content/templates/route.ts | 1 - app/api/content/validate/route.ts | 1 - app/api/organizations/artists/route.ts | 1 - app/api/songs/analyze/presets/route.ts | 1 + app/api/spotify/artist/albums/route.ts | 1 - app/api/transcribe/route.ts | 5 +- evals/catalog-songs-count.eval.ts | 5 +- evals/first-week-album-sales.eval.ts | 12 +- evals/memory-tools.eval.ts | 2 +- evals/monthly-listeners-tracking.eval.ts | 2 +- evals/search-web-tool.eval.ts | 9 +- evals/social-scraping.eval.ts | 8 +- evals/spotify-tools.eval.ts | 5 +- evals/tiktok-analytics-questions.eval.ts | 6 +- lib/accounts/getAccountHandler.ts | 1 - lib/accounts/validateAccountParams.ts | 1 - .../sandboxes/aggregateAccountSandboxStats.ts | 3 +- .../sandboxes/getAdminSandboxesHandler.ts | 4 +- lib/ai/__tests__/getAvailableModels.test.ts | 8 +- lib/ai/__tests__/getModel.test.ts | 10 +- lib/ai/getAvailableModels.ts | 6 +- lib/ai/getModel.ts | 7 +- lib/ai/isEmbedModel.ts | 2 + lib/artist/validateArtistSocialsScrapeBody.ts | 1 - .../__tests__/buildGetArtistsParams.test.ts | 4 +- .../checkAccountArtistAccess.test.ts | 20 +- .../__tests__/createArtistInDb.test.ts | 4 +- .../__tests__/createArtistPostHandler.test.ts | 5 + .../validateCreateArtistBody.test.ts | 5 + .../validateGetArtistsRequest.test.ts | 30 +- lib/artists/checkAccountArtistAccess.ts | 4 +- lib/artists/createArtistPostHandler.ts | 9 +- lib/artists/getFormattedArtist.ts | 13 +- lib/artists/getSocialPlatformByLink.ts | 1 - lib/artists/validateArtistsQuery.ts | 1 - lib/arweave/isIPFSUrl.ts | 1 - lib/arweave/isNormalizedIPFSURL.ts | 1 - .../__tests__/validateAuthContext.test.ts | 4 + lib/catalog/formatCatalogSongsAsCSV.ts | 6 +- lib/catalog/getCatalogDataAsCSV.ts | 2 + lib/catalog/getCatalogSongs.ts | 24 +- lib/catalog/getCatalogs.ts | 10 +- .../buildSystemPromptWithImages.test.ts | 2 +- .../__tests__/handleChatCompletion.test.ts | 34 +- .../integration/chatEndToEnd.test.ts | 95 +- lib/chat/__tests__/saveChatCompletion.test.ts | 10 +- lib/chat/__tests__/setupConversation.test.ts | 14 +- .../__tests__/setupToolsForRequest.test.ts | 16 +- .../__tests__/validateChatRequest.test.ts | 77 +- lib/chat/handleChatCompletion.ts | 3 +- lib/chat/handleChatStream.ts | 10 +- .../__tests__/getPrepareStepResult.test.ts | 76 +- .../toolChains/__tests__/toolChains.test.ts | 27 +- .../toolChains/getExecutedToolTimeline.ts | 6 +- lib/chat/toolChains/getPrepareStepResult.ts | 11 +- lib/chat/toolChains/index.ts | 7 +- lib/chat/validateMessages.ts | 4 +- lib/chats/__tests__/updateChatHandler.test.ts | 16 +- .../__tests__/validateUpdateChatBody.test.ts | 13 +- lib/chats/buildGetChatsParams.ts | 2 +- lib/chats/processCompactChatRequest.ts | 4 + .../__tests__/encodeGitHubThreadId.test.ts | 6 +- .../handleCodingAgentCallback.test.ts | 4 +- .../__tests__/handleGitHubWebhook.test.ts | 6 + .../__tests__/onMergeAction.test.ts | 9 +- .../__tests__/onMergeTestToMainAction.test.ts | 14 +- .../parseMergeTestToMainActionId.test.ts | 4 +- lib/coding-agent/buildPRCard.ts | 4 +- lib/coding-agent/encodeGitHubThreadId.ts | 2 + lib/coding-agent/handleMergeSuccess.ts | 2 + lib/coding-agent/handlers/onMergeAction.ts | 8 +- lib/coding-agent/mergeGithubBranch.ts | 27 +- lib/coding-agent/parseMergeActionId.ts | 2 + .../parseMergeTestToMainActionId.ts | 2 + lib/coding-agent/postGitHubComment.ts | 17 +- .../__tests__/getConnectorsHandler.test.ts | 4 +- .../validateAuthorizeConnectorRequest.test.ts | 5 +- .../validateGetConnectorsRequest.test.ts | 8 +- .../connectors/disconnectConnectorHandler.ts | 5 +- lib/composio/connectors/getConnectors.ts | 7 +- .../validateAuthorizeConnectorRequest.ts | 5 +- .../validateDisconnectConnectorRequest.ts | 5 +- .../validateGetConnectorsRequest.ts | 5 +- lib/composio/getCallbackUrl.ts | 1 + .../__tests__/createToolRouterSession.test.ts | 7 +- .../__tests__/getComposioTools.test.ts | 6 +- .../toolRouter/createToolRouterSession.ts | 4 +- lib/contact/contactTeam.ts | 1 - .../__tests__/createContentHandler.test.ts | 1 - .../getArtistContentReadiness.test.ts | 5 +- .../persistCreateContentRunVideo.test.ts | 5 +- .../validateCreateContentBody.test.ts | 5 +- lib/content/contentTemplates.ts | 5 +- lib/content/createContentHandler.ts | 2 + lib/content/getArtistContentReadiness.ts | 9 +- lib/content/getArtistFileTree.ts | 3 + lib/content/getArtistRootPrefix.ts | 5 + lib/content/getContentValidateHandler.ts | 3 +- lib/content/isCompletedRun.ts | 4 + lib/content/persistCreateContentRunVideo.ts | 2 + lib/content/resolveArtistSlug.ts | 4 +- lib/content/validateCreateContentBody.ts | 6 +- .../validateGetContentEstimateQuery.ts | 2 + .../validateGetContentValidateQuery.ts | 2 + lib/credits/__tests__/getCreditUsage.test.ts | 6 +- .../__tests__/handleChatCredits.test.ts | 13 +- lib/credits/getCreditUsage.ts | 7 +- lib/credits/handleChatCredits.ts | 4 + .../validateInboundEmailEvent.test.ts | 3 +- .../__tests__/extractRoomIdFromHtml.test.ts | 3 +- .../inbound/__tests__/getFromWithName.test.ts | 9 +- lib/emails/inbound/extractRoomIdFromHtml.ts | 5 +- lib/emails/processAndSendEmail.ts | 6 +- lib/evals/callChatFunctions.ts | 1 + lib/evals/callChatFunctionsWithResult.ts | 5 +- lib/evals/createToolsCalledScorer.ts | 18 +- lib/evals/extractTextFromResult.ts | 6 +- lib/evals/extractTextResultFromSteps.ts | 15 +- lib/evals/getCatalogSongsCountExpected.ts | 3 + lib/evals/getSpotifyFollowersData.ts | 4 +- lib/evals/getSpotifyFollowersExpected.ts | 4 + lib/evals/scorers/CatalogAvailability.ts | 29 +- lib/evals/scorers/QuestionAnswered.ts | 31 +- lib/evals/scorers/ToolsCalled.ts | 26 +- .../__tests__/getKnowledgeBaseText.test.ts | 4 +- lib/files/generateAndStoreTxtFile.ts | 1 - lib/files/parseFilesFromQuery.ts | 5 +- .../__tests__/callFlamingoGenerate.test.ts | 18 +- .../getFlamingoPresetsHandler.test.ts | 3 + lib/flamingo/__tests__/postProcessors.test.ts | 8 +- lib/flamingo/__tests__/presets.test.ts | 9 +- .../processAnalyzeMusicRequest.test.ts | 13 +- lib/flamingo/callFlamingoGenerate.ts | 4 +- lib/flamingo/executeFullReport.ts | 69 +- lib/flamingo/getFlamingoPresetsHandler.ts | 5 +- lib/flamingo/isFlamingoGenerateResult.ts | 10 +- lib/flamingo/postFlamingoGenerateHandler.ts | 7 +- lib/flamingo/presets/audienceProfile.ts | 2 +- lib/flamingo/presets/catalogMetadata.ts | 2 +- lib/flamingo/presets/condenseRepetitions.ts | 6 +- lib/flamingo/presets/contentAdvisory.ts | 2 +- lib/flamingo/presets/deduplicateArray.ts | 1 - lib/flamingo/presets/extractOneCycle.ts | 1 - lib/flamingo/presets/getAllPresets.ts | 1 - lib/flamingo/presets/getPreset.ts | 1 - lib/flamingo/presets/getPresetSummaries.ts | 3 +- lib/flamingo/presets/lyricTranscription.ts | 5 +- lib/flamingo/presets/moodTags.ts | 5 +- lib/flamingo/presets/musicTheory.ts | 6 +- lib/flamingo/presets/parseJsonLike.ts | 1 - lib/flamingo/presets/presetRegistry.ts | 6 +- lib/flamingo/presets/similarArtists.ts | 2 +- lib/flamingo/presets/syncBriefMatch.ts | 2 +- lib/flamingo/processAnalyzeMusicRequest.ts | 9 +- lib/flamingo/validateFlamingoGenerateBody.ts | 8 +- .../deleteAccountGithubRepos.test.ts | 8 +- .../__tests__/findOrgReposByAccountId.test.ts | 6 +- .../__tests__/getRepoGitModules.test.ts | 7 +- lib/github/expandSubmoduleEntries.ts | 6 + lib/github/findOrgReposByAccountId.ts | 19 +- lib/github/getOrgRepoUrls.ts | 5 +- lib/github/getRepoFileTree.ts | 8 +- lib/github/getRepoGitModules.ts | 3 + lib/github/resolveSubmodulePath.ts | 2 + lib/mcp/__tests__/getMcpTools.test.ts | 6 +- lib/mcp/__tests__/verifyApiKey.test.ts | 6 +- lib/mcp/resolveAccountId.ts | 2 + .../__tests__/registerSendEmailTool.test.ts | 3 +- .../registerWebDeepResearchTool.test.ts | 5 +- .../registerGetArtistSocialsTool.ts | 1 - .../registerUpdateArtistSocialsTool.ts | 5 +- .../registerCreateNewArtistTool.test.ts | 8 +- .../artists/registerCreateNewArtistTool.ts | 10 +- .../flamingo/registerAnalyzeMusicTool.ts | 3 +- lib/mcp/tools/registerWebDeepResearchTool.ts | 4 +- .../registerPromptSandboxTool.test.ts | 13 +- .../search/registerSearchGoogleImagesTool.ts | 22 +- .../registerGetTaskRunStatusTool.test.ts | 13 +- lib/mcp/tools/transcribe/index.ts | 1 - .../transcribe/registerTranscribeAudioTool.ts | 5 +- .../__tests__/convertToUiMessages.test.ts | 4 +- .../extractImageUrlsFromMessages.test.ts | 21 +- .../getLatestUserMessageText.test.ts | 4 +- lib/messages/__tests__/getTextContent.test.ts | 4 +- lib/messages/convertToUiMessages.ts | 2 +- lib/messages/getLatestUserMessageText.ts | 4 +- lib/messages/getTextContent.ts | 2 +- .../createNotificationHandler.test.ts | 7 +- .../validateCreateNotificationBody.test.ts | 10 +- .../__tests__/canAccessAccount.test.ts | 4 +- .../validateOrganizationAccess.test.ts | 4 +- lib/organizations/addArtistToOrgHandler.ts | 1 - lib/organizations/canAccessAccount.ts | 4 +- .../createOrganizationHandler.ts | 1 - .../formatAccountOrganizations.ts | 5 +- .../validateAddArtistToOrgBody.ts | 5 +- .../validateCreateOrganizationBody.ts | 1 - lib/perplexity/chatWithPerplexity.ts | 4 +- lib/prompts/getSystemPrompt.ts | 1 + .../__tests__/buildGetPulsesParams.test.ts | 4 +- lib/pulse/__tests__/getPulsesHandler.test.ts | 6 +- .../__tests__/updatePulsesHandler.test.ts | 6 +- .../validateGetPulsesRequest.test.ts | 42 +- lib/rooms/__tests__/copyRoom.test.ts | 4 +- lib/rooms/copyRoom.ts | 5 +- .../createSandboxFromSnapshot.test.ts | 6 +- .../__tests__/getActiveSandbox.test.ts | 15 +- .../__tests__/getOrCreateSandbox.test.ts | 3 +- .../__tests__/getSandboxesFileHandler.test.ts | 2 +- lib/sandbox/getActiveSandbox.ts | 4 +- lib/sandbox/runClaudeCode.ts | 2 +- lib/segments/createSegmentResponses.ts | 1 - lib/slack/chat/bot.ts | 56 - .../chat/handlers/handleSlackChatMessage.ts | 129 - lib/slack/chat/handlers/onNewMention.ts | 19 - .../chat/handlers/onSubscribedMessage.ts | 18 - lib/slack/chat/handlers/registerHandlers.ts | 10 - lib/slack/chat/types.ts | 10 - lib/slack/chat/validateEnv.ts | 20 - lib/slack/handleUrlVerification.ts | 21 - lib/spotify/getSpotifyFollowers.ts | 10 +- .../__tests__/insertAccountArtistId.test.ts | 4 +- .../__tests__/selectAccountArtistId.test.ts | 4 +- .../account_artist_ids/getAccountArtistIds.ts | 5 +- .../selectAccountArtistId.ts | 5 +- .../account_info/insertAccountInfo.ts | 1 - .../selectAccountOrganizationIds.test.ts | 4 +- .../addAccountToOrganization.ts | 1 - .../selectAccountOrganizationIds.ts | 5 +- .../__tests__/insertAccountSandbox.test.ts | 4 +- .../__tests__/upsertAccountSnapshot.test.ts | 3 +- .../selectAccountWorkspaceId.test.ts | 4 +- .../getAccountWorkspaceIds.ts | 3 +- .../selectAccountWorkspaceId.ts | 5 +- .../selectAccountWithSocials.test.ts | 12 +- lib/supabase/accounts/selectAccounts.ts | 9 +- .../selectArtistOrganizationIds.test.ts | 4 +- .../addArtistToOrganization.ts | 1 - .../getArtistsByOrganization.ts | 1 - lib/supabase/files/createFileRecord.ts | 7 +- .../__tests__/selectPulseAccounts.test.ts | 45 +- .../__tests__/upsertPulseAccount.test.ts | 4 +- .../song_artists/insertSongArtists.ts | 21 +- lib/supabase/storage/uploadFileByKey.ts | 19 +- lib/tasks/__tests__/deleteTask.test.ts | 16 +- lib/tasks/__tests__/getTaskRunHandler.test.ts | 27 +- .../__tests__/validateGetTaskRunQuery.test.ts | 2 + lib/tasks/validateGetTaskRunQuery.ts | 7 +- lib/telegram/sendErrorNotification.ts | 7 +- lib/transcribe/formatTranscriptMd.ts | 1 - lib/transcribe/index.ts | 1 - lib/transcribe/processAudioTranscription.ts | 7 +- lib/transcribe/saveAudioToFiles.ts | 14 +- lib/transcribe/saveTranscriptToFiles.ts | 4 + lib/transcribe/transcribeAudio.ts | 3 +- lib/transcribe/types.ts | 8 +- lib/trigger/triggerCreateContent.ts | 3 +- lib/workspaces/createWorkspacePostHandler.ts | 9 +- lib/youtube/fetchYouTubeChannelInfo.ts | 1 - lib/youtube/getDefaultDateRange.ts | 1 - lib/youtube/isTokenExpired.ts | 1 - next.config.ts | 12 +- types/database.types.ts | 6833 ++++++++--------- 271 files changed, 4393 insertions(+), 4786 deletions(-) delete mode 100644 app/api/chat/slack/route.ts delete mode 100644 lib/slack/chat/bot.ts delete mode 100644 lib/slack/chat/handlers/handleSlackChatMessage.ts delete mode 100644 lib/slack/chat/handlers/onNewMention.ts delete mode 100644 lib/slack/chat/handlers/onSubscribedMessage.ts delete mode 100644 lib/slack/chat/handlers/registerHandlers.ts delete mode 100644 lib/slack/chat/types.ts delete mode 100644 lib/slack/chat/validateEnv.ts delete mode 100644 lib/slack/handleUrlVerification.ts diff --git a/app/api/accounts/[id]/route.ts b/app/api/accounts/[id]/route.ts index bf1b03492..42b388bf3 100644 --- a/app/api/accounts/[id]/route.ts +++ b/app/api/accounts/[id]/route.ts @@ -23,13 +23,10 @@ export async function OPTIONS() { * - id (required): The unique identifier of the account (UUID) * * @param request - The request object + * @param params.params * @param params - Route params containing the account ID * @returns A NextResponse with account data */ -export async function GET( - request: NextRequest, - { params }: { params: Promise<{ id: string }> }, -) { +export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { return getAccountHandler(request, params); } - diff --git a/app/api/admins/sandboxes/__tests__/route.test.ts b/app/api/admins/sandboxes/__tests__/route.test.ts index 98e2650c9..444485e80 100644 --- a/app/api/admins/sandboxes/__tests__/route.test.ts +++ b/app/api/admins/sandboxes/__tests__/route.test.ts @@ -3,8 +3,7 @@ import { NextRequest, NextResponse } from "next/server"; const mockGetAdminSandboxesHandler = vi.fn(); vi.mock("@/lib/admins/sandboxes/getAdminSandboxesHandler", () => ({ - getAdminSandboxesHandler: (...args: unknown[]) => - mockGetAdminSandboxesHandler(...args), + getAdminSandboxesHandler: (...args: unknown[]) => mockGetAdminSandboxesHandler(...args), })); const { GET, OPTIONS } = await import("../route"); @@ -15,10 +14,7 @@ beforeEach(() => { describe("GET /api/admins/sandboxes", () => { it("delegates to getAdminSandboxesHandler and returns its response", async () => { - const expected = NextResponse.json( - { status: "success", accounts: [] }, - { status: 200 }, - ); + const expected = NextResponse.json({ status: "success", accounts: [] }, { status: 200 }); mockGetAdminSandboxesHandler.mockResolvedValue(expected); const request = new NextRequest("https://example.com/api/admins/sandboxes"); @@ -86,10 +82,7 @@ describe("GET /api/admins/sandboxes", () => { it("returns 500 when handler returns internal error", async () => { mockGetAdminSandboxesHandler.mockResolvedValue( - NextResponse.json( - { status: "error", message: "Internal server error" }, - { status: 500 }, - ), + NextResponse.json({ status: "error", message: "Internal server error" }, { status: 500 }), ); const request = new NextRequest("https://example.com/api/admins/sandboxes"); diff --git a/app/api/artists/route.ts b/app/api/artists/route.ts index 64b65a42c..7fe9a21b8 100644 --- a/app/api/artists/route.ts +++ b/app/api/artists/route.ts @@ -54,4 +54,3 @@ export async function GET(request: NextRequest) { export async function POST(request: NextRequest) { return createArtistPostHandler(request); } - diff --git a/app/api/chat/slack/route.ts b/app/api/chat/slack/route.ts deleted file mode 100644 index 9b86f10a3..000000000 --- a/app/api/chat/slack/route.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { NextRequest } from "next/server"; -import { after } from "next/server"; -import { slackChatBot } from "@/lib/slack/chat/bot"; -import { handleUrlVerification } from "@/lib/slack/handleUrlVerification"; -import "@/lib/slack/chat/handlers/registerHandlers"; - -/** - * GET /api/chat/slack - * - * Handles Slack webhook verification handshake. - * - * @param request - The incoming verification request - * @returns The webhook handler response - */ -export async function GET(request: NextRequest) { - return slackChatBot.webhooks.slack(request, { waitUntil: p => after(() => p) }); -} - -/** - * POST /api/chat/slack - * - * Webhook endpoint for the Record Label Agent Slack bot. - * Handles url_verification challenges and delegates messages to the bot. - * - * @param request - The incoming webhook request - * @returns The webhook handler response or url_verification challenge - */ -export async function POST(request: NextRequest) { - const verification = await handleUrlVerification(request); - if (verification) return verification; - - await slackChatBot.initialize(); - - return slackChatBot.webhooks.slack(request, { waitUntil: p => after(() => p) }); -} diff --git a/app/api/coding-agent/[platform]/route.ts b/app/api/coding-agent/[platform]/route.ts index a51a2104d..9e0025fd9 100644 --- a/app/api/coding-agent/[platform]/route.ts +++ b/app/api/coding-agent/[platform]/route.ts @@ -1,7 +1,6 @@ import type { NextRequest } from "next/server"; import { after } from "next/server"; import { codingAgentBot } from "@/lib/coding-agent/bot"; -import { handleUrlVerification } from "@/lib/slack/handleUrlVerification"; import "@/lib/coding-agent/handlers/registerHandlers"; /** @@ -10,6 +9,7 @@ import "@/lib/coding-agent/handlers/registerHandlers"; * Handles webhook verification handshakes (e.g. WhatsApp hub.challenge). * * @param request - The incoming verification request + * @param params.params * @param params - Route params containing the platform name */ export async function GET( @@ -34,6 +34,7 @@ export async function GET( * Handles Slack and WhatsApp webhooks via dynamic [platform] segment. * * @param request - The incoming webhook request + * @param params.params * @param params - Route params containing the platform name */ export async function POST( @@ -42,9 +43,16 @@ export async function POST( ) { const { platform } = await params; + // Handle Slack url_verification challenge before loading the bot. + // This avoids blocking on Redis/adapter initialization during setup. if (platform === "slack") { - const verification = await handleUrlVerification(request); - if (verification) return verification; + const body = await request + .clone() + .json() + .catch(() => null); + if (body?.type === "url_verification" && typeof body?.challenge === "string") { + return Response.json({ challenge: body.challenge }); + } } await codingAgentBot.initialize(); diff --git a/app/api/coding-agent/callback/__tests__/route.test.ts b/app/api/coding-agent/callback/__tests__/route.test.ts index 892cfa843..d817f0fc4 100644 --- a/app/api/coding-agent/callback/__tests__/route.test.ts +++ b/app/api/coding-agent/callback/__tests__/route.test.ts @@ -2,9 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest } from "next/server"; const mockInitialize = vi.fn(); -const mockHandleCallback = vi.fn().mockResolvedValue( - new Response("ok", { status: 200 }), -); +const mockHandleCallback = vi.fn().mockResolvedValue(new Response("ok", { status: 200 })); vi.mock("@/lib/coding-agent/bot", () => ({ codingAgentBot: { diff --git a/app/api/content/create/route.ts b/app/api/content/create/route.ts index 9d1a5fd96..94c2b5217 100644 --- a/app/api/content/create/route.ts +++ b/app/api/content/create/route.ts @@ -29,4 +29,3 @@ export async function POST(request: NextRequest): Promise { export const dynamic = "force-dynamic"; export const fetchCache = "force-no-store"; export const revalidate = 0; - diff --git a/app/api/content/estimate/route.ts b/app/api/content/estimate/route.ts index e6ad622f0..40ad08c06 100644 --- a/app/api/content/estimate/route.ts +++ b/app/api/content/estimate/route.ts @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise { export const dynamic = "force-dynamic"; export const fetchCache = "force-no-store"; export const revalidate = 0; - diff --git a/app/api/content/templates/route.ts b/app/api/content/templates/route.ts index 11572d481..cfe77afbc 100644 --- a/app/api/content/templates/route.ts +++ b/app/api/content/templates/route.ts @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise { export const dynamic = "force-dynamic"; export const fetchCache = "force-no-store"; export const revalidate = 0; - diff --git a/app/api/content/validate/route.ts b/app/api/content/validate/route.ts index 9a205cdce..1583bb4e4 100644 --- a/app/api/content/validate/route.ts +++ b/app/api/content/validate/route.ts @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise { export const dynamic = "force-dynamic"; export const fetchCache = "force-no-store"; export const revalidate = 0; - diff --git a/app/api/organizations/artists/route.ts b/app/api/organizations/artists/route.ts index c722e06f2..028c9f5c8 100644 --- a/app/api/organizations/artists/route.ts +++ b/app/api/organizations/artists/route.ts @@ -29,4 +29,3 @@ export async function OPTIONS() { export async function POST(request: NextRequest) { return addArtistToOrgHandler(request); } - diff --git a/app/api/songs/analyze/presets/route.ts b/app/api/songs/analyze/presets/route.ts index 8baccd38d..b809394c1 100644 --- a/app/api/songs/analyze/presets/route.ts +++ b/app/api/songs/analyze/presets/route.ts @@ -28,6 +28,7 @@ export async function OPTIONS() { * - status: "success" * - presets: Array of { name, label, description, requiresAudio, responseFormat } * + * @param request * @returns A NextResponse with the list of available presets */ export async function GET(request: NextRequest): Promise { diff --git a/app/api/spotify/artist/albums/route.ts b/app/api/spotify/artist/albums/route.ts index b7d939f87..b7ac94e06 100644 --- a/app/api/spotify/artist/albums/route.ts +++ b/app/api/spotify/artist/albums/route.ts @@ -32,4 +32,3 @@ export async function OPTIONS() { export async function GET(request: NextRequest) { return getSpotifyArtistAlbumsHandler(request); } - diff --git a/app/api/transcribe/route.ts b/app/api/transcribe/route.ts index 5cf0b9a53..0896806bc 100644 --- a/app/api/transcribe/route.ts +++ b/app/api/transcribe/route.ts @@ -2,6 +2,10 @@ import { NextRequest, NextResponse } from "next/server"; import { processAudioTranscription } from "@/lib/transcribe/processAudioTranscription"; import { formatTranscriptionError } from "@/lib/transcribe/types"; +/** + * + * @param req + */ export async function POST(req: NextRequest) { try { const body = await req.json(); @@ -40,4 +44,3 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: message }, { status }); } } - diff --git a/evals/catalog-songs-count.eval.ts b/evals/catalog-songs-count.eval.ts index 960068b59..1792f22ad 100644 --- a/evals/catalog-songs-count.eval.ts +++ b/evals/catalog-songs-count.eval.ts @@ -1,9 +1,6 @@ import { Eval } from "braintrust"; import { Factuality, AnswerCorrectness } from "autoevals"; -import { - callChatFunctionsWithResult, - extractTextFromResult, -} from "@/lib/evals"; +import { callChatFunctionsWithResult, extractTextFromResult } from "@/lib/evals"; import getCatalogSongsCountData from "@/lib/evals/getCatalogSongsCountData"; /** diff --git a/evals/first-week-album-sales.eval.ts b/evals/first-week-album-sales.eval.ts index 31f03c49c..6ba634862 100644 --- a/evals/first-week-album-sales.eval.ts +++ b/evals/first-week-album-sales.eval.ts @@ -14,8 +14,7 @@ import { callChatFunctions } from "@/lib/evals"; Eval("First Week Album Sales Evaluation", { data: () => [ { - input: - "how many albums did Halsey The Great Impersonator sell the first week of release", + input: "how many albums did Halsey The Great Impersonator sell the first week of release", expected: "Halsey's album 'The Great Impersonator' sold between 93,000 and 100,000 copies in its first week of release. It debuted at No. 2 on the Billboard 200 chart.", metadata: { @@ -26,8 +25,7 @@ Eval("First Week Album Sales Evaluation", { }, }, { - input: - "what were the first week sales for Taylor Swift's Midnights album?", + input: "what were the first week sales for Taylor Swift's Midnights album?", expected: "Taylor Swift's Midnights sold 1.578 million equivalent album units in its first week in the United States, which included between 1 million and 1.5 million pure album sales. This marked the biggest sales week for any album since Adele's 25 in 2015 and the best sales week for a vinyl album in the modern tracking era.", metadata: { @@ -38,8 +36,7 @@ Eval("First Week Album Sales Evaluation", { }, }, { - input: - "how many copies did Drake's Certified Lover Boy sell in the first week", + input: "how many copies did Drake's Certified Lover Boy sell in the first week", expected: "Drake's 'Certified Lover Boy' sold approximately 613,000 album-equivalent units in its first week, securing the #1 spot on the Billboard 200 chart.", metadata: { @@ -50,8 +47,7 @@ Eval("First Week Album Sales Evaluation", { }, }, { - input: - "what are the first week streaming numbers for Bad Bunny's Un Verano Sin Ti", + input: "what are the first week streaming numbers for Bad Bunny's Un Verano Sin Ti", expected: "In its first week of release in the United States, Bad Bunny's album Un Verano Sin Ti garnered over 355 million on-demand streams and 274,000 album-equivalent units, the most for any album that year and the largest streaming week for a Latin album ever at that time. The album also set a record for the biggest debut for a Latin album in Spotify's history.", metadata: { diff --git a/evals/memory-tools.eval.ts b/evals/memory-tools.eval.ts index 9de8fda65..41c8daa67 100644 --- a/evals/memory-tools.eval.ts +++ b/evals/memory-tools.eval.ts @@ -50,7 +50,7 @@ Eval("Memory & Storage Tools Evaluation", { const result = await callChatFunctionsWithResult(input); const output = extractTextFromResult(result); const toolCalls = - result.toolCalls?.map((tc) => ({ + result.toolCalls?.map(tc => ({ toolName: tc.toolName, args: {}, })) || []; diff --git a/evals/monthly-listeners-tracking.eval.ts b/evals/monthly-listeners-tracking.eval.ts index 7fa4965b5..b46fbb35d 100644 --- a/evals/monthly-listeners-tracking.eval.ts +++ b/evals/monthly-listeners-tracking.eval.ts @@ -16,7 +16,7 @@ Eval("Monthly Listeners Tracking Evaluation", { data: () => { const { startDateFormatted, endDateFormatted } = getDynamicDates(); - const testCases = EVAL_ARTISTS.map((artist) => ({ + const testCases = EVAL_ARTISTS.map(artist => ({ input: `what is the increase for ${artist} monthlies from ${startDateFormatted} to ${endDateFormatted}`, expected: `I've set up a monthlies tracking for ${artist}. would you like to receive the updated list in your email?`, metadata: { diff --git a/evals/search-web-tool.eval.ts b/evals/search-web-tool.eval.ts index dda174926..f02584d99 100644 --- a/evals/search-web-tool.eval.ts +++ b/evals/search-web-tool.eval.ts @@ -80,8 +80,7 @@ This year's Grammys were notable for historic wins, genre-crossing breakthroughs }, }, { - input: - "What are the current Spotify streaming numbers for Bad Bunny's latest album?", + input: "What are the current Spotify streaming numbers for Bad Bunny's latest album?", expected: `Bad Bunny's latest album titled "DeBÍ TiRAR MáS FOToS," released in 2025, currently has around 1.07 billion streams on Spotify. His previous album "Un Verano Sin Ti" has over 20.6 billion streams on Spotify, making it one of the most streamed albums on the platform as of late 2025.`, metadata: { category: "streaming_data", @@ -181,8 +180,7 @@ These collaborations highlight a range of featured artists who dropped new track }, }, { - input: - "What are the current music industry revenue statistics for Q2 2025?", + input: "What are the current music industry revenue statistics for Q2 2025?", expected: `The current music industry revenue statistics for Q2 2025 show continued growth driven primarily by streaming and subscription services. Key highlights from major companies: @@ -227,8 +225,7 @@ Overall, 2025 sees music copyright law adapting to address the growing influence }, }, { - input: - "What are the latest features on TikTok for music creators in Q2 2025?", + input: "What are the latest features on TikTok for music creators in Q2 2025?", expected: `The latest features on TikTok for music creators in Q2 2025 center around the beta launch of TikTok Songwriter Features. These include: - Songwriter Account Label: Music creators can create official Songwriter accounts that add a clear "Songwriter" label to their profile for identification. diff --git a/evals/social-scraping.eval.ts b/evals/social-scraping.eval.ts index 277616d96..e9748abcd 100644 --- a/evals/social-scraping.eval.ts +++ b/evals/social-scraping.eval.ts @@ -56,8 +56,7 @@ Eval("Social Scraping Evaluation", { }, { input: "How many Instagram followers do I have?", - expected: - "Specific follower count from fresh scraping (e.g., '112,545 followers')", + expected: "Specific follower count from fresh scraping (e.g., '112,545 followers')", metadata: { artist: "Fat Beats", platform: "instagram", @@ -94,8 +93,7 @@ Eval("Social Scraping Evaluation", { { input: "Fetch streaming trend and playlist-add history for the last 90 days (shows what's actually growing).", - expected: - "Streaming trend data and playlist-add history from Spotify tools and web search", + expected: "Streaming trend data and playlist-add history from Spotify tools and web search", metadata: { artist: "Unknown", platform: "spotify", @@ -124,7 +122,7 @@ Eval("Social Scraping Evaluation", { const result = await callChatFunctionsWithResult(input); const output = extractTextFromResult(result); const toolCalls = - result.toolCalls?.map((tc) => ({ + result.toolCalls?.map(tc => ({ toolName: tc.toolName, args: {}, })) || []; diff --git a/evals/spotify-tools.eval.ts b/evals/spotify-tools.eval.ts index adb8856d6..8a7010c6b 100644 --- a/evals/spotify-tools.eval.ts +++ b/evals/spotify-tools.eval.ts @@ -37,8 +37,7 @@ Eval("Spotify Tools Evaluation", { { input: 'craft a spotify for artists pitch, in line with their requirements, about the 2 late to be toxic album and focus track "what happened 2 us". ask any questions you need to get necessary info you don\'t have', - expected: - "A Spotify for Artists pitch using data from Spotify tools and web research", + expected: "A Spotify for Artists pitch using data from Spotify tools and web research", metadata: { artist: "Unknown", platform: "Spotify", @@ -67,7 +66,7 @@ Eval("Spotify Tools Evaluation", { const result = await callChatFunctionsWithResult(input); const output = extractTextFromResult(result); const toolCalls = - result.toolCalls?.map((tc) => ({ + result.toolCalls?.map(tc => ({ toolName: tc.toolName, args: {}, })) || []; diff --git a/evals/tiktok-analytics-questions.eval.ts b/evals/tiktok-analytics-questions.eval.ts index b74579a33..019ee8f7d 100644 --- a/evals/tiktok-analytics-questions.eval.ts +++ b/evals/tiktok-analytics-questions.eval.ts @@ -23,8 +23,7 @@ Eval("TikTok Analytics Questions Evaluation", { data: () => [ { input: "how many total views does @iamjuliusblack have on TikTok", - expected: - "A specific number of total views (e.g., '150,000 total views')", + expected: "A specific number of total views (e.g., '150,000 total views')", metadata: { artist: "Julius Black", platform: "tiktok", @@ -34,8 +33,7 @@ Eval("TikTok Analytics Questions Evaluation", { }, { input: "show me @iamjuliusblack's 10 highest performing TikTok posts", - expected: - "A ranked list of 10 TikTok posts with URLs, view counts, likes, and captions", + expected: "A ranked list of 10 TikTok posts with URLs, view counts, likes, and captions", metadata: { artist: "Julius Black", platform: "tiktok", diff --git a/lib/accounts/getAccountHandler.ts b/lib/accounts/getAccountHandler.ts index 327242f0d..0c58a58f4 100644 --- a/lib/accounts/getAccountHandler.ts +++ b/lib/accounts/getAccountHandler.ts @@ -61,4 +61,3 @@ export async function getAccountHandler( ); } } - diff --git a/lib/accounts/validateAccountParams.ts b/lib/accounts/validateAccountParams.ts index 8b2c4534b..47864d240 100644 --- a/lib/accounts/validateAccountParams.ts +++ b/lib/accounts/validateAccountParams.ts @@ -34,4 +34,3 @@ export function validateAccountParams(id: string): NextResponse | AccountParams return result.data; } - diff --git a/lib/admins/sandboxes/aggregateAccountSandboxStats.ts b/lib/admins/sandboxes/aggregateAccountSandboxStats.ts index 99bd17ec8..69cdbcf0d 100644 --- a/lib/admins/sandboxes/aggregateAccountSandboxStats.ts +++ b/lib/admins/sandboxes/aggregateAccountSandboxStats.ts @@ -37,7 +37,6 @@ export async function aggregateAccountSandboxStats(): Promise - new Date(b.last_created_at).getTime() - new Date(a.last_created_at).getTime(), + (a, b) => new Date(b.last_created_at).getTime() - new Date(a.last_created_at).getTime(), ); } diff --git a/lib/admins/sandboxes/getAdminSandboxesHandler.ts b/lib/admins/sandboxes/getAdminSandboxesHandler.ts index 02741a79c..0290bdfd2 100644 --- a/lib/admins/sandboxes/getAdminSandboxesHandler.ts +++ b/lib/admins/sandboxes/getAdminSandboxesHandler.ts @@ -48,9 +48,7 @@ export async function getAdminSandboxesHandler(request: NextRequest): Promise( - emailRows - .filter(r => r.account_id !== null) - .map(r => [r.account_id as string, r.email]), + emailRows.filter(r => r.account_id !== null).map(r => [r.account_id as string, r.email]), ); const accounts = stats.map(s => ({ diff --git a/lib/ai/__tests__/getAvailableModels.test.ts b/lib/ai/__tests__/getAvailableModels.test.ts index 05a9014b8..271752bc7 100644 --- a/lib/ai/__tests__/getAvailableModels.test.ts +++ b/lib/ai/__tests__/getAvailableModels.test.ts @@ -1,14 +1,14 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { gateway } from "@ai-sdk/gateway"; +import { getAvailableModels } from "../getAvailableModels"; + vi.mock("@ai-sdk/gateway", () => ({ gateway: { getAvailableModels: vi.fn(), }, })); -import { gateway } from "@ai-sdk/gateway"; -import { getAvailableModels } from "../getAvailableModels"; - const mockGatewayGetAvailableModels = vi.mocked(gateway.getAvailableModels); describe("getAvailableModels", () => { @@ -35,7 +35,7 @@ describe("getAvailableModels", () => { // Should filter out embed models (output price = 0) expect(models).toHaveLength(2); - expect(models.map((m) => m.id)).toEqual(["gpt-4", "claude-3-opus"]); + expect(models.map(m => m.id)).toEqual(["gpt-4", "claude-3-opus"]); }); it("returns empty array when gateway returns no models", async () => { diff --git a/lib/ai/__tests__/getModel.test.ts b/lib/ai/__tests__/getModel.test.ts index 52ec40c22..367fa40cb 100644 --- a/lib/ai/__tests__/getModel.test.ts +++ b/lib/ai/__tests__/getModel.test.ts @@ -1,12 +1,12 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { getAvailableModels } from "@/lib/ai/getAvailableModels"; +import { getModel } from "../getModel"; + vi.mock("@/lib/ai/getAvailableModels", () => ({ getAvailableModels: vi.fn(), })); -import { getAvailableModels } from "@/lib/ai/getAvailableModels"; -import { getModel } from "../getModel"; - const mockGetAvailableModels = vi.mocked(getAvailableModels); describe("getModel", () => { @@ -35,9 +35,7 @@ describe("getModel", () => { }); it("returns undefined when model is not found", async () => { - const models = [ - { id: "gpt-4", pricing: { input: "0.00003", output: "0.00006" } }, - ]; + const models = [{ id: "gpt-4", pricing: { input: "0.00003", output: "0.00006" } }]; mockGetAvailableModels.mockResolvedValue(models as any); const model = await getModel("unknown-model"); diff --git a/lib/ai/getAvailableModels.ts b/lib/ai/getAvailableModels.ts index 8ecfb8f3d..a46fd79ee 100644 --- a/lib/ai/getAvailableModels.ts +++ b/lib/ai/getAvailableModels.ts @@ -5,12 +5,10 @@ import isEmbedModel from "./isEmbedModel"; * Returns the list of available LLMs from the Vercel AI Gateway. * Filters out embed models that are not suitable for chat. */ -export const getAvailableModels = async (): Promise< - GatewayLanguageModelEntry[] -> => { +export const getAvailableModels = async (): Promise => { try { const apiResponse = await gateway.getAvailableModels(); - const gatewayModels = apiResponse.models.filter((m) => !isEmbedModel(m)); + const gatewayModels = apiResponse.models.filter(m => !isEmbedModel(m)); return gatewayModels; } catch { return []; diff --git a/lib/ai/getModel.ts b/lib/ai/getModel.ts index b802acaf9..99ca9c2fe 100644 --- a/lib/ai/getModel.ts +++ b/lib/ai/getModel.ts @@ -3,15 +3,14 @@ import { GatewayLanguageModelEntry } from "@ai-sdk/gateway"; /** * Returns a specific model by its ID from the list of available models. + * * @param modelId - The ID of the model to find * @returns The matching model or undefined if not found */ -export const getModel = async ( - modelId: string, -): Promise => { +export const getModel = async (modelId: string): Promise => { try { const availableModels = await getAvailableModels(); - return availableModels.find((model) => model.id === modelId); + return availableModels.find(model => model.id === modelId); } catch (error) { console.error(`Failed to get model with ID ${modelId}:`, error); return undefined; diff --git a/lib/ai/isEmbedModel.ts b/lib/ai/isEmbedModel.ts index 7c5fbbfb4..4901f1e8f 100644 --- a/lib/ai/isEmbedModel.ts +++ b/lib/ai/isEmbedModel.ts @@ -3,6 +3,8 @@ import { GatewayLanguageModelEntry } from "@ai-sdk/gateway"; /** * Determines if a model is an embedding model (not suitable for chat). * Embed models typically have 0 output pricing since they only produce embeddings. + * + * @param m */ export const isEmbedModel = (m: GatewayLanguageModelEntry): boolean => { const pricing = m.pricing; diff --git a/lib/artist/validateArtistSocialsScrapeBody.ts b/lib/artist/validateArtistSocialsScrapeBody.ts index 7ef98c2a2..a6d5cf8e7 100644 --- a/lib/artist/validateArtistSocialsScrapeBody.ts +++ b/lib/artist/validateArtistSocialsScrapeBody.ts @@ -36,4 +36,3 @@ export function validateArtistSocialsScrapeBody( return validationResult.data; } - diff --git a/lib/artists/__tests__/buildGetArtistsParams.test.ts b/lib/artists/__tests__/buildGetArtistsParams.test.ts index 398d670bf..6e5ec1f10 100644 --- a/lib/artists/__tests__/buildGetArtistsParams.test.ts +++ b/lib/artists/__tests__/buildGetArtistsParams.test.ts @@ -1,12 +1,12 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { buildGetArtistsParams } from "../buildGetArtistsParams"; +import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; + vi.mock("@/lib/organizations/canAccessAccount", () => ({ canAccessAccount: vi.fn(), })); -import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; - describe("buildGetArtistsParams", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/artists/__tests__/checkAccountArtistAccess.test.ts b/lib/artists/__tests__/checkAccountArtistAccess.test.ts index 1bb0b2536..9966402e8 100644 --- a/lib/artists/__tests__/checkAccountArtistAccess.test.ts +++ b/lib/artists/__tests__/checkAccountArtistAccess.test.ts @@ -1,6 +1,10 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { checkAccountArtistAccess } from "../checkAccountArtistAccess"; +import { selectAccountArtistId } from "@/lib/supabase/account_artist_ids/selectAccountArtistId"; +import { selectArtistOrganizationIds } from "@/lib/supabase/artist_organization_ids/selectArtistOrganizationIds"; +import { selectAccountOrganizationIds } from "@/lib/supabase/account_organization_ids/selectAccountOrganizationIds"; + vi.mock("@/lib/supabase/account_artist_ids/selectAccountArtistId", () => ({ selectAccountArtistId: vi.fn(), })); @@ -13,10 +17,6 @@ vi.mock("@/lib/supabase/account_organization_ids/selectAccountOrganizationIds", selectAccountOrganizationIds: vi.fn(), })); -import { selectAccountArtistId } from "@/lib/supabase/account_artist_ids/selectAccountArtistId"; -import { selectArtistOrganizationIds } from "@/lib/supabase/artist_organization_ids/selectArtistOrganizationIds"; -import { selectAccountOrganizationIds } from "@/lib/supabase/account_organization_ids/selectAccountOrganizationIds"; - describe("checkAccountArtistAccess", () => { beforeEach(() => { vi.clearAllMocks(); @@ -34,12 +34,8 @@ describe("checkAccountArtistAccess", () => { it("should return true when account and artist share an organization", async () => { vi.mocked(selectAccountArtistId).mockResolvedValue(null); - vi.mocked(selectArtistOrganizationIds).mockResolvedValue([ - { organization_id: "org-1" }, - ]); - vi.mocked(selectAccountOrganizationIds).mockResolvedValue([ - { organization_id: "org-1" }, - ]); + vi.mocked(selectArtistOrganizationIds).mockResolvedValue([{ organization_id: "org-1" }]); + vi.mocked(selectAccountOrganizationIds).mockResolvedValue([{ organization_id: "org-1" }]); const result = await checkAccountArtistAccess("account-123", "artist-456"); @@ -69,9 +65,7 @@ describe("checkAccountArtistAccess", () => { it("should return false when account org lookup errors (fail closed)", async () => { vi.mocked(selectAccountArtistId).mockResolvedValue(null); - vi.mocked(selectArtistOrganizationIds).mockResolvedValue([ - { organization_id: "org-1" }, - ]); + vi.mocked(selectArtistOrganizationIds).mockResolvedValue([{ organization_id: "org-1" }]); vi.mocked(selectAccountOrganizationIds).mockResolvedValue(null); const result = await checkAccountArtistAccess("account-123", "artist-456"); diff --git a/lib/artists/__tests__/createArtistInDb.test.ts b/lib/artists/__tests__/createArtistInDb.test.ts index e979fbb54..eaed9442c 100644 --- a/lib/artists/__tests__/createArtistInDb.test.ts +++ b/lib/artists/__tests__/createArtistInDb.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { createArtistInDb } from "../createArtistInDb"; + const mockInsertAccount = vi.fn(); const mockInsertAccountInfo = vi.fn(); const mockSelectAccountWithSocials = vi.fn(); @@ -26,8 +28,6 @@ vi.mock("@/lib/supabase/artist_organization_ids/addArtistToOrganization", () => addArtistToOrganization: (...args: unknown[]) => mockAddArtistToOrganization(...args), })); -import { createArtistInDb } from "../createArtistInDb"; - describe("createArtistInDb", () => { const mockAccount = { id: "artist-123", diff --git a/lib/artists/__tests__/createArtistPostHandler.test.ts b/lib/artists/__tests__/createArtistPostHandler.test.ts index e63d244dc..dd72b2e1b 100644 --- a/lib/artists/__tests__/createArtistPostHandler.test.ts +++ b/lib/artists/__tests__/createArtistPostHandler.test.ts @@ -14,6 +14,11 @@ vi.mock("@/lib/auth/validateAuthContext", () => ({ validateAuthContext: (...args: unknown[]) => mockValidateAuthContext(...args), })); +/** + * + * @param body + * @param headers + */ function createRequest(body: unknown, headers: Record = {}): NextRequest { const defaultHeaders: Record = { "Content-Type": "application/json", diff --git a/lib/artists/__tests__/validateCreateArtistBody.test.ts b/lib/artists/__tests__/validateCreateArtistBody.test.ts index 4de5562b1..d12fe1bac 100644 --- a/lib/artists/__tests__/validateCreateArtistBody.test.ts +++ b/lib/artists/__tests__/validateCreateArtistBody.test.ts @@ -9,6 +9,11 @@ vi.mock("@/lib/auth/validateAuthContext", () => ({ validateAuthContext: (...args: unknown[]) => mockValidateAuthContext(...args), })); +/** + * + * @param body + * @param headers + */ function createRequest(body: unknown, headers: Record = {}): NextRequest { const defaultHeaders: Record = { "Content-Type": "application/json" }; return new NextRequest("http://localhost/api/artists", { diff --git a/lib/artists/__tests__/validateGetArtistsRequest.test.ts b/lib/artists/__tests__/validateGetArtistsRequest.test.ts index 699f80c68..d7449d813 100644 --- a/lib/artists/__tests__/validateGetArtistsRequest.test.ts +++ b/lib/artists/__tests__/validateGetArtistsRequest.test.ts @@ -2,6 +2,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest, NextResponse } from "next/server"; import { validateGetArtistsRequest } from "../validateGetArtistsRequest"; +import { validateAuthContext } from "@/lib/auth/validateAuthContext"; +import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; + vi.mock("@/lib/auth/validateAuthContext", () => ({ validateAuthContext: vi.fn(), })); @@ -14,9 +17,6 @@ vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => new Headers()), })); -import { validateAuthContext } from "@/lib/auth/validateAuthContext"; -import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; - describe("validateGetArtistsRequest", () => { beforeEach(() => { vi.clearAllMocks(); @@ -76,9 +76,7 @@ describe("validateGetArtistsRequest", () => { authToken: "test-token", }); - const request = new NextRequest( - `http://localhost/api/artists?org_id=${orgFilterId}`, - ); + const request = new NextRequest(`http://localhost/api/artists?org_id=${orgFilterId}`); const result = await validateGetArtistsRequest(request); expect(result).not.toBeInstanceOf(NextResponse); @@ -95,9 +93,7 @@ describe("validateGetArtistsRequest", () => { authToken: "test-token", }); - const request = new NextRequest( - "http://localhost/api/artists?account_id=not-a-uuid", - ); + const request = new NextRequest("http://localhost/api/artists?account_id=not-a-uuid"); const result = await validateGetArtistsRequest(request); expect(result).toBeInstanceOf(NextResponse); @@ -111,9 +107,7 @@ describe("validateGetArtistsRequest", () => { authToken: "test-token", }); - const request = new NextRequest( - "http://localhost/api/artists?org_id=not-a-uuid", - ); + const request = new NextRequest("http://localhost/api/artists?org_id=not-a-uuid"); const result = await validateGetArtistsRequest(request); expect(result).toBeInstanceOf(NextResponse); @@ -130,9 +124,7 @@ describe("validateGetArtistsRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(true); - const request = new NextRequest( - `http://localhost/api/artists?account_id=${targetAccountId}`, - ); + const request = new NextRequest(`http://localhost/api/artists?account_id=${targetAccountId}`); const result = await validateGetArtistsRequest(request); expect(canAccessAccount).toHaveBeenCalledWith({ @@ -155,9 +147,7 @@ describe("validateGetArtistsRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(false); - const request = new NextRequest( - `http://localhost/api/artists?account_id=${otherAccountId}`, - ); + const request = new NextRequest(`http://localhost/api/artists?account_id=${otherAccountId}`); const result = await validateGetArtistsRequest(request); expect(result).toBeInstanceOf(NextResponse); @@ -174,9 +164,7 @@ describe("validateGetArtistsRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(false); - const request = new NextRequest( - `http://localhost/api/artists?account_id=${notInOrgId}`, - ); + const request = new NextRequest(`http://localhost/api/artists?account_id=${notInOrgId}`); const result = await validateGetArtistsRequest(request); expect(canAccessAccount).toHaveBeenCalledWith({ diff --git a/lib/artists/checkAccountArtistAccess.ts b/lib/artists/checkAccountArtistAccess.ts index a0b8defef..9b851f768 100644 --- a/lib/artists/checkAccountArtistAccess.ts +++ b/lib/artists/checkAccountArtistAccess.ts @@ -31,9 +31,7 @@ export async function checkAccountArtistAccess( if (!artistOrgs.length) return false; - const orgIds = artistOrgs - .map((o) => o.organization_id) - .filter((id): id is string => Boolean(id)); + const orgIds = artistOrgs.map(o => o.organization_id).filter((id): id is string => Boolean(id)); if (!orgIds.length) return false; const userOrgAccess = await selectAccountOrganizationIds(accountId, orgIds); diff --git a/lib/artists/createArtistPostHandler.ts b/lib/artists/createArtistPostHandler.ts index 58bed3f75..80cb3adf1 100644 --- a/lib/artists/createArtistPostHandler.ts +++ b/lib/artists/createArtistPostHandler.ts @@ -19,9 +19,7 @@ import { createArtistInDb } from "@/lib/artists/createArtistInDb"; * @param request - The request object containing JSON body * @returns A NextResponse with artist data or error */ -export async function createArtistPostHandler( - request: NextRequest, -): Promise { +export async function createArtistPostHandler(request: NextRequest): Promise { const validated = await validateCreateArtistBody(request); if (validated instanceof NextResponse) { return validated; @@ -41,10 +39,7 @@ export async function createArtistPostHandler( ); } - return NextResponse.json( - { artist }, - { status: 201, headers: getCorsHeaders() }, - ); + return NextResponse.json({ artist }, { status: 201, headers: getCorsHeaders() }); } catch (error) { const message = error instanceof Error ? error.message : "Failed to create artist"; return NextResponse.json( diff --git a/lib/artists/getFormattedArtist.ts b/lib/artists/getFormattedArtist.ts index 8aa2211f9..a4f75e72a 100644 --- a/lib/artists/getFormattedArtist.ts +++ b/lib/artists/getFormattedArtist.ts @@ -60,13 +60,11 @@ export function getFormattedArtist(row: ArtistQueryRow): FormattedArtist { instruction: "", }; - const account_socials = (artist.account_socials || []).map( - (social: AccountSocialWithSocial) => ({ - ...social.social, - link: social.social?.profile_url || "", - type: getSocialPlatformByLink(social.social?.profile_url || ""), - }), - ); + const account_socials = (artist.account_socials || []).map((social: AccountSocialWithSocial) => ({ + ...social.social, + link: social.social?.profile_url || "", + type: getSocialPlatformByLink(social.social?.profile_url || ""), + })); return { name: artist.name, @@ -76,4 +74,3 @@ export function getFormattedArtist(row: ArtistQueryRow): FormattedArtist { pinned: row.pinned || false, }; } - diff --git a/lib/artists/getSocialPlatformByLink.ts b/lib/artists/getSocialPlatformByLink.ts index aaf6ab682..744ad626e 100644 --- a/lib/artists/getSocialPlatformByLink.ts +++ b/lib/artists/getSocialPlatformByLink.ts @@ -17,4 +17,3 @@ export function getSocialPlatformByLink(link: string): string { return "NONE"; } - diff --git a/lib/artists/validateArtistsQuery.ts b/lib/artists/validateArtistsQuery.ts index 9c02188d2..91b5a9080 100644 --- a/lib/artists/validateArtistsQuery.ts +++ b/lib/artists/validateArtistsQuery.ts @@ -37,4 +37,3 @@ export function validateArtistsQuery(searchParams: URLSearchParams): NextRespons return result.data; } - diff --git a/lib/arweave/isIPFSUrl.ts b/lib/arweave/isIPFSUrl.ts index ba9e54843..271ce35fe 100644 --- a/lib/arweave/isIPFSUrl.ts +++ b/lib/arweave/isIPFSUrl.ts @@ -10,4 +10,3 @@ import { isGatewayIPFSUrl } from "./isGatewayIPFSUrl"; export function isIPFSUrl(url: string | null | undefined): boolean { return url ? isNormalizedIPFSURL(url) || isGatewayIPFSUrl(url) : false; } - diff --git a/lib/arweave/isNormalizedIPFSURL.ts b/lib/arweave/isNormalizedIPFSURL.ts index cdfbe3720..7275e6450 100644 --- a/lib/arweave/isNormalizedIPFSURL.ts +++ b/lib/arweave/isNormalizedIPFSURL.ts @@ -7,4 +7,3 @@ export function isNormalizedIPFSURL(url: string | null | undefined): boolean { return url && typeof url === "string" ? url.startsWith("ipfs://") : false; } - diff --git a/lib/auth/__tests__/validateAuthContext.test.ts b/lib/auth/__tests__/validateAuthContext.test.ts index 911ecbc4e..ac44727d6 100644 --- a/lib/auth/__tests__/validateAuthContext.test.ts +++ b/lib/auth/__tests__/validateAuthContext.test.ts @@ -39,6 +39,10 @@ const mockGetApiKeyDetails = vi.mocked(getApiKeyDetails); const mockValidateOrganizationAccess = vi.mocked(validateOrganizationAccess); const mockCanAccessAccount = vi.mocked(canAccessAccount); +/** + * + * @param headers + */ function createMockRequest(headers: Record = {}): Request { return { headers: { diff --git a/lib/catalog/formatCatalogSongsAsCSV.ts b/lib/catalog/formatCatalogSongsAsCSV.ts index f9d0bf226..29cc443cb 100644 --- a/lib/catalog/formatCatalogSongsAsCSV.ts +++ b/lib/catalog/formatCatalogSongsAsCSV.ts @@ -2,10 +2,12 @@ import { CatalogSong } from "./getCatalogSongs"; /** * Formats catalog songs into the CSV-like format expected by the scorer + * + * @param songs */ export function formatCatalogSongsAsCSV(songs: CatalogSong[]): string { - const csvLines = songs.map((song) => { - const artistNames = song.artists.map((artist) => artist.name).join(", "); + const csvLines = songs.map(song => { + const artistNames = song.artists.map(artist => artist.name).join(", "); return `${song.isrc},"${song.name}","${song.album}","${artistNames}"`; }); diff --git a/lib/catalog/getCatalogDataAsCSV.ts b/lib/catalog/getCatalogDataAsCSV.ts index ea529c37e..4a86fc0ee 100644 --- a/lib/catalog/getCatalogDataAsCSV.ts +++ b/lib/catalog/getCatalogDataAsCSV.ts @@ -3,6 +3,8 @@ import { formatCatalogSongsAsCSV } from "./formatCatalogSongsAsCSV"; /** * Gets all catalog songs and formats them as CSV for the scorer + * + * @param catalogId */ export async function getCatalogDataAsCSV(catalogId: string): Promise { const allSongs: CatalogSong[] = []; diff --git a/lib/catalog/getCatalogSongs.ts b/lib/catalog/getCatalogSongs.ts index b82747a6c..d7b5ca620 100644 --- a/lib/catalog/getCatalogSongs.ts +++ b/lib/catalog/getCatalogSongs.ts @@ -25,11 +25,18 @@ export interface CatalogSongsResponse { error?: string; } +/** + * + * @param catalogId + * @param pageSize + * @param page + * @param artistName + */ export async function getCatalogSongs( catalogId: string, pageSize: number = 100, page: number = 1, - artistName?: string + artistName?: string, ): Promise { try { const params = new URLSearchParams({ @@ -42,15 +49,12 @@ export async function getCatalogSongs( params.append("artistName", artistName); } - const response = await fetch( - `${NEW_API_BASE_URL}/api/catalogs/songs?${params}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await fetch(`${NEW_API_BASE_URL}/api/catalogs/songs?${params}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); if (!response.ok) { const errorText = await response.text(); diff --git a/lib/catalog/getCatalogs.ts b/lib/catalog/getCatalogs.ts index 179d1f3a9..4ac8a842d 100644 --- a/lib/catalog/getCatalogs.ts +++ b/lib/catalog/getCatalogs.ts @@ -8,9 +8,11 @@ export interface CatalogsResponse { error?: string; } -export async function getCatalogs( - accountId: string -): Promise { +/** + * + * @param accountId + */ +export async function getCatalogs(accountId: string): Promise { try { const response = await fetch( `https://api.recoupable.com/api/catalogs?account_id=${accountId}`, @@ -19,7 +21,7 @@ export async function getCatalogs( headers: { "Content-Type": "application/json", }, - } + }, ); if (!response.ok) { diff --git a/lib/chat/__tests__/buildSystemPromptWithImages.test.ts b/lib/chat/__tests__/buildSystemPromptWithImages.test.ts index 37717cee4..7f5e6d487 100644 --- a/lib/chat/__tests__/buildSystemPromptWithImages.test.ts +++ b/lib/chat/__tests__/buildSystemPromptWithImages.test.ts @@ -57,7 +57,7 @@ describe("buildSystemPromptWithImages", () => { const result = buildSystemPromptWithImages(basePrompt, imageUrls); const lines = result.split("\n"); - const imageLines = lines.filter((line) => line.startsWith("- Image")); + const imageLines = lines.filter(line => line.startsWith("- Image")); expect(imageLines).toHaveLength(2); }); }); diff --git a/lib/chat/__tests__/handleChatCompletion.test.ts b/lib/chat/__tests__/handleChatCompletion.test.ts index 098a8a8c7..aab50328f 100644 --- a/lib/chat/__tests__/handleChatCompletion.test.ts +++ b/lib/chat/__tests__/handleChatCompletion.test.ts @@ -1,6 +1,17 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import type { UIMessage } from "ai"; +import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails"; +import selectRoom from "@/lib/supabase/rooms/selectRoom"; +import { upsertRoom } from "@/lib/supabase/rooms/upsertRoom"; +import upsertMemory from "@/lib/supabase/memories/upsertMemory"; +import { sendNewConversationNotification } from "@/lib/telegram/sendNewConversationNotification"; +import { generateChatTitle } from "@/lib/chat/generateChatTitle"; +import { handleSendEmailToolOutputs } from "@/lib/emails/handleSendEmailToolOutputs"; +import { sendErrorNotification } from "@/lib/telegram/sendErrorNotification"; +import { handleChatCompletion } from "../handleChatCompletion"; +import type { ChatRequestBody } from "../validateChatRequest"; + // Mock all dependencies before importing the module under test vi.mock("@/lib/supabase/account_emails/selectAccountEmails", () => ({ default: vi.fn(), @@ -34,17 +45,6 @@ vi.mock("@/lib/telegram/sendErrorNotification", () => ({ sendErrorNotification: vi.fn(), })); -import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails"; -import selectRoom from "@/lib/supabase/rooms/selectRoom"; -import { upsertRoom } from "@/lib/supabase/rooms/upsertRoom"; -import upsertMemory from "@/lib/supabase/memories/upsertMemory"; -import { sendNewConversationNotification } from "@/lib/telegram/sendNewConversationNotification"; -import { generateChatTitle } from "@/lib/chat/generateChatTitle"; -import { handleSendEmailToolOutputs } from "@/lib/emails/handleSendEmailToolOutputs"; -import { sendErrorNotification } from "@/lib/telegram/sendErrorNotification"; -import { handleChatCompletion } from "../handleChatCompletion"; -import type { ChatRequestBody } from "../validateChatRequest"; - const mockSelectAccountEmails = vi.mocked(selectAccountEmails); const mockSelectRoom = vi.mocked(selectRoom); const mockUpsertRoom = vi.mocked(upsertRoom); @@ -55,6 +55,12 @@ const mockHandleSendEmailToolOutputs = vi.mocked(handleSendEmailToolOutputs); const mockSendErrorNotification = vi.mocked(sendErrorNotification); // Helper to create mock UIMessage +/** + * + * @param id + * @param role + * @param text + */ function createMockUIMessage(id: string, role: "user" | "assistant", text: string): UIMessage { return { id, @@ -65,6 +71,10 @@ function createMockUIMessage(id: string, role: "user" | "assistant", text: strin } // Helper to create mock ChatRequestBody +/** + * + * @param overrides + */ function createMockBody(overrides: Partial = {}): ChatRequestBody { return { accountId: "account-123", @@ -122,7 +132,7 @@ describe("handleChatCompletion", () => { const responseMessages = [createMockUIMessage("resp-1", "assistant", "Hi there!")]; const callOrder: string[] = []; - mockUpsertMemory.mockImplementation(async (params) => { + mockUpsertMemory.mockImplementation(async params => { callOrder.push(params.id); return null; }); diff --git a/lib/chat/__tests__/integration/chatEndToEnd.test.ts b/lib/chat/__tests__/integration/chatEndToEnd.test.ts index 6e075cc94..f08d5bcb1 100644 --- a/lib/chat/__tests__/integration/chatEndToEnd.test.ts +++ b/lib/chat/__tests__/integration/chatEndToEnd.test.ts @@ -1,6 +1,24 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { NextResponse } from "next/server"; +import { getApiKeyAccountId } from "@/lib/auth/getApiKeyAccountId"; +import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails"; +import { selectAccountInfo } from "@/lib/supabase/account_info/selectAccountInfo"; +import { getAccountWithDetails } from "@/lib/supabase/accounts/getAccountWithDetails"; +import { getKnowledgeBaseText } from "@/lib/files/getKnowledgeBaseText"; +import selectRoom from "@/lib/supabase/rooms/selectRoom"; +import { upsertRoom } from "@/lib/supabase/rooms/upsertRoom"; +import upsertMemory from "@/lib/supabase/memories/upsertMemory"; +import { sendNewConversationNotification } from "@/lib/telegram/sendNewConversationNotification"; +import { handleSendEmailToolOutputs } from "@/lib/emails/handleSendEmailToolOutputs"; +import { getCreditUsage } from "@/lib/credits/getCreditUsage"; +import { deductCredits } from "@/lib/credits/deductCredits"; +import { generateChatTitle } from "../../generateChatTitle"; +import { handleChatCompletion } from "../../handleChatCompletion"; +import { handleChatCredits } from "@/lib/credits/handleChatCredits"; +import { validateChatRequest } from "../../validateChatRequest"; +import { setupChatRequest } from "../../setupChatRequest"; + /** * Integration tests for chat endpoints. * @@ -137,24 +155,6 @@ vi.mock("ai", () => ({ })), })); -import { getApiKeyAccountId } from "@/lib/auth/getApiKeyAccountId"; -import selectAccountEmails from "@/lib/supabase/account_emails/selectAccountEmails"; -import { selectAccountInfo } from "@/lib/supabase/account_info/selectAccountInfo"; -import { getAccountWithDetails } from "@/lib/supabase/accounts/getAccountWithDetails"; -import { getKnowledgeBaseText } from "@/lib/files/getKnowledgeBaseText"; -import selectRoom from "@/lib/supabase/rooms/selectRoom"; -import { upsertRoom } from "@/lib/supabase/rooms/upsertRoom"; -import upsertMemory from "@/lib/supabase/memories/upsertMemory"; -import { sendNewConversationNotification } from "@/lib/telegram/sendNewConversationNotification"; -import { handleSendEmailToolOutputs } from "@/lib/emails/handleSendEmailToolOutputs"; -import { getCreditUsage } from "@/lib/credits/getCreditUsage"; -import { deductCredits } from "@/lib/credits/deductCredits"; -import { generateChatTitle } from "../../generateChatTitle"; -import { handleChatCompletion } from "../../handleChatCompletion"; -import { handleChatCredits } from "@/lib/credits/handleChatCredits"; -import { validateChatRequest } from "../../validateChatRequest"; -import { setupChatRequest } from "../../setupChatRequest"; - const mockGetApiKeyAccountId = vi.mocked(getApiKeyAccountId); const mockSelectAccountEmails = vi.mocked(selectAccountEmails); const mockSelectAccountInfo = vi.mocked(selectAccountInfo); @@ -170,10 +170,12 @@ const mockDeductCredits = vi.mocked(deductCredits); const mockGenerateChatTitle = vi.mocked(generateChatTitle); // Helper to create mock NextRequest -function createMockRequest( - body: unknown, - headers: Record = {}, -): Request { +/** + * + * @param body + * @param headers + */ +function createMockRequest(body: unknown, headers: Record = {}): Request { return { json: () => Promise.resolve(body), headers: { @@ -210,10 +212,7 @@ describe("Chat Integration Tests", () => { it("validates and returns body for valid request with prompt", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "valid-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "valid-key" }); const result = await validateChatRequest(request as any); @@ -251,16 +250,10 @@ describe("Chat Integration Tests", () => { it("returns 401 when API key lookup fails", async () => { // getApiKeyAccountId returns a NextResponse when authentication fails mockGetApiKeyAccountId.mockResolvedValue( - NextResponse.json( - { status: "error", message: "Unauthorized" }, - { status: 401 }, - ), + NextResponse.json({ status: "error", message: "Unauthorized" }, { status: 401 }), ); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "invalid-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "invalid-key" }); const result = await validateChatRequest(request as any); @@ -271,10 +264,7 @@ describe("Chat Integration Tests", () => { it("returns 400 when neither messages nor prompt is provided", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { roomId: "room-123" }, - { "x-api-key": "valid-key" }, - ); + const request = createMockRequest({ roomId: "room-123" }, { "x-api-key": "valid-key" }); const result = await validateChatRequest(request as any); @@ -406,9 +396,7 @@ describe("Chat Integration Tests", () => { mockGenerateChatTitle.mockResolvedValue("New Chat Title"); const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }], roomId: "new-room-123", accountId: "account-123", }; @@ -433,9 +421,7 @@ describe("Chat Integration Tests", () => { mockSelectRoom.mockResolvedValue({ id: "existing-room" } as any); const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }], roomId: "existing-room", accountId: "account-123", }; @@ -454,9 +440,7 @@ describe("Chat Integration Tests", () => { mockSelectRoom.mockResolvedValue({ id: "room-123" } as any); const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }], roomId: "room-123", accountId: "account-123", }; @@ -486,9 +470,7 @@ describe("Chat Integration Tests", () => { mockSelectRoom.mockResolvedValue({ id: "room-123" } as any); const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Send an email" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Send an email" }] }], roomId: "room-123", accountId: "account-123", }; @@ -516,9 +498,7 @@ describe("Chat Integration Tests", () => { mockSelectRoom.mockRejectedValue(new Error("Database error")); const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }], roomId: "room-123", accountId: "account-123", }; @@ -535,9 +515,7 @@ describe("Chat Integration Tests", () => { it("handles empty roomId by defaulting to empty string", async () => { const body = { - messages: [ - { id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }, - ], + messages: [{ id: "msg-1", role: "user", parts: [{ type: "text", text: "Hello" }] }], accountId: "account-123", // roomId not provided }; @@ -629,10 +607,7 @@ describe("Chat Integration Tests", () => { it("validates prompt-based requests through full pipeline", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { prompt: "What is 2+2?" }, - { "x-api-key": "valid-key" }, - ); + const request = createMockRequest({ prompt: "What is 2+2?" }, { "x-api-key": "valid-key" }); const validationResult = await validateChatRequest(request as any); expect(validationResult).not.toBeInstanceOf(NextResponse); diff --git a/lib/chat/__tests__/saveChatCompletion.test.ts b/lib/chat/__tests__/saveChatCompletion.test.ts index f25d7177e..ddd995f67 100644 --- a/lib/chat/__tests__/saveChatCompletion.test.ts +++ b/lib/chat/__tests__/saveChatCompletion.test.ts @@ -1,5 +1,10 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { getMessages } from "@/lib/messages/getMessages"; +import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; +import insertMemories from "@/lib/supabase/memories/insertMemories"; +import { saveChatCompletion } from "../saveChatCompletion"; + // Mock dependencies before importing the module under test vi.mock("@/lib/messages/getMessages", () => ({ getMessages: vi.fn(), @@ -13,11 +18,6 @@ vi.mock("@/lib/supabase/memories/insertMemories", () => ({ default: vi.fn(), })); -import { getMessages } from "@/lib/messages/getMessages"; -import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; -import insertMemories from "@/lib/supabase/memories/insertMemories"; -import { saveChatCompletion } from "../saveChatCompletion"; - const mockGetMessages = vi.mocked(getMessages); const mockFilterMessageContentForMemories = vi.mocked(filterMessageContentForMemories); const mockInsertMemories = vi.mocked(insertMemories); diff --git a/lib/chat/__tests__/setupConversation.test.ts b/lib/chat/__tests__/setupConversation.test.ts index 9f395d3d6..f0b8f3176 100644 --- a/lib/chat/__tests__/setupConversation.test.ts +++ b/lib/chat/__tests__/setupConversation.test.ts @@ -1,5 +1,12 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { generateUUID } from "@/lib/uuid/generateUUID"; +import { createNewRoom } from "@/lib/chat/createNewRoom"; +import insertMemories from "@/lib/supabase/memories/insertMemories"; +import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; +import selectRoom from "@/lib/supabase/rooms/selectRoom"; +import { setupConversation } from "../setupConversation"; + // Mock dependencies vi.mock("@/lib/uuid/generateUUID", () => { const mockFn = vi.fn(() => "mock-uuid"); @@ -25,13 +32,6 @@ vi.mock("@/lib/supabase/rooms/selectRoom", () => ({ default: vi.fn(), })); -import { generateUUID } from "@/lib/uuid/generateUUID"; -import { createNewRoom } from "@/lib/chat/createNewRoom"; -import insertMemories from "@/lib/supabase/memories/insertMemories"; -import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; -import selectRoom from "@/lib/supabase/rooms/selectRoom"; -import { setupConversation } from "../setupConversation"; - const mockGenerateUUID = vi.mocked(generateUUID); const mockCreateNewRoom = vi.mocked(createNewRoom); const mockInsertMemories = vi.mocked(insertMemories); diff --git a/lib/chat/__tests__/setupToolsForRequest.test.ts b/lib/chat/__tests__/setupToolsForRequest.test.ts index c5b4bbf24..68b0b48c3 100644 --- a/lib/chat/__tests__/setupToolsForRequest.test.ts +++ b/lib/chat/__tests__/setupToolsForRequest.test.ts @@ -1,6 +1,11 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { ChatRequestBody } from "../validateChatRequest"; +// Import after mocks +import { setupToolsForRequest } from "../setupToolsForRequest"; +import { getMcpTools } from "@/lib/mcp/getMcpTools"; +import { getComposioTools } from "@/lib/composio/toolRouter"; + // Mock external dependencies vi.mock("@/lib/mcp/getMcpTools", () => ({ getMcpTools: vi.fn(), @@ -10,11 +15,6 @@ vi.mock("@/lib/composio/toolRouter", () => ({ getComposioTools: vi.fn(), })); -// Import after mocks -import { setupToolsForRequest } from "../setupToolsForRequest"; -import { getMcpTools } from "@/lib/mcp/getMcpTools"; -import { getComposioTools } from "@/lib/composio/toolRouter"; - const mockGetMcpTools = vi.mocked(getMcpTools); const mockGetComposioTools = vi.mocked(getComposioTools); @@ -238,14 +238,14 @@ describe("setupToolsForRequest", () => { // Track when each operation starts and completes mockGetMcpTools.mockImplementation(async () => { executionOrder.push("getMcpTools:start"); - await new Promise((resolve) => setTimeout(resolve, 10)); + await new Promise(resolve => setTimeout(resolve, 10)); executionOrder.push("getMcpTools:end"); return { mcpTool: { description: "MCP Tool", parameters: {} } }; }); mockGetComposioTools.mockImplementation(async () => { executionOrder.push("getComposioTools:start"); - await new Promise((resolve) => setTimeout(resolve, 10)); + await new Promise(resolve => setTimeout(resolve, 10)); executionOrder.push("getComposioTools:end"); return { composioTool: { description: "Composio Tool", parameters: {} } }; }); @@ -293,6 +293,4 @@ describe("setupToolsForRequest", () => { expect(mockGetComposioTools).toHaveBeenCalledTimes(1); }); }); - - }); diff --git a/lib/chat/__tests__/validateChatRequest.test.ts b/lib/chat/__tests__/validateChatRequest.test.ts index a5876eca5..2f7651d08 100644 --- a/lib/chat/__tests__/validateChatRequest.test.ts +++ b/lib/chat/__tests__/validateChatRequest.test.ts @@ -2,6 +2,17 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextResponse } from "next/server"; import { validateChatRequest, chatRequestSchema } from "../validateChatRequest"; +import { getApiKeyAccountId } from "@/lib/auth/getApiKeyAccountId"; +import { getAuthenticatedAccountId } from "@/lib/auth/getAuthenticatedAccountId"; +import { validateOverrideAccountId } from "@/lib/accounts/validateOverrideAccountId"; +import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; +import { validateOrganizationAccess } from "@/lib/organizations/validateOrganizationAccess"; +import { generateUUID } from "@/lib/uuid/generateUUID"; +import { createNewRoom } from "@/lib/chat/createNewRoom"; +import insertMemories from "@/lib/supabase/memories/insertMemories"; +import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; +import { setupConversation } from "@/lib/chat/setupConversation"; + // Mock dependencies vi.mock("@/lib/auth/getApiKeyAccountId", () => ({ getApiKeyAccountId: vi.fn(), @@ -47,17 +58,6 @@ vi.mock("@/lib/chat/setupConversation", () => ({ setupConversation: vi.fn(), })); -import { getApiKeyAccountId } from "@/lib/auth/getApiKeyAccountId"; -import { getAuthenticatedAccountId } from "@/lib/auth/getAuthenticatedAccountId"; -import { validateOverrideAccountId } from "@/lib/accounts/validateOverrideAccountId"; -import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; -import { validateOrganizationAccess } from "@/lib/organizations/validateOrganizationAccess"; -import { generateUUID } from "@/lib/uuid/generateUUID"; -import { createNewRoom } from "@/lib/chat/createNewRoom"; -import insertMemories from "@/lib/supabase/memories/insertMemories"; -import filterMessageContentForMemories from "@/lib/messages/filterMessageContentForMemories"; -import { setupConversation } from "@/lib/chat/setupConversation"; - const mockGetApiKeyAccountId = vi.mocked(getApiKeyAccountId); const mockGetAuthenticatedAccountId = vi.mocked(getAuthenticatedAccountId); const mockValidateOverrideAccountId = vi.mocked(validateOverrideAccountId); @@ -70,6 +70,11 @@ const mockFilterMessageContentForMemories = vi.mocked(filterMessageContentForMem const mockSetupConversation = vi.mocked(setupConversation); // Helper to create mock NextRequest +/** + * + * @param body + * @param headers + */ function createMockRequest(body: unknown, headers: Record = {}): Request { return { json: () => Promise.resolve(body), @@ -94,10 +99,7 @@ describe("validateChatRequest", () => { it("rejects when neither messages nor prompt is provided", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { roomId: "room-123" }, - { "x-api-key": "test-key" }, - ); + const request = createMockRequest({ roomId: "room-123" }, { "x-api-key": "test-key" }); const result = await validateChatRequest(request as any); @@ -143,10 +145,7 @@ describe("validateChatRequest", () => { it("accepts valid prompt string", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { prompt: "Hello, world!" }, - { "x-api-key": "test-key" }, - ); + const request = createMockRequest({ prompt: "Hello, world!" }, { "x-api-key": "test-key" }); const result = await validateChatRequest(request as any); @@ -183,16 +182,10 @@ describe("validateChatRequest", () => { it("rejects request with invalid API key", async () => { mockGetApiKeyAccountId.mockResolvedValue( - NextResponse.json( - { status: "error", message: "Invalid API key" }, - { status: 401 }, - ), + NextResponse.json({ status: "error", message: "Invalid API key" }, { status: 401 }), ); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "invalid-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "invalid-key" }); const result = await validateChatRequest(request as any); @@ -202,10 +195,7 @@ describe("validateChatRequest", () => { it("uses accountId from valid API key", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-abc-123"); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "valid-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "valid-key" }); const result = await validateChatRequest(request as any); @@ -254,10 +244,7 @@ describe("validateChatRequest", () => { orgId: "org-account-123", }); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "org-api-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "org-api-key" }); const result = await validateChatRequest(request as any); @@ -273,10 +260,7 @@ describe("validateChatRequest", () => { orgId: null, }); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "personal-api-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "personal-api-key" }); const result = await validateChatRequest(request as any); @@ -350,10 +334,7 @@ describe("validateChatRequest", () => { it("converts prompt to messages array", async () => { mockGetApiKeyAccountId.mockResolvedValue("account-123"); - const request = createMockRequest( - { prompt: "Hello, world!" }, - { "x-api-key": "test-key" }, - ); + const request = createMockRequest({ prompt: "Hello, world!" }, { "x-api-key": "test-key" }); const result = await validateChatRequest(request as any); @@ -583,10 +564,7 @@ describe("validateChatRequest", () => { orgId: "api-key-org-123", }); - const request = createMockRequest( - { prompt: "Hello" }, - { "x-api-key": "org-api-key" }, - ); + const request = createMockRequest({ prompt: "Hello" }, { "x-api-key": "org-api-key" }); const result = await validateChatRequest(request as any); @@ -635,7 +613,10 @@ describe("validateChatRequest", () => { memoryId: "memory-id", }); - const request = createMockRequest({ prompt: "Create a new room" }, { "x-api-key": "test-key" }); + const request = createMockRequest( + { prompt: "Create a new room" }, + { "x-api-key": "test-key" }, + ); await validateChatRequest(request as any); diff --git a/lib/chat/handleChatCompletion.ts b/lib/chat/handleChatCompletion.ts index 0a162ec66..81dedabb6 100644 --- a/lib/chat/handleChatCompletion.ts +++ b/lib/chat/handleChatCompletion.ts @@ -47,8 +47,7 @@ export async function handleChatCompletion( // Create room and send notification if this is a new conversation if (!room) { - const latestMessageText = - lastMessage.parts.find((part) => part.type === "text")?.text || ""; + const latestMessageText = lastMessage.parts.find(part => part.type === "text")?.text || ""; const conversationName = await generateChatTitle(latestMessageText); await Promise.all([ diff --git a/lib/chat/handleChatStream.ts b/lib/chat/handleChatStream.ts index fe9713747..b181bcdec 100644 --- a/lib/chat/handleChatStream.ts +++ b/lib/chat/handleChatStream.ts @@ -31,25 +31,23 @@ export async function handleChatStream(request: NextRequest): Promise const stream = createUIMessageStream({ originalMessages: body.messages, generateId: generateUUID, - execute: async (options) => { + execute: async options => { const { writer } = options; const result = await agent.stream(chatConfig); writer.merge(result.toUIMessageStream()); // Note: Credit handling and chat completion handling will be added // as part of the handleChatCredits and handleChatCompletion migrations }, - onFinish: async (event) => { + onFinish: async event => { if (event.isAborted) { return; } - const assistantMessages = event.messages.filter( - (message) => message.role === "assistant", - ); + const assistantMessages = event.messages.filter(message => message.role === "assistant"); const responseMessages = assistantMessages.length > 0 ? assistantMessages : [event.responseMessage]; await handleChatCompletion(body, responseMessages); }, - onError: (e) => { + onError: e => { console.error("/api/chat onError:", e); return JSON.stringify({ status: "error", diff --git a/lib/chat/toolChains/__tests__/getPrepareStepResult.test.ts b/lib/chat/toolChains/__tests__/getPrepareStepResult.test.ts index 3f1ace6b6..df582c015 100644 --- a/lib/chat/toolChains/__tests__/getPrepareStepResult.test.ts +++ b/lib/chat/toolChains/__tests__/getPrepareStepResult.test.ts @@ -1,13 +1,11 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import getPrepareStepResult from "../getPrepareStepResult"; + // Mock the toolChains module vi.mock("../toolChains", () => ({ TOOL_CHAINS: { - test_trigger: [ - { toolName: "step_one" }, - { toolName: "step_two" }, - { toolName: "step_three" }, - ], + test_trigger: [{ toolName: "step_one" }, { toolName: "step_two" }, { toolName: "step_three" }], custom_chain: [ { toolName: "custom_step_one", @@ -25,8 +23,6 @@ vi.mock("../toolChains", () => ({ }, })); -import getPrepareStepResult from "../getPrepareStepResult"; - describe("getPrepareStepResult", () => { beforeEach(() => { vi.clearAllMocks(); @@ -50,7 +46,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "unrelated_tool", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "unrelated_tool", + output: { type: "json", value: {} }, + }, ], }, ], @@ -70,7 +70,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, ], @@ -90,7 +94,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, { @@ -116,7 +124,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, { @@ -149,12 +161,20 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, { toolResults: [ - { toolCallId: "call-2", toolName: "some_other_tool", output: { type: "json", value: {} } }, + { + toolCallId: "call-2", + toolName: "some_other_tool", + output: { type: "json", value: {} }, + }, ], }, { @@ -183,7 +203,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "custom_chain", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "custom_chain", + output: { type: "json", value: {} }, + }, ], }, ], @@ -206,12 +230,20 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "custom_chain", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "custom_chain", + output: { type: "json", value: {} }, + }, ], }, { toolResults: [ - { toolCallId: "call-2", toolName: "custom_step_one", output: { type: "json", value: {} } }, + { + toolCallId: "call-2", + toolName: "custom_step_one", + output: { type: "json", value: {} }, + }, ], }, ], @@ -237,7 +269,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, { @@ -260,7 +296,11 @@ describe("getPrepareStepResult", () => { steps: [ { toolResults: [ - { toolCallId: "call-1", toolName: "test_trigger", output: { type: "json", value: {} } }, + { + toolCallId: "call-1", + toolName: "test_trigger", + output: { type: "json", value: {} }, + }, ], }, ], diff --git a/lib/chat/toolChains/__tests__/toolChains.test.ts b/lib/chat/toolChains/__tests__/toolChains.test.ts index 59a23aabd..fdd5782f6 100644 --- a/lib/chat/toolChains/__tests__/toolChains.test.ts +++ b/lib/chat/toolChains/__tests__/toolChains.test.ts @@ -1,10 +1,5 @@ import { describe, it, expect } from "vitest"; -import { - TOOL_CHAINS, - TOOL_MODEL_MAP, - ToolChainItem, - PrepareStepResult, -} from "../toolChains"; +import { TOOL_CHAINS, TOOL_MODEL_MAP, ToolChainItem, PrepareStepResult } from "../toolChains"; describe("toolChains", () => { describe("ToolChainItem type", () => { @@ -86,7 +81,7 @@ describe("toolChains", () => { it("includes update_account_info with custom system prompt", () => { const chain = TOOL_CHAINS.create_new_artist; const updateAccountStep = chain.find( - (item) => item.toolName === "update_account_info" && item.system + item => item.toolName === "update_account_info" && item.system, ); expect(updateAccountStep).toBeDefined(); expect(updateAccountStep?.system).toContain("get_spotify_search"); @@ -106,16 +101,14 @@ describe("toolChains", () => { it("does not include create_knowledge_base tool", () => { const chain = TOOL_CHAINS.create_new_artist; const hasCreateKnowledgeBase = chain.some( - (item) => item.toolName === "create_knowledge_base" + item => item.toolName === "create_knowledge_base", ); expect(hasCreateKnowledgeBase).toBe(false); }); it("includes generate_txt_file with system prompt for knowledge base report", () => { const chain = TOOL_CHAINS.create_new_artist; - const generateStep = chain.find( - (item) => item.toolName === "generate_txt_file" - ); + const generateStep = chain.find(item => item.toolName === "generate_txt_file"); expect(generateStep).toBeDefined(); expect(generateStep?.system).toBeDefined(); expect(generateStep?.system).toContain("knowledge base report"); @@ -123,12 +116,8 @@ describe("toolChains", () => { it("includes update_account_info step with system prompt to link knowledge base", () => { const chain = TOOL_CHAINS.create_new_artist; - const updateSteps = chain.filter( - (item) => item.toolName === "update_account_info" - ); - const knowledgeLinkStep = updateSteps.find( - (item) => item.system?.includes("knowledges") - ); + const updateSteps = chain.filter(item => item.toolName === "update_account_info"); + const knowledgeLinkStep = updateSteps.find(item => item.system?.includes("knowledges")); expect(knowledgeLinkStep).toBeDefined(); expect(knowledgeLinkStep?.system).toContain("arweaveUrl"); }); @@ -142,9 +131,7 @@ describe("toolChains", () => { it("includes generate_txt_file with custom system prompt", () => { const chain = TOOL_CHAINS.create_release_report; - const generateStep = chain.find( - (item) => item.toolName === "generate_txt_file" - ); + const generateStep = chain.find(item => item.toolName === "generate_txt_file"); expect(generateStep).toBeDefined(); expect(generateStep?.system).toBeDefined(); }); diff --git a/lib/chat/toolChains/getExecutedToolTimeline.ts b/lib/chat/toolChains/getExecutedToolTimeline.ts index 1e522d701..32bf281a0 100644 --- a/lib/chat/toolChains/getExecutedToolTimeline.ts +++ b/lib/chat/toolChains/getExecutedToolTimeline.ts @@ -10,16 +10,16 @@ type ToolCallContent = { const getExecutedToolTimeline = (steps: StepResult[]): string[] => { const toolCallsContent = steps.flatMap( (step): ToolCallContent[] => - step.toolResults?.map((result) => ({ + step.toolResults?.map(result => ({ type: "tool-result" as const, toolCallId: result.toolCallId || "", toolName: result.toolName, output: { type: "json" as const, value: result.output }, - })) || [] + })) || [], ); // Build timeline of executed tools from toolCallsContent - return toolCallsContent.map((call) => call.toolName); + return toolCallsContent.map(call => call.toolName); }; export default getExecutedToolTimeline; diff --git a/lib/chat/toolChains/getPrepareStepResult.ts b/lib/chat/toolChains/getPrepareStepResult.ts index 5a908afa3..c011c078e 100644 --- a/lib/chat/toolChains/getPrepareStepResult.ts +++ b/lib/chat/toolChains/getPrepareStepResult.ts @@ -12,10 +12,10 @@ type PrepareStepOptions = { /** * Returns the next tool to run based on timeline progression through tool chains. * Uses toolCallsContent to track exact execution order and position in sequence. + * + * @param options */ -const getPrepareStepResult = ( - options: PrepareStepOptions -): PrepareStepResult | undefined => { +const getPrepareStepResult = (options: PrepareStepOptions): PrepareStepResult | undefined => { const { steps } = options; // Extract tool calls timeline (history) from steps const executedTimeline = getExecutedToolTimeline(steps); @@ -32,10 +32,7 @@ const getPrepareStepResult = ( let timelinePosition = triggerIndex; // Walk through the timeline starting from trigger - while ( - timelinePosition < executedTimeline.length && - sequencePosition < fullSequence.length - ) { + while (timelinePosition < executedTimeline.length && sequencePosition < fullSequence.length) { const currentTool = executedTimeline[timelinePosition]; const expectedTool = fullSequence[sequencePosition].toolName; diff --git a/lib/chat/toolChains/index.ts b/lib/chat/toolChains/index.ts index 7d52b25e2..24bc4a877 100644 --- a/lib/chat/toolChains/index.ts +++ b/lib/chat/toolChains/index.ts @@ -1,4 +1,9 @@ -export { TOOL_CHAINS, TOOL_MODEL_MAP, type ToolChainItem, type PrepareStepResult } from "./toolChains"; +export { + TOOL_CHAINS, + TOOL_MODEL_MAP, + type ToolChainItem, + type PrepareStepResult, +} from "./toolChains"; export { default as getPrepareStepResult } from "./getPrepareStepResult"; export { default as getExecutedToolTimeline } from "./getExecutedToolTimeline"; export { createNewArtistToolChain } from "./createNewArtistToolChain"; diff --git a/lib/chat/validateMessages.ts b/lib/chat/validateMessages.ts index 7ae4c8e0f..e67aec8f4 100644 --- a/lib/chat/validateMessages.ts +++ b/lib/chat/validateMessages.ts @@ -14,8 +14,6 @@ export function validateMessages(messages: UIMessage[]) { return { lastMessage: messages[messages.length - 1], - validMessages: messages.filter( - (m) => m.parts.find((part) => part.type === "text")?.text?.length, - ), + validMessages: messages.filter(m => m.parts.find(part => part.type === "text")?.text?.length), }; } diff --git a/lib/chats/__tests__/updateChatHandler.test.ts b/lib/chats/__tests__/updateChatHandler.test.ts index cbb33603e..b59695443 100644 --- a/lib/chats/__tests__/updateChatHandler.test.ts +++ b/lib/chats/__tests__/updateChatHandler.test.ts @@ -2,6 +2,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest, NextResponse } from "next/server"; import { updateChatHandler } from "../updateChatHandler"; +import { validateUpdateChatBody } from "@/lib/chats/validateUpdateChatBody"; +import { updateRoom } from "@/lib/supabase/rooms/updateRoom"; + vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => ({ "Access-Control-Allow-Origin": "*" })), })); @@ -14,9 +17,6 @@ vi.mock("@/lib/supabase/rooms/updateRoom", () => ({ updateRoom: vi.fn(), })); -import { validateUpdateChatBody } from "@/lib/chats/validateUpdateChatBody"; -import { updateRoom } from "@/lib/supabase/rooms/updateRoom"; - describe("updateChatHandler", () => { const mockRequest = () => { return new NextRequest("http://localhost/api/chats", { @@ -87,10 +87,7 @@ describe("updateChatHandler", () => { it("returns 401 from validation when auth fails", async () => { vi.mocked(validateUpdateChatBody).mockResolvedValue( - NextResponse.json( - { status: "error", error: "Unauthorized" }, - { status: 401 }, - ), + NextResponse.json({ status: "error", error: "Unauthorized" }, { status: 401 }), ); const request = mockRequest(); @@ -102,10 +99,7 @@ describe("updateChatHandler", () => { it("returns 404 from validation when chat not found", async () => { vi.mocked(validateUpdateChatBody).mockResolvedValue( - NextResponse.json( - { status: "error", error: "Chat room not found" }, - { status: 404 }, - ), + NextResponse.json({ status: "error", error: "Chat room not found" }, { status: 404 }), ); const request = mockRequest(); diff --git a/lib/chats/__tests__/validateUpdateChatBody.test.ts b/lib/chats/__tests__/validateUpdateChatBody.test.ts index d3328d980..e59e8c646 100644 --- a/lib/chats/__tests__/validateUpdateChatBody.test.ts +++ b/lib/chats/__tests__/validateUpdateChatBody.test.ts @@ -2,6 +2,10 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest, NextResponse } from "next/server"; import { validateUpdateChatBody } from "../validateUpdateChatBody"; +import { validateAuthContext } from "@/lib/auth/validateAuthContext"; +import selectRoom from "@/lib/supabase/rooms/selectRoom"; +import { buildGetChatsParams } from "@/lib/chats/buildGetChatsParams"; + vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => ({ "Access-Control-Allow-Origin": "*" })), })); @@ -18,10 +22,6 @@ vi.mock("@/lib/chats/buildGetChatsParams", () => ({ buildGetChatsParams: vi.fn(), })); -import { validateAuthContext } from "@/lib/auth/validateAuthContext"; -import selectRoom from "@/lib/supabase/rooms/selectRoom"; -import { buildGetChatsParams } from "@/lib/chats/buildGetChatsParams"; - describe("validateUpdateChatBody", () => { beforeEach(() => { vi.clearAllMocks(); @@ -296,10 +296,7 @@ describe("validateUpdateChatBody", () => { describe("authentication errors", () => { it("returns 401 when auth fails", async () => { vi.mocked(validateAuthContext).mockResolvedValue( - NextResponse.json( - { status: "error", error: "Unauthorized" }, - { status: 401 }, - ), + NextResponse.json({ status: "error", error: "Unauthorized" }, { status: 401 }), ); const request = createRequest({ diff --git a/lib/chats/buildGetChatsParams.ts b/lib/chats/buildGetChatsParams.ts index 71f3c0970..f27236518 100644 --- a/lib/chats/buildGetChatsParams.ts +++ b/lib/chats/buildGetChatsParams.ts @@ -58,7 +58,7 @@ export async function buildGetChatsParams( if (org_id) { // Org key: fetch all member account IDs for this organization const orgMembers = await getAccountOrganizations({ organizationId: org_id }); - const memberAccountIds = orgMembers.map((member) => member.account_id); + const memberAccountIds = orgMembers.map(member => member.account_id); return { params: { account_ids: memberAccountIds, artist_id }, error: null }; } diff --git a/lib/chats/processCompactChatRequest.ts b/lib/chats/processCompactChatRequest.ts index 73ba607cf..ba085123e 100644 --- a/lib/chats/processCompactChatRequest.ts +++ b/lib/chats/processCompactChatRequest.ts @@ -18,6 +18,10 @@ interface ProcessCompactChatRequestParams { * Verifies the chat exists and the user has access before compacting. * * @param params - The parameters for processing the chat compaction. + * @param params.chatId + * @param params.prompt + * @param params.accountId + * @param params.orgId * @returns The result of the compaction attempt. */ export async function processCompactChatRequest({ diff --git a/lib/coding-agent/__tests__/encodeGitHubThreadId.test.ts b/lib/coding-agent/__tests__/encodeGitHubThreadId.test.ts index b69c72248..10afc1971 100644 --- a/lib/coding-agent/__tests__/encodeGitHubThreadId.test.ts +++ b/lib/coding-agent/__tests__/encodeGitHubThreadId.test.ts @@ -3,9 +3,9 @@ import { encodeGitHubThreadId } from "../encodeGitHubThreadId"; describe("encodeGitHubThreadId", () => { it("encodes PR-level thread ID", () => { - expect( - encodeGitHubThreadId({ owner: "recoupable", repo: "tasks", prNumber: 68 }), - ).toBe("github:recoupable/tasks:68"); + expect(encodeGitHubThreadId({ owner: "recoupable", repo: "tasks", prNumber: 68 })).toBe( + "github:recoupable/tasks:68", + ); }); it("encodes review comment thread ID", () => { diff --git a/lib/coding-agent/__tests__/handleCodingAgentCallback.test.ts b/lib/coding-agent/__tests__/handleCodingAgentCallback.test.ts index 06819dca4..ebc0e519d 100644 --- a/lib/coding-agent/__tests__/handleCodingAgentCallback.test.ts +++ b/lib/coding-agent/__tests__/handleCodingAgentCallback.test.ts @@ -131,7 +131,9 @@ describe("handleCodingAgentCallback", () => { expect(response.status).toBe(200); // stdout should be posted first, then the card expect(mockPost).toHaveBeenCalledTimes(2); - expect(mockPost.mock.calls[0][0]).toBe("Created branch agent/fix-bug-1234\nModified 3 files in api/"); + expect(mockPost.mock.calls[0][0]).toBe( + "Created branch agent/fix-bug-1234\nModified 3 files in api/", + ); expect(mockPost.mock.calls[1][0]).toEqual(expect.objectContaining({ card: expect.anything() })); }); diff --git a/lib/coding-agent/__tests__/handleGitHubWebhook.test.ts b/lib/coding-agent/__tests__/handleGitHubWebhook.test.ts index 5e059f4e7..194a71701 100644 --- a/lib/coding-agent/__tests__/handleGitHubWebhook.test.ts +++ b/lib/coding-agent/__tests__/handleGitHubWebhook.test.ts @@ -45,6 +45,12 @@ const BASE_PAYLOAD = { }, }; +/** + * + * @param body + * @param event + * @param signature + */ function makeRequest(body: unknown, event = "issue_comment", signature = "valid") { return { text: () => Promise.resolve(JSON.stringify(body)), diff --git a/lib/coding-agent/__tests__/onMergeAction.test.ts b/lib/coding-agent/__tests__/onMergeAction.test.ts index fde843798..56f25c326 100644 --- a/lib/coding-agent/__tests__/onMergeAction.test.ts +++ b/lib/coding-agent/__tests__/onMergeAction.test.ts @@ -160,14 +160,15 @@ describe("registerOnMergeAction", () => { await handler({ thread: mockThread, actionId: "merge_pr:recoupable/api#42" }); expect(mockHandleMergeSuccess).not.toHaveBeenCalled(); - expect(mockThread.post).toHaveBeenCalledWith("❌ recoupable/api#42 failed to merge: Not allowed"); + expect(mockThread.post).toHaveBeenCalledWith( + "❌ recoupable/api#42 failed to merge: Not allowed", + ); }); it("merge button click triggers snapshot upsert in Supabase via handleMergeSuccess", async () => { // Use the real handleMergeSuccess instead of the mock to verify the full chain - const { handleMergeSuccess: realHandleMergeSuccess } = await vi.importActual< - typeof import("../handleMergeSuccess") - >("../handleMergeSuccess"); + const { handleMergeSuccess: realHandleMergeSuccess } = + await vi.importActual("../handleMergeSuccess"); mockHandleMergeSuccess.mockImplementation(realHandleMergeSuccess); mockMergeGithubPR.mockResolvedValue({ ok: true }); diff --git a/lib/coding-agent/__tests__/onMergeTestToMainAction.test.ts b/lib/coding-agent/__tests__/onMergeTestToMainAction.test.ts index 8405b85f8..f173d6cec 100644 --- a/lib/coding-agent/__tests__/onMergeTestToMainAction.test.ts +++ b/lib/coding-agent/__tests__/onMergeTestToMainAction.test.ts @@ -5,15 +5,16 @@ vi.mock("../mergeGithubBranch", () => ({ mergeGithubBranch: (...args: unknown[]) => mockMergeGithubBranch(...args), })); -const { registerOnMergeTestToMainAction } = await import( - "../handlers/onMergeTestToMainAction" -); +const { registerOnMergeTestToMainAction } = await import("../handlers/onMergeTestToMainAction"); beforeEach(() => { vi.clearAllMocks(); process.env.GITHUB_TOKEN = "ghp_test"; }); +/** + * + */ function createMockBot() { return { onAction: vi.fn() } as any; } @@ -36,7 +37,12 @@ describe("registerOnMergeTestToMainAction", () => { await handler({ thread: mockThread, actionId: "merge_test_to_main:recoupable/chat" }); - expect(mockMergeGithubBranch).toHaveBeenCalledWith("recoupable/chat", "test", "main", "ghp_test"); + expect(mockMergeGithubBranch).toHaveBeenCalledWith( + "recoupable/chat", + "test", + "main", + "ghp_test", + ); expect(mockThread.post).toHaveBeenCalledWith("✅ Merged test → main for recoupable/chat."); }); diff --git a/lib/coding-agent/__tests__/parseMergeTestToMainActionId.test.ts b/lib/coding-agent/__tests__/parseMergeTestToMainActionId.test.ts index 40a4683bd..4bfff65bf 100644 --- a/lib/coding-agent/__tests__/parseMergeTestToMainActionId.test.ts +++ b/lib/coding-agent/__tests__/parseMergeTestToMainActionId.test.ts @@ -3,7 +3,9 @@ import { parseMergeTestToMainActionId } from "../parseMergeTestToMainActionId"; describe("parseMergeTestToMainActionId", () => { it("parses a valid action ID", () => { - expect(parseMergeTestToMainActionId("merge_test_to_main:recoupable/api")).toBe("recoupable/api"); + expect(parseMergeTestToMainActionId("merge_test_to_main:recoupable/api")).toBe( + "recoupable/api", + ); }); it("parses action ID with hyphenated repo name", () => { diff --git a/lib/coding-agent/buildPRCard.ts b/lib/coding-agent/buildPRCard.ts index b46c6c1fc..61ca0a870 100644 --- a/lib/coding-agent/buildPRCard.ts +++ b/lib/coding-agent/buildPRCard.ts @@ -11,7 +11,9 @@ export function buildPRCard(title: string, prs: CodingAgentPR[]) { return Card({ title, children: [ - CardText(`${prs.map(pr => `- ${pr.repo}#${pr.number} → \`${pr.baseBranch}\``).join("\n")}\n\nReply in this thread to give feedback.`), + CardText( + `${prs.map(pr => `- ${pr.repo}#${pr.number} → \`${pr.baseBranch}\``).join("\n")}\n\nReply in this thread to give feedback.`, + ), Actions([ ...prs.flatMap(pr => [ LinkButton({ url: pr.url, label: `Review ${pr.repo}#${pr.number}` }), diff --git a/lib/coding-agent/encodeGitHubThreadId.ts b/lib/coding-agent/encodeGitHubThreadId.ts index 1cfff2fe4..f4797e435 100644 --- a/lib/coding-agent/encodeGitHubThreadId.ts +++ b/lib/coding-agent/encodeGitHubThreadId.ts @@ -6,6 +6,8 @@ import type { GitHubThreadId } from "@chat-adapter/github"; * * - PR-level: `github:{owner}/{repo}:{prNumber}` * - Review comment: `github:{owner}/{repo}:{prNumber}:rc:{reviewCommentId}` + * + * @param thread */ export function encodeGitHubThreadId(thread: GitHubThreadId): string { const { owner, repo, prNumber, reviewCommentId } = thread; diff --git a/lib/coding-agent/handleMergeSuccess.ts b/lib/coding-agent/handleMergeSuccess.ts index f026f48d4..c241923b8 100644 --- a/lib/coding-agent/handleMergeSuccess.ts +++ b/lib/coding-agent/handleMergeSuccess.ts @@ -7,6 +7,8 @@ import type { CodingAgentThreadState } from "./types"; * Handles post-merge cleanup after all PRs merged successfully. * Deletes the shared PR state keys for all repos and persists the latest * snapshot via upsertAccountSnapshot. + * + * @param state */ export async function handleMergeSuccess(state: CodingAgentThreadState): Promise { try { diff --git a/lib/coding-agent/handlers/onMergeAction.ts b/lib/coding-agent/handlers/onMergeAction.ts index ccb5a82c3..887e35254 100644 --- a/lib/coding-agent/handlers/onMergeAction.ts +++ b/lib/coding-agent/handlers/onMergeAction.ts @@ -36,9 +36,7 @@ export function registerOnMergeAction(bot: CodingAgentBot) { return; } - const pr = state?.prs?.find( - p => p.repo === parsed.repo && p.number === parsed.number, - ); + const pr = state?.prs?.find(p => p.repo === parsed.repo && p.number === parsed.number); if (!pr) { await thread.post(`PR ${parsed.repo}#${parsed.number} not found in this thread.`); @@ -54,9 +52,7 @@ export function registerOnMergeAction(bot: CodingAgentBot) { } // Remove merged PR from state - const remainingPrs = state!.prs!.filter( - p => !(p.repo === pr.repo && p.number === pr.number), - ); + const remainingPrs = state!.prs!.filter(p => !(p.repo === pr.repo && p.number === pr.number)); const allMerged = remainingPrs.length === 0; await thread.setState({ diff --git a/lib/coding-agent/mergeGithubBranch.ts b/lib/coding-agent/mergeGithubBranch.ts index 5efeff319..74024a0f8 100644 --- a/lib/coding-agent/mergeGithubBranch.ts +++ b/lib/coding-agent/mergeGithubBranch.ts @@ -24,22 +24,19 @@ export async function mergeGithubBranch( token: string, ): Promise { const [owner, repoName] = repo.split("/"); - const response = await fetch( - `https://api.github.com/repos/${owner}/${repoName}/merges`, - { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - Accept: "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - }, - body: JSON.stringify({ - base, - head, - commit_message: `Merge ${head} into ${base}`, - }), + const response = await fetch(`https://api.github.com/repos/${owner}/${repoName}/merges`, { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", }, - ); + body: JSON.stringify({ + base, + head, + commit_message: `Merge ${head} into ${base}`, + }), + }); // 201 = merged, 204 = already up to date (both are success) if (response.ok) { diff --git a/lib/coding-agent/parseMergeActionId.ts b/lib/coding-agent/parseMergeActionId.ts index 5118249eb..25fd3eeb5 100644 --- a/lib/coding-agent/parseMergeActionId.ts +++ b/lib/coding-agent/parseMergeActionId.ts @@ -1,6 +1,8 @@ /** * Parses a merge action ID like "merge_pr:recoupable/api#42" * into { repo, number } or null if the format doesn't match. + * + * @param actionId */ export function parseMergeActionId(actionId: string) { const match = actionId.match(/^merge_pr:(.+)#(\d+)$/); diff --git a/lib/coding-agent/parseMergeTestToMainActionId.ts b/lib/coding-agent/parseMergeTestToMainActionId.ts index 1228615fa..14133eac5 100644 --- a/lib/coding-agent/parseMergeTestToMainActionId.ts +++ b/lib/coding-agent/parseMergeTestToMainActionId.ts @@ -1,6 +1,8 @@ /** * Parses a merge_test_to_main action ID like "merge_test_to_main:recoupable/api" * into the repo string, or null if the format doesn't match. + * + * @param actionId */ export function parseMergeTestToMainActionId(actionId: string): string | null { const prefix = "merge_test_to_main:"; diff --git a/lib/coding-agent/postGitHubComment.ts b/lib/coding-agent/postGitHubComment.ts index 007c36a1f..be3993529 100644 --- a/lib/coding-agent/postGitHubComment.ts +++ b/lib/coding-agent/postGitHubComment.ts @@ -12,17 +12,14 @@ export async function postGitHubComment( ): Promise { const token = process.env.GITHUB_TOKEN; - const response = await fetch( - `https://api.github.com/repos/${repo}/issues/${prNumber}/comments`, - { - method: "POST", - headers: { - Authorization: `token ${token}`, - Accept: "application/vnd.github+json", - }, - body: JSON.stringify({ body }), + const response = await fetch(`https://api.github.com/repos/${repo}/issues/${prNumber}/comments`, { + method: "POST", + headers: { + Authorization: `token ${token}`, + Accept: "application/vnd.github+json", }, - ); + body: JSON.stringify({ body }), + }); if (!response.ok) { const text = await response.text(); diff --git a/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts b/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts index c214bf71f..d6c3fe31f 100644 --- a/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts +++ b/lib/composio/connectors/__tests__/getConnectorsHandler.test.ts @@ -62,9 +62,7 @@ describe("getConnectorsHandler", () => { { slug: "tiktok", name: "TikTok", isConnected: true }, ]); - const request = new NextRequest( - "http://localhost/api/connectors?account_id=account-456", - ); + const request = new NextRequest("http://localhost/api/connectors?account_id=account-456"); await getConnectorsHandler(request); // API is unopinionated — no allowedToolkits filtering diff --git a/lib/composio/connectors/__tests__/validateAuthorizeConnectorRequest.test.ts b/lib/composio/connectors/__tests__/validateAuthorizeConnectorRequest.test.ts index 879661004..294201c19 100644 --- a/lib/composio/connectors/__tests__/validateAuthorizeConnectorRequest.test.ts +++ b/lib/composio/connectors/__tests__/validateAuthorizeConnectorRequest.test.ts @@ -145,7 +145,10 @@ describe("validateAuthorizeConnectorRequest", () => { orgId: null, authToken: "test-token", }); - vi.mocked(checkAccountAccess).mockResolvedValue({ hasAccess: true, entityType: "organization" }); + vi.mocked(checkAccountAccess).mockResolvedValue({ + hasAccess: true, + entityType: "organization", + }); const request = new NextRequest("http://localhost/api/connectors/authorize", { method: "POST", diff --git a/lib/composio/connectors/__tests__/validateGetConnectorsRequest.test.ts b/lib/composio/connectors/__tests__/validateGetConnectorsRequest.test.ts index 5dc514ff9..dc51dbec8 100644 --- a/lib/composio/connectors/__tests__/validateGetConnectorsRequest.test.ts +++ b/lib/composio/connectors/__tests__/validateGetConnectorsRequest.test.ts @@ -62,7 +62,9 @@ describe("validateGetConnectorsRequest", () => { }); vi.mocked(checkAccountAccess).mockResolvedValue({ hasAccess: true, entityType: "artist" }); - const request = new NextRequest(`http://localhost/api/connectors?account_id=${mockTargetAccountId}`); + const request = new NextRequest( + `http://localhost/api/connectors?account_id=${mockTargetAccountId}`, + ); const result = await validateGetConnectorsRequest(request); expect(checkAccountAccess).toHaveBeenCalledWith(mockAccountId, mockTargetAccountId); @@ -82,7 +84,9 @@ describe("validateGetConnectorsRequest", () => { }); vi.mocked(checkAccountAccess).mockResolvedValue({ hasAccess: false }); - const request = new NextRequest(`http://localhost/api/connectors?account_id=${mockTargetAccountId}`); + const request = new NextRequest( + `http://localhost/api/connectors?account_id=${mockTargetAccountId}`, + ); const result = await validateGetConnectorsRequest(request); expect(result).toBeInstanceOf(NextResponse); diff --git a/lib/composio/connectors/disconnectConnectorHandler.ts b/lib/composio/connectors/disconnectConnectorHandler.ts index 02d935268..1bb348f60 100644 --- a/lib/composio/connectors/disconnectConnectorHandler.ts +++ b/lib/composio/connectors/disconnectConnectorHandler.ts @@ -36,7 +36,10 @@ export async function disconnectConnectorHandler(request: NextRequest): Promise< await disconnectConnector(connectedAccountId); } - return NextResponse.json({ success: true, message: "Connector disconnected" }, { status: 200, headers }); + return NextResponse.json( + { success: true, message: "Connector disconnected" }, + { status: 200, headers }, + ); } catch (error) { const message = error instanceof Error ? error.message : "Failed to disconnect connector"; return NextResponse.json({ error: message }, { status: 500, headers }); diff --git a/lib/composio/connectors/getConnectors.ts b/lib/composio/connectors/getConnectors.ts index be19f5c06..d89f5211e 100644 --- a/lib/composio/connectors/getConnectors.ts +++ b/lib/composio/connectors/getConnectors.ts @@ -15,12 +15,7 @@ export interface ConnectorInfo { * Passed explicitly to composio.create() because session.toolkits() * only returns the first 20 by default. */ -const SUPPORTED_TOOLKITS = [ - "googlesheets", - "googledrive", - "googledocs", - "tiktok", -]; +const SUPPORTED_TOOLKITS = ["googlesheets", "googledrive", "googledocs", "tiktok"]; /** * Options for getting connectors. diff --git a/lib/composio/connectors/validateAuthorizeConnectorRequest.ts b/lib/composio/connectors/validateAuthorizeConnectorRequest.ts index 134cda3c2..fa8e39f43 100644 --- a/lib/composio/connectors/validateAuthorizeConnectorRequest.ts +++ b/lib/composio/connectors/validateAuthorizeConnectorRequest.ts @@ -54,7 +54,10 @@ export async function validateAuthorizeConnectorRequest( if (account_id) { const accessResult = await checkAccountAccess(accountId, account_id); if (!accessResult.hasAccess) { - return NextResponse.json({ error: "Access denied to this account" }, { status: 403, headers }); + return NextResponse.json( + { error: "Access denied to this account" }, + { status: 403, headers }, + ); } // Build auth configs for custom OAuth diff --git a/lib/composio/connectors/validateDisconnectConnectorRequest.ts b/lib/composio/connectors/validateDisconnectConnectorRequest.ts index 6716f2856..5c39de414 100644 --- a/lib/composio/connectors/validateDisconnectConnectorRequest.ts +++ b/lib/composio/connectors/validateDisconnectConnectorRequest.ts @@ -50,7 +50,10 @@ export async function validateDisconnectConnectorRequest( // Disconnecting for another account - verify access to that account const accessResult = await checkAccountAccess(accountId, account_id); if (!accessResult.hasAccess) { - return NextResponse.json({ error: "Access denied to this account" }, { status: 403, headers }); + return NextResponse.json( + { error: "Access denied to this account" }, + { status: 403, headers }, + ); } } else { // Disconnecting account's own connection - verify ownership diff --git a/lib/composio/connectors/validateGetConnectorsRequest.ts b/lib/composio/connectors/validateGetConnectorsRequest.ts index 916eb315c..61fb90a9f 100644 --- a/lib/composio/connectors/validateGetConnectorsRequest.ts +++ b/lib/composio/connectors/validateGetConnectorsRequest.ts @@ -51,7 +51,10 @@ export async function validateGetConnectorsRequest( if (account_id) { const accessResult = await checkAccountAccess(accountId, account_id); if (!accessResult.hasAccess) { - return NextResponse.json({ error: "Access denied to this account" }, { status: 403, headers }); + return NextResponse.json( + { error: "Access denied to this account" }, + { status: 403, headers }, + ); } return { accountId: account_id }; diff --git a/lib/composio/getCallbackUrl.ts b/lib/composio/getCallbackUrl.ts index 570c92516..8c83505a3 100644 --- a/lib/composio/getCallbackUrl.ts +++ b/lib/composio/getCallbackUrl.ts @@ -19,6 +19,7 @@ interface CallbackOptions { * * @param options.destination - Where to redirect: "chat" or "connectors" * @param options.roomId - For chat destination, the room ID to return to + * @param options * @returns Full callback URL with success indicator */ export function getCallbackUrl(options: CallbackOptions): string { diff --git a/lib/composio/toolRouter/__tests__/createToolRouterSession.test.ts b/lib/composio/toolRouter/__tests__/createToolRouterSession.test.ts index 802de374d..2287b91bf 100644 --- a/lib/composio/toolRouter/__tests__/createToolRouterSession.test.ts +++ b/lib/composio/toolRouter/__tests__/createToolRouterSession.test.ts @@ -54,7 +54,12 @@ describe("createToolRouterSession", () => { it("should pass artist connections when account has no overlap", async () => { // Account has Google Sheets connected but NOT TikTok vi.mocked(getConnectors).mockResolvedValue([ - { slug: "googlesheets", name: "Google Sheets", isConnected: true, connectedAccountId: "gs-123" }, + { + slug: "googlesheets", + name: "Google Sheets", + isConnected: true, + connectedAccountId: "gs-123", + }, { slug: "tiktok", name: "TikTok", isConnected: false }, ]); diff --git a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts index 594717e52..cb32d4ab9 100644 --- a/lib/composio/toolRouter/__tests__/getComposioTools.test.ts +++ b/lib/composio/toolRouter/__tests__/getComposioTools.test.ts @@ -76,7 +76,11 @@ describe("getComposioTools", () => { expect(checkAccountArtistAccess).toHaveBeenCalledWith("account-123", "artist-456"); expect(getArtistConnectionsFromComposio).toHaveBeenCalledWith("artist-456"); - expect(createToolRouterSession).toHaveBeenCalledWith("account-123", "room-789", mockConnections); + expect(createToolRouterSession).toHaveBeenCalledWith( + "account-123", + "room-789", + mockConnections, + ); }); it("should skip artist connections when access is denied", async () => { diff --git a/lib/composio/toolRouter/createToolRouterSession.ts b/lib/composio/toolRouter/createToolRouterSession.ts index 2ecf2ec78..deb86406f 100644 --- a/lib/composio/toolRouter/createToolRouterSession.ts +++ b/lib/composio/toolRouter/createToolRouterSession.ts @@ -49,9 +49,7 @@ export async function createToolRouterSession( // Only keep artist connections for toolkits the account doesn't have filteredConnections = Object.fromEntries( - Object.entries(artistConnections).filter( - ([slug]) => !accountConnectedSlugs.has(slug), - ), + Object.entries(artistConnections).filter(([slug]) => !accountConnectedSlugs.has(slug)), ); // If nothing left after filtering, don't pass overrides at all diff --git a/lib/contact/contactTeam.ts b/lib/contact/contactTeam.ts index e10af73cd..f6880adbf 100644 --- a/lib/contact/contactTeam.ts +++ b/lib/contact/contactTeam.ts @@ -41,4 +41,3 @@ ${message}`; }; } } - diff --git a/lib/content/__tests__/createContentHandler.test.ts b/lib/content/__tests__/createContentHandler.test.ts index 64589da6e..c3d6d4738 100644 --- a/lib/content/__tests__/createContentHandler.test.ts +++ b/lib/content/__tests__/createContentHandler.test.ts @@ -128,4 +128,3 @@ describe("createContentHandler", () => { expect(body.runIds).toBeDefined(); }); }); - diff --git a/lib/content/__tests__/getArtistContentReadiness.test.ts b/lib/content/__tests__/getArtistContentReadiness.test.ts index e7cbf03e4..8be69a985 100644 --- a/lib/content/__tests__/getArtistContentReadiness.test.ts +++ b/lib/content/__tests__/getArtistContentReadiness.test.ts @@ -72,7 +72,9 @@ describe("getArtistContentReadiness", () => { expect(result.ready).toBe(true); expect(result.missing).toEqual([]); // config.json appears as a warning, not a blocker - expect(result.warnings.some(item => item.file === "config/content-creation/config.json")).toBe(true); + expect(result.warnings.some(item => item.file === "config/content-creation/config.json")).toBe( + true, + ); }); it("throws when account has no github repo", async () => { @@ -86,4 +88,3 @@ describe("getArtistContentReadiness", () => { ).rejects.toThrow("No GitHub repository configured for this account"); }); }); - diff --git a/lib/content/__tests__/persistCreateContentRunVideo.test.ts b/lib/content/__tests__/persistCreateContentRunVideo.test.ts index c1c168287..04e469b8b 100644 --- a/lib/content/__tests__/persistCreateContentRunVideo.test.ts +++ b/lib/content/__tests__/persistCreateContentRunVideo.test.ts @@ -181,7 +181,8 @@ describe("persistCreateContentRunVideo", () => { }, }; - await expect(persistCreateContentRunVideo(run)).rejects.toThrow("Failed to create or find file record"); + await expect(persistCreateContentRunVideo(run)).rejects.toThrow( + "Failed to create or find file record", + ); }); }); - diff --git a/lib/content/__tests__/validateCreateContentBody.test.ts b/lib/content/__tests__/validateCreateContentBody.test.ts index 1bc66a438..31b1c4619 100644 --- a/lib/content/__tests__/validateCreateContentBody.test.ts +++ b/lib/content/__tests__/validateCreateContentBody.test.ts @@ -20,6 +20,10 @@ vi.mock("@/lib/content/resolveArtistSlug", () => ({ resolveArtistSlug: vi.fn().mockResolvedValue("gatsby-grace"), })); +/** + * + * @param body + */ function createRequest(body: unknown): NextRequest { return new NextRequest("http://localhost/api/content/create", { method: "POST", @@ -119,4 +123,3 @@ describe("validateCreateContentBody", () => { } }); }); - diff --git a/lib/content/contentTemplates.ts b/lib/content/contentTemplates.ts index 6896c195a..66da0d334 100644 --- a/lib/content/contentTemplates.ts +++ b/lib/content/contentTemplates.ts @@ -25,7 +25,10 @@ export const CONTENT_TEMPLATES: ContentTemplate[] = [ /** Derived from the first entry in CONTENT_TEMPLATES to avoid string duplication. */ export const DEFAULT_CONTENT_TEMPLATE = CONTENT_TEMPLATES[0].name; +/** + * + * @param template + */ export function isSupportedContentTemplate(template: string): boolean { return CONTENT_TEMPLATES.some(item => item.name === template); } - diff --git a/lib/content/createContentHandler.ts b/lib/content/createContentHandler.ts index b0e845f3e..5459cbb89 100644 --- a/lib/content/createContentHandler.ts +++ b/lib/content/createContentHandler.ts @@ -9,6 +9,8 @@ import { selectAccountSnapshots } from "@/lib/supabase/account_snapshots/selectA /** * Handler for POST /api/content/create. * Always returns runIds array (KISS — one response shape for single and batch). + * + * @param request */ export async function createContentHandler(request: NextRequest): Promise { const validated = await validateCreateContentBody(request); diff --git a/lib/content/getArtistContentReadiness.ts b/lib/content/getArtistContentReadiness.ts index d199c0872..9238598e4 100644 --- a/lib/content/getArtistContentReadiness.ts +++ b/lib/content/getArtistContentReadiness.ts @@ -22,6 +22,11 @@ export interface ArtistContentReadiness { /** * Checks whether an artist has the expected files for content creation. * Searches the main repo and org submodule repos. + * + * @param root0 + * @param root0.accountId + * @param root0.artistAccountId + * @param root0.artistSlug */ export async function getArtistContentReadiness({ accountId, @@ -65,9 +70,7 @@ export async function getArtistContentReadiness({ const hasFile = (relativePath: string): boolean => blobPaths.some(path => path === `${artistRootPrefix}${relativePath}`); const hasAnyMp3 = blobPaths.some( - path => - path.startsWith(artistRootPrefix) && - path.toLowerCase().endsWith(".mp3"), + path => path.startsWith(artistRootPrefix) && path.toLowerCase().endsWith(".mp3"), ); const issues: ContentReadinessIssue[] = []; diff --git a/lib/content/getArtistFileTree.ts b/lib/content/getArtistFileTree.ts index 908855a00..b5392b527 100644 --- a/lib/content/getArtistFileTree.ts +++ b/lib/content/getArtistFileTree.ts @@ -4,6 +4,9 @@ import { getOrgRepoUrls } from "@/lib/github/getOrgRepoUrls"; /** * Gets the file tree that contains the artist, checking the main repo * first, then falling back to org submodule repos. + * + * @param githubRepo + * @param artistSlug */ export async function getArtistFileTree( githubRepo: string, diff --git a/lib/content/getArtistRootPrefix.ts b/lib/content/getArtistRootPrefix.ts index 5a777abe9..bf81d48a5 100644 --- a/lib/content/getArtistRootPrefix.ts +++ b/lib/content/getArtistRootPrefix.ts @@ -1,3 +1,8 @@ +/** + * + * @param paths + * @param artistSlug + */ export function getArtistRootPrefix(paths: string[], artistSlug: string): string { const preferredPrefix = `artists/${artistSlug}/`; if (paths.some(path => path.startsWith(preferredPrefix))) { diff --git a/lib/content/getContentValidateHandler.ts b/lib/content/getContentValidateHandler.ts index 268741c1e..81cd0ce86 100644 --- a/lib/content/getContentValidateHandler.ts +++ b/lib/content/getContentValidateHandler.ts @@ -8,6 +8,8 @@ import { getArtistContentReadiness } from "@/lib/content/getArtistContentReadine * Handler for GET /api/content/validate. * NOTE: Phase 1 returns structural readiness scaffolding. Deep filesystem checks * are performed in the background task before spend-heavy steps. + * + * @param request */ export async function getContentValidateHandler(request: NextRequest): Promise { const validated = await validateGetContentValidateQuery(request); @@ -42,4 +44,3 @@ export async function getContentValidateHandler(request: NextRequest): Promise(run: T): Promise { if (run.taskIdentifier !== CREATE_CONTENT_TASK_ID || !isCompletedRun(run)) { diff --git a/lib/content/resolveArtistSlug.ts b/lib/content/resolveArtistSlug.ts index c74a83793..8f5cc4b5d 100644 --- a/lib/content/resolveArtistSlug.ts +++ b/lib/content/resolveArtistSlug.ts @@ -9,9 +9,7 @@ import { selectAccounts } from "@/lib/supabase/accounts/selectAccounts"; * @param artistAccountId - The artist's account UUID * @returns The artist slug, or null if not found */ -export async function resolveArtistSlug( - artistAccountId: string, -): Promise { +export async function resolveArtistSlug(artistAccountId: string): Promise { const accounts = await selectAccounts(artistAccountId); const name = accounts[0]?.name; if (!name) return null; diff --git a/lib/content/validateCreateContentBody.ts b/lib/content/validateCreateContentBody.ts index 6d7cdc569..2c780e753 100644 --- a/lib/content/validateCreateContentBody.ts +++ b/lib/content/validateCreateContentBody.ts @@ -13,7 +13,9 @@ import { resolveArtistSlug } from "@/lib/content/resolveArtistSlug"; export const CAPTION_LENGTHS = ["short", "medium", "long"] as const; export const createContentBodySchema = z.object({ - artist_account_id: z.string({ message: "artist_account_id is required" }).uuid("artist_account_id must be a valid UUID"), + artist_account_id: z + .string({ message: "artist_account_id is required" }) + .uuid("artist_account_id must be a valid UUID"), template: z .string() .min(1, "template cannot be empty") @@ -38,6 +40,8 @@ export type ValidatedCreateContentBody = { /** * Validates auth and request body for POST /api/content/create. + * + * @param request */ export async function validateCreateContentBody( request: NextRequest, diff --git a/lib/content/validateGetContentEstimateQuery.ts b/lib/content/validateGetContentEstimateQuery.ts index 5828e7cc2..97af7468b 100644 --- a/lib/content/validateGetContentEstimateQuery.ts +++ b/lib/content/validateGetContentEstimateQuery.ts @@ -15,6 +15,8 @@ export type ValidatedGetContentEstimateQuery = z.infer ({ getModel: vi.fn(), })); -import { getModel } from "@/lib/ai/getModel"; -import { getCreditUsage } from "../getCreditUsage"; - const mockGetModel = vi.mocked(getModel); describe("getCreditUsage", () => { diff --git a/lib/credits/__tests__/handleChatCredits.test.ts b/lib/credits/__tests__/handleChatCredits.test.ts index 27f6a9a99..500b45bb8 100644 --- a/lib/credits/__tests__/handleChatCredits.test.ts +++ b/lib/credits/__tests__/handleChatCredits.test.ts @@ -1,5 +1,9 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { getCreditUsage } from "@/lib/credits/getCreditUsage"; +import { deductCredits } from "@/lib/credits/deductCredits"; +import { handleChatCredits } from "../handleChatCredits"; + vi.mock("@/lib/credits/getCreditUsage", () => ({ getCreditUsage: vi.fn(), })); @@ -8,10 +12,6 @@ vi.mock("@/lib/credits/deductCredits", () => ({ deductCredits: vi.fn(), })); -import { getCreditUsage } from "@/lib/credits/getCreditUsage"; -import { deductCredits } from "@/lib/credits/deductCredits"; -import { handleChatCredits } from "../handleChatCredits"; - const mockGetCreditUsage = vi.mocked(getCreditUsage); const mockDeductCredits = vi.mocked(deductCredits); @@ -143,10 +143,7 @@ describe("handleChatCredits", () => { accountId: "account-123", }); - expect(consoleSpy).toHaveBeenCalledWith( - "Failed to handle chat credits:", - expect.any(Error), - ); + expect(consoleSpy).toHaveBeenCalledWith("Failed to handle chat credits:", expect.any(Error)); }); }); }); diff --git a/lib/credits/getCreditUsage.ts b/lib/credits/getCreditUsage.ts index 846314c86..a74d104a4 100644 --- a/lib/credits/getCreditUsage.ts +++ b/lib/credits/getCreditUsage.ts @@ -3,6 +3,7 @@ import { LanguageModelUsage } from "ai"; /** * Calculates the total spend in USD for a given language model usage. + * * @param usage - The language model usage data * @param modelId - The ID of the model used * @returns The total spend in USD or 0 if calculation fails @@ -20,10 +21,8 @@ export const getCreditUsage = async ( // LanguageModelUsage uses inputTokens/outputTokens (SDK v3) // or promptTokens/completionTokens (SDK v2 compatibility) - const inputTokens = - (usage as any).inputTokens ?? (usage as any).promptTokens; - const outputTokens = - (usage as any).outputTokens ?? (usage as any).completionTokens; + const inputTokens = (usage as any).inputTokens ?? (usage as any).promptTokens; + const outputTokens = (usage as any).outputTokens ?? (usage as any).completionTokens; if (!inputTokens || !outputTokens) { console.error("No tokens found in usage"); diff --git a/lib/credits/handleChatCredits.ts b/lib/credits/handleChatCredits.ts index c0462eab2..305875791 100644 --- a/lib/credits/handleChatCredits.ts +++ b/lib/credits/handleChatCredits.ts @@ -11,9 +11,13 @@ interface HandleChatCreditsParams { /** * Handles credit deduction after chat completion. * Calculates usage cost and deducts appropriate credits from the user's account. + * + * @param usage.usage * @param usage - The language model usage data * @param model - The model ID used for the chat * @param accountId - The account ID to deduct credits from (optional) + * @param usage.model + * @param usage.accountId */ export const handleChatCredits = async ({ usage, diff --git a/lib/emails/__tests__/validateInboundEmailEvent.test.ts b/lib/emails/__tests__/validateInboundEmailEvent.test.ts index 803818eb6..fa14d42fb 100644 --- a/lib/emails/__tests__/validateInboundEmailEvent.test.ts +++ b/lib/emails/__tests__/validateInboundEmailEvent.test.ts @@ -12,8 +12,7 @@ const baseEvent = { to: ["agent@mail.recoupable.com"], bcc: [], cc: [], - message_id: - "", + message_id: "", subject: "Add mp3s to Gatsby Grace files in sandbox", attachments: [], }, diff --git a/lib/emails/inbound/__tests__/extractRoomIdFromHtml.test.ts b/lib/emails/inbound/__tests__/extractRoomIdFromHtml.test.ts index 5fcf968be..d7aebeea3 100644 --- a/lib/emails/inbound/__tests__/extractRoomIdFromHtml.test.ts +++ b/lib/emails/inbound/__tests__/extractRoomIdFromHtml.test.ts @@ -104,8 +104,7 @@ describe("extractRoomIdFromHtml", () => { }); it("returns undefined for invalid UUID format in link", () => { - const html = - 'link'; + const html = 'link'; const result = extractRoomIdFromHtml(html); diff --git a/lib/emails/inbound/__tests__/getFromWithName.test.ts b/lib/emails/inbound/__tests__/getFromWithName.test.ts index bb4efd98a..3b0c867d8 100644 --- a/lib/emails/inbound/__tests__/getFromWithName.test.ts +++ b/lib/emails/inbound/__tests__/getFromWithName.test.ts @@ -34,10 +34,7 @@ describe("getFromWithName", () => { }); it("falls back to cc array when not in to array", () => { - const result = getFromWithName( - ["other@example.com"], - ["support@mail.recoupable.com"], - ); + const result = getFromWithName(["other@example.com"], ["support@mail.recoupable.com"]); expect(result).toBe("Support by Recoup "); }); @@ -66,9 +63,7 @@ describe("getFromWithName", () => { }); it("throws error when arrays are empty", () => { - expect(() => getFromWithName([])).toThrow( - "No email found ending with @mail.recoupable.com", - ); + expect(() => getFromWithName([])).toThrow("No email found ending with @mail.recoupable.com"); }); }); diff --git a/lib/emails/inbound/extractRoomIdFromHtml.ts b/lib/emails/inbound/extractRoomIdFromHtml.ts index f637b17e6..6a48f954b 100644 --- a/lib/emails/inbound/extractRoomIdFromHtml.ts +++ b/lib/emails/inbound/extractRoomIdFromHtml.ts @@ -10,10 +10,7 @@ const CHAT_LINK_PATTERNS = [ // Pattern to find UUID after /chat/ or %2Fchat%2F in link text that may contain tags // The link text version: "https:///chat.recoupable.com/chat/uuid" -const WBR_STRIPPED_PATTERN = new RegExp( - `chat\\.recoupable\\.com/chat/(${UUID_PATTERN})`, - "i", -); +const WBR_STRIPPED_PATTERN = new RegExp(`chat\\.recoupable\\.com/chat/(${UUID_PATTERN})`, "i"); /** * Extracts the roomId from email HTML by looking for a Recoup chat link. diff --git a/lib/emails/processAndSendEmail.ts b/lib/emails/processAndSendEmail.ts index c70e20d0e..f21296764 100644 --- a/lib/emails/processAndSendEmail.ts +++ b/lib/emails/processAndSendEmail.ts @@ -34,6 +34,8 @@ export type ProcessAndSendEmailResult = ProcessAndSendEmailSuccess | ProcessAndS * * Handles room lookup, footer generation, markdown-to-HTML conversion, * and the Resend API call. + * + * @param input */ export async function processAndSendEmail( input: ProcessAndSendEmailInput, @@ -58,7 +60,9 @@ export async function processAndSendEmail( const data = await result.json(); return { success: false, - error: data?.error?.message || `Failed to send email from ${RECOUP_FROM_EMAIL} to ${to.join(", ")}.`, + error: + data?.error?.message || + `Failed to send email from ${RECOUP_FROM_EMAIL} to ${to.join(", ")}.`, }; } diff --git a/lib/evals/callChatFunctions.ts b/lib/evals/callChatFunctions.ts index ef770a2b5..23d64a06e 100644 --- a/lib/evals/callChatFunctions.ts +++ b/lib/evals/callChatFunctions.ts @@ -6,6 +6,7 @@ import { extractTextFromResult } from "./extractTextFromResult"; * This function encapsulates the logic for calling the chat system * and can be reused across different evaluations. * + * @param input * @deprecated Use callChatFunctionsWithResult for access to tool calls */ export async function callChatFunctions(input: string): Promise { diff --git a/lib/evals/callChatFunctionsWithResult.ts b/lib/evals/callChatFunctionsWithResult.ts index 16330158a..b80fcb584 100644 --- a/lib/evals/callChatFunctionsWithResult.ts +++ b/lib/evals/callChatFunctionsWithResult.ts @@ -8,6 +8,8 @@ import { ChatRequestBody } from "@/lib/chat/validateChatRequest"; * * Note: result.toolCalls only contains calls from the LAST step. When using multi-step * tool chains, we need to collect toolCalls from result.steps to capture all tool usage. + * + * @param input */ export async function callChatFunctionsWithResult(input: string) { const messages: UIMessage[] = [ @@ -38,8 +40,7 @@ export async function callChatFunctionsWithResult(input: string) { const result = await agent.generate({ messages: convertedMessages }); // Collect tool calls from ALL steps, not just the last one - const allToolCalls = - result.steps?.flatMap((step) => step.toolCalls || []) || result.toolCalls; + const allToolCalls = result.steps?.flatMap(step => step.toolCalls || []) || result.toolCalls; // Return result with all tool calls from all steps return { diff --git a/lib/evals/createToolsCalledScorer.ts b/lib/evals/createToolsCalledScorer.ts index dff87149e..8a9ac7e7f 100644 --- a/lib/evals/createToolsCalledScorer.ts +++ b/lib/evals/createToolsCalledScorer.ts @@ -3,16 +3,12 @@ import { ToolsCalled } from "./scorers/ToolsCalled"; /** * Creates a scorer that checks if required tools were called. * Handles extracting output text and toolCalls from the task result. + * + * @param requiredTools + * @param penalizedTools */ -export const createToolsCalledScorer = ( - requiredTools: string[], - penalizedTools: string[] = [] -) => { - return async (args: { - output: unknown; - expected?: string; - input: string; - }) => { +export const createToolsCalledScorer = (requiredTools: string[], penalizedTools: string[] = []) => { + return async (args: { output: unknown; expected?: string; input: string }) => { // Extract output text and toolCalls const outputText = typeof args.output === "object" && args.output && "output" in args.output @@ -20,9 +16,7 @@ export const createToolsCalledScorer = ( : (args.output as string); const toolCalls = - typeof args.output === "object" && - args.output && - "toolCalls" in args.output + typeof args.output === "object" && args.output && "toolCalls" in args.output ? (args.output.toolCalls as Array<{ toolName: string; args: Record; diff --git a/lib/evals/extractTextFromResult.ts b/lib/evals/extractTextFromResult.ts index 09e7a69fa..dc67f3ab5 100644 --- a/lib/evals/extractTextFromResult.ts +++ b/lib/evals/extractTextFromResult.ts @@ -3,10 +3,10 @@ import { extractTextResultFromSteps } from "./extractTextResultFromSteps"; /** * Extract text from a GenerateTextResult + * + * @param result */ -export function extractTextFromResult( - result: Awaited> -): string { +export function extractTextFromResult(result: Awaited>): string { // Handle multi-step responses (when maxSteps > 1) const stepsText = extractTextResultFromSteps(result); if (stepsText) return stepsText; diff --git a/lib/evals/extractTextResultFromSteps.ts b/lib/evals/extractTextResultFromSteps.ts index 9c4606f02..16881677f 100644 --- a/lib/evals/extractTextResultFromSteps.ts +++ b/lib/evals/extractTextResultFromSteps.ts @@ -4,15 +4,13 @@ import type { TextPart } from "ai"; /** * Extract text from multi-step GenerateTextResult * Handles responses where maxSteps > 1 + * + * @param result */ export function extractTextResultFromSteps( - result: Awaited> + result: Awaited>, ): string | null { - if ( - !result.steps || - !Array.isArray(result.steps) || - result.steps.length === 0 - ) { + if (!result.steps || !Array.isArray(result.steps) || result.steps.length === 0) { return null; } @@ -25,10 +23,7 @@ export function extractTextResultFromSteps( const textParts = lastStep.content .filter( (part: unknown): part is TextPart => - typeof part === "object" && - part !== null && - "type" in part && - part.type === "text" + typeof part === "object" && part !== null && "type" in part && part.type === "text", ) .map((part: TextPart) => part.text) .join(""); diff --git a/lib/evals/getCatalogSongsCountExpected.ts b/lib/evals/getCatalogSongsCountExpected.ts index 6f04e59ca..d94383ef5 100644 --- a/lib/evals/getCatalogSongsCountExpected.ts +++ b/lib/evals/getCatalogSongsCountExpected.ts @@ -2,6 +2,9 @@ import { getCatalogs } from "@/lib/catalog/getCatalogs"; import { getCatalogSongs } from "@/lib/catalog/getCatalogSongs"; import { EVAL_ACCOUNT_ID } from "@/lib/consts"; +/** + * + */ async function getCatalogSongsCountExpected() { try { const catalogsData = await getCatalogs(EVAL_ACCOUNT_ID); diff --git a/lib/evals/getSpotifyFollowersData.ts b/lib/evals/getSpotifyFollowersData.ts index 2edb87cc8..6074aceb9 100644 --- a/lib/evals/getSpotifyFollowersData.ts +++ b/lib/evals/getSpotifyFollowersData.ts @@ -3,7 +3,7 @@ import { EVAL_ARTISTS } from "@/lib/consts"; const getSpotifyFollowersData = async () => { const testCases = await Promise.all( - EVAL_ARTISTS.map(async (artist) => { + EVAL_ARTISTS.map(async artist => { const { expected } = await getSpotifyFollowersExpected(artist); return { input: `how many total followers does ${artist} have on Spotify`, @@ -15,7 +15,7 @@ const getSpotifyFollowersData = async () => { data_type: "spotify_followers", }, }; - }) + }), ); return testCases; diff --git a/lib/evals/getSpotifyFollowersExpected.ts b/lib/evals/getSpotifyFollowersExpected.ts index ef96e2487..f52219379 100644 --- a/lib/evals/getSpotifyFollowersExpected.ts +++ b/lib/evals/getSpotifyFollowersExpected.ts @@ -1,5 +1,9 @@ import { getSpotifyFollowers } from "@/lib/spotify/getSpotifyFollowers"; +/** + * + * @param artist + */ async function getSpotifyFollowersExpected(artist: string) { try { const followerCount = await getSpotifyFollowers(artist); diff --git a/lib/evals/scorers/CatalogAvailability.ts b/lib/evals/scorers/CatalogAvailability.ts index 206053f2d..8cf292d9d 100644 --- a/lib/evals/scorers/CatalogAvailability.ts +++ b/lib/evals/scorers/CatalogAvailability.ts @@ -5,6 +5,11 @@ import { z } from "zod"; /** * Custom scorer that uses AI to check if recommended songs are actually in the catalog + * + * @param root0 + * @param root0.output + * @param root0.expected + * @param root0.input */ export const CatalogAvailability = async ({ output, @@ -40,29 +45,19 @@ ${catalog} IMPORTANT: Return ONLY valid JSON. Use double quotes for all strings. Escape any quotes within strings with backslashes. Example: "reasoning": "This is a test with \\"quotes\\" inside"`, schema: z.object({ - analysis: z - .string() - .describe("Detailed analysis of the song recommendations"), + analysis: z.string().describe("Detailed analysis of the song recommendations"), totalSongs: z.number().describe("Total number of songs recommended"), - songsInCatalog: z - .number() - .describe("Number of songs that are in the catalog"), + songsInCatalog: z.number().describe("Number of songs that are in the catalog"), matchedSongs: z .array( z.object({ recommended: z.string().describe("The song as recommended"), catalogMatch: z.string().describe("The matching song in catalog"), - confidence: z - .number() - .min(0) - .max(1) - .describe("Confidence in the match (0-1)"), - }) + confidence: z.number().min(0).max(1).describe("Confidence in the match (0-1)"), + }), ) .describe("Songs that were matched to the catalog"), - unmatchedSongs: z - .array(z.string()) - .describe("Songs that were not found in the catalog"), + unmatchedSongs: z.array(z.string()).describe("Songs that were not found in the catalog"), score: z .number() .min(0) @@ -77,9 +72,7 @@ IMPORTANT: Return ONLY valid JSON. Use double quotes for all strings. Escape any } const score = - typeof result.object.score === "number" - ? Math.max(0, Math.min(1, result.object.score)) - : 0; + typeof result.object.score === "number" ? Math.max(0, Math.min(1, result.object.score)) : 0; return { name: "catalog_availability", diff --git a/lib/evals/scorers/QuestionAnswered.ts b/lib/evals/scorers/QuestionAnswered.ts index 787eca4b0..a7bafd1d7 100644 --- a/lib/evals/scorers/QuestionAnswered.ts +++ b/lib/evals/scorers/QuestionAnswered.ts @@ -5,6 +5,11 @@ import { z } from "zod"; /** * Custom scorer that checks if the AI actually answered the customer's question * with a specific answer, or if it deflected/explained why it couldn't answer + * + * @param root0 + * @param root0.output + * @param root0.expected + * @param root0.input */ export const QuestionAnswered = async ({ output, @@ -44,37 +49,29 @@ Return your evaluation as JSON.`, schema: z.object({ answered: z .boolean() - .describe( - "Did the AI provide the specific information requested in the question?" - ), + .describe("Did the AI provide the specific information requested in the question?"), hasSpecificAnswer: z .boolean() .describe( - "Does the response contain specific data/numbers/facts that directly address the question?" + "Does the response contain specific data/numbers/facts that directly address the question?", ), deflected: z .boolean() .describe( - "Did the AI deflect by explaining why it can't answer or offering alternatives instead of answering?" + "Did the AI deflect by explaining why it can't answer or offering alternatives instead of answering?", ), score: z .number() .min(0) .max(1) .describe( - "Score from 0-1 where 1=fully answered, 0.5-0.9=partially answered, 0-0.4=not answered" + "Score from 0-1 where 1=fully answered, 0.5-0.9=partially answered, 0-0.4=not answered", ), reasoning: z .string() - .describe( - "Detailed explanation of why the response did or did not answer the question" - ), - whatWasAsked: z - .string() - .describe("What specific information did the customer ask for?"), - whatWasProvided: z - .string() - .describe("What information did the AI actually provide?"), + .describe("Detailed explanation of why the response did or did not answer the question"), + whatWasAsked: z.string().describe("What specific information did the customer ask for?"), + whatWasProvided: z.string().describe("What information did the AI actually provide?"), }), }); @@ -83,9 +80,7 @@ Return your evaluation as JSON.`, } const score = - typeof result.object.score === "number" - ? Math.max(0, Math.min(1, result.object.score)) - : 0; + typeof result.object.score === "number" ? Math.max(0, Math.min(1, result.object.score)) : 0; return { name: "question_answered", diff --git a/lib/evals/scorers/ToolsCalled.ts b/lib/evals/scorers/ToolsCalled.ts index bcbc9ef6e..6a4511004 100644 --- a/lib/evals/scorers/ToolsCalled.ts +++ b/lib/evals/scorers/ToolsCalled.ts @@ -1,5 +1,13 @@ /** * Generic scorer that checks if specific tools were called + * + * @param root0 + * @param root0.output + * @param root0.expected + * @param root0.input + * @param root0.toolCalls + * @param root0.requiredTools + * @param root0.penalizedTools */ export const ToolsCalled = async ({ toolCalls, @@ -14,20 +22,16 @@ export const ToolsCalled = async ({ penalizedTools?: string[]; }) => { try { - const calledTools = toolCalls?.map((tc) => tc.toolName) || []; + const calledTools = toolCalls?.map(tc => tc.toolName) || []; // Check if required tools were called - const calledRequiredTools = requiredTools.filter((requiredTool) => - calledTools.some((tool) => - tool.toLowerCase().includes(requiredTool.toLowerCase()) - ) + const calledRequiredTools = requiredTools.filter(requiredTool => + calledTools.some(tool => tool.toLowerCase().includes(requiredTool.toLowerCase())), ); // Check if penalized tools were called - const calledPenalizedTools = penalizedTools.filter((penalizedTool) => - calledTools.some((tool) => - tool.toLowerCase().includes(penalizedTool.toLowerCase()) - ) + const calledPenalizedTools = penalizedTools.filter(penalizedTool => + calledTools.some(tool => tool.toLowerCase().includes(penalizedTool.toLowerCase())), ); // Calculate score based on required tools @@ -64,9 +68,7 @@ export const ToolsCalled = async ({ calledRequiredTools, penalizedTools, calledPenalizedTools, - missingRequiredTools: requiredTools.filter( - (tool) => !calledRequiredTools.includes(tool) - ), + missingRequiredTools: requiredTools.filter(tool => !calledRequiredTools.includes(tool)), }, }; } catch (error) { diff --git a/lib/files/__tests__/getKnowledgeBaseText.test.ts b/lib/files/__tests__/getKnowledgeBaseText.test.ts index 5dbb9583f..e9815e95f 100644 --- a/lib/files/__tests__/getKnowledgeBaseText.test.ts +++ b/lib/files/__tests__/getKnowledgeBaseText.test.ts @@ -47,7 +47,9 @@ describe("getKnowledgeBaseText", () => { text: () => Promise.resolve("Plain text content"), } as Response); - const knowledges = [{ name: "notes.txt", url: "https://example.com/notes.txt", type: "text/plain" }]; + const knowledges = [ + { name: "notes.txt", url: "https://example.com/notes.txt", type: "text/plain" }, + ]; const result = await getKnowledgeBaseText(knowledges); expect(result).toContain("Plain text content"); diff --git a/lib/files/generateAndStoreTxtFile.ts b/lib/files/generateAndStoreTxtFile.ts index 331505dd0..c5b35cd88 100644 --- a/lib/files/generateAndStoreTxtFile.ts +++ b/lib/files/generateAndStoreTxtFile.ts @@ -65,4 +65,3 @@ export async function generateAndStoreTxtFile(contents: string): Promise file.data && file.mediaType); } - diff --git a/lib/flamingo/__tests__/callFlamingoGenerate.test.ts b/lib/flamingo/__tests__/callFlamingoGenerate.test.ts index db36ec3ad..6e9e2da88 100644 --- a/lib/flamingo/__tests__/callFlamingoGenerate.test.ts +++ b/lib/flamingo/__tests__/callFlamingoGenerate.test.ts @@ -87,9 +87,9 @@ describe("callFlamingoGenerate", () => { text: async () => "Service Unavailable", }); - await expect( - callFlamingoGenerate({ prompt: "Describe this." }), - ).rejects.toThrow("Flamingo model returned 503: Service Unavailable"); + await expect(callFlamingoGenerate({ prompt: "Describe this." })).rejects.toThrow( + "Flamingo model returned 503: Service Unavailable", + ); }); it("throws error with fallback message when error text cannot be read", async () => { @@ -101,9 +101,9 @@ describe("callFlamingoGenerate", () => { }, }); - await expect( - callFlamingoGenerate({ prompt: "Describe this." }), - ).rejects.toThrow("Flamingo model returned 500: Unknown error"); + await expect(callFlamingoGenerate({ prompt: "Describe this." })).rejects.toThrow( + "Flamingo model returned 500: Unknown error", + ); }); it("throws when response shape is invalid", async () => { @@ -112,8 +112,8 @@ describe("callFlamingoGenerate", () => { json: async () => ({ response: 42 }), }); - await expect( - callFlamingoGenerate({ prompt: "Describe this." }), - ).rejects.toThrow("Flamingo model returned an unexpected response shape"); + await expect(callFlamingoGenerate({ prompt: "Describe this." })).rejects.toThrow( + "Flamingo model returned an unexpected response shape", + ); }); }); diff --git a/lib/flamingo/__tests__/getFlamingoPresetsHandler.test.ts b/lib/flamingo/__tests__/getFlamingoPresetsHandler.test.ts index 19109b2d6..1c30d8fc9 100644 --- a/lib/flamingo/__tests__/getFlamingoPresetsHandler.test.ts +++ b/lib/flamingo/__tests__/getFlamingoPresetsHandler.test.ts @@ -17,6 +17,9 @@ vi.mock("../presets", () => ({ getPresetSummaries: vi.fn(), })); +/** + * + */ function createMockRequest(): NextRequest { return { headers: new Headers({ "x-api-key": "test-key" }), diff --git a/lib/flamingo/__tests__/postProcessors.test.ts b/lib/flamingo/__tests__/postProcessors.test.ts index ccbcaf11c..cd422235f 100644 --- a/lib/flamingo/__tests__/postProcessors.test.ts +++ b/lib/flamingo/__tests__/postProcessors.test.ts @@ -23,9 +23,7 @@ describe("parseJsonLike", () => { }); it("handles nested objects with single quotes", () => { - const result = parseJsonLike( - "{'tags': ['dreamy', 'sad'], 'mood': 'melancholic'}", - ); + const result = parseJsonLike("{'tags': ['dreamy', 'sad'], 'mood': 'melancholic'}"); expect(result).toEqual({ tags: ["dreamy", "sad"], mood: "melancholic" }); }); @@ -46,9 +44,7 @@ describe("condenseRepetitions", () => { }); it("condenses within larger text", () => { - const result = condenseRepetitions( - "Ah, oh, oh, oh, oh, oh, yeah", - ); + const result = condenseRepetitions("Ah, oh, oh, oh, oh, oh, yeah"); expect(result).toBe("Ah, (oh x5), yeah"); }); diff --git a/lib/flamingo/__tests__/presets.test.ts b/lib/flamingo/__tests__/presets.test.ts index 04c903ac6..740664a04 100644 --- a/lib/flamingo/__tests__/presets.test.ts +++ b/lib/flamingo/__tests__/presets.test.ts @@ -1,10 +1,5 @@ import { describe, it, expect } from "vitest"; -import { - getPreset, - getAllPresets, - getPresetSummaries, - PRESET_NAMES, -} from "../presets"; +import { getPreset, getAllPresets, getPresetSummaries, PRESET_NAMES } from "../presets"; import { FULL_REPORT_SECTIONS, FULL_REPORT_PRESET_NAME } from "../presets/fullReport"; describe("getPreset", () => { @@ -62,7 +57,7 @@ describe("getPresetSummaries", () => { it("includes full_report in summaries", () => { const summaries = getPresetSummaries(); - const fullReport = summaries.find((s) => s.name === "full_report"); + const fullReport = summaries.find(s => s.name === "full_report"); expect(fullReport).toBeDefined(); expect(fullReport?.label).toBe("Full Report"); }); diff --git a/lib/flamingo/__tests__/processAnalyzeMusicRequest.test.ts b/lib/flamingo/__tests__/processAnalyzeMusicRequest.test.ts index 6cf968a36..9cd72f1b3 100644 --- a/lib/flamingo/__tests__/processAnalyzeMusicRequest.test.ts +++ b/lib/flamingo/__tests__/processAnalyzeMusicRequest.test.ts @@ -6,8 +6,7 @@ const mockGetPreset = vi.fn(); const mockExecuteFullReport = vi.fn(); vi.mock("@/lib/flamingo/callFlamingoGenerate", () => ({ - callFlamingoGenerate: (...args: unknown[]) => - mockCallFlamingoGenerate(...args), + callFlamingoGenerate: (...args: unknown[]) => mockCallFlamingoGenerate(...args), })); vi.mock("@/lib/flamingo/presets", () => ({ @@ -77,9 +76,7 @@ describe("processAnalyzeMusicRequest", () => { report: { metadata: { title: "Song" } }, elapsed_seconds: 30.5, }); - expect(mockExecuteFullReport).toHaveBeenCalledWith( - "https://example.com/song.mp3", - ); + expect(mockExecuteFullReport).toHaveBeenCalledWith("https://example.com/song.mp3"); }); it("returns error when full_report preset has no audio_url", async () => { @@ -155,7 +152,7 @@ describe("processAnalyzeMusicRequest", () => { expect(result).toEqual({ type: "error", - error: 'Unknown preset: nonexistent_preset', + error: "Unknown preset: nonexistent_preset", }); }); @@ -215,9 +212,7 @@ describe("processAnalyzeMusicRequest", () => { describe("inference failure", () => { it("throws when callFlamingoGenerate fails", async () => { - mockCallFlamingoGenerate.mockRejectedValue( - new Error("Modal returned 503"), - ); + mockCallFlamingoGenerate.mockRejectedValue(new Error("Modal returned 503")); await expect( processAnalyzeMusicRequest({ diff --git a/lib/flamingo/callFlamingoGenerate.ts b/lib/flamingo/callFlamingoGenerate.ts index 14cd67123..b94ce2ba6 100644 --- a/lib/flamingo/callFlamingoGenerate.ts +++ b/lib/flamingo/callFlamingoGenerate.ts @@ -33,9 +33,7 @@ export async function callFlamingoGenerate( if (!response.ok) { const errorText = await response.text().catch(() => "Unknown error"); - throw new Error( - `Flamingo model returned ${response.status}: ${errorText}`, - ); + throw new Error(`Flamingo model returned ${response.status}: ${errorText}`); } const data = await response.json(); diff --git a/lib/flamingo/executeFullReport.ts b/lib/flamingo/executeFullReport.ts index 87635e34c..fa5605cec 100644 --- a/lib/flamingo/executeFullReport.ts +++ b/lib/flamingo/executeFullReport.ts @@ -32,46 +32,39 @@ export async function executeFullReport(audioUrl: string): Promise<{ const startTime = Date.now(); // Build all preset calls in parallel - const promises: Promise[] = FULL_REPORT_SECTIONS.map( - async (section) => { - const preset = getPreset(section.preset); - if (!preset) return null; + const promises: Promise[] = FULL_REPORT_SECTIONS.map(async section => { + const preset = getPreset(section.preset); + if (!preset) return null; - try { - const result = await callFlamingoGenerate({ - prompt: preset.prompt, - audio_url: audioUrl, - max_new_tokens: preset.params.max_new_tokens, - temperature: preset.params.temperature, - top_p: 1.0, - do_sample: preset.params.do_sample, - }); + try { + const result = await callFlamingoGenerate({ + prompt: preset.prompt, + audio_url: audioUrl, + max_new_tokens: preset.params.max_new_tokens, + temperature: preset.params.temperature, + top_p: 1.0, + do_sample: preset.params.do_sample, + }); - // Apply post-processing if the preset defines one - const data = preset.parseResponse - ? preset.parseResponse(result.response) - : result.response; + // Apply post-processing if the preset defines one + const data = preset.parseResponse ? preset.parseResponse(result.response) : result.response; - return { - reportKey: section.reportKey, - data, - elapsed_seconds: result.elapsed_seconds, - }; - } catch (error) { - console.error( - `[WARN] Full report section "${section.preset}" failed:`, - error, - ); - return { - reportKey: section.reportKey, - data: { - error: `Section failed: ${error instanceof Error ? error.message : "unknown error"}`, - }, - elapsed_seconds: 0, - }; - } - }, - ); + return { + reportKey: section.reportKey, + data, + elapsed_seconds: result.elapsed_seconds, + }; + } catch (error) { + console.error(`[WARN] Full report section "${section.preset}" failed:`, error); + return { + reportKey: section.reportKey, + data: { + error: `Section failed: ${error instanceof Error ? error.message : "unknown error"}`, + }, + elapsed_seconds: 0, + }; + } + }); // Execute all presets in parallel const results = await Promise.all(promises); @@ -84,7 +77,7 @@ export async function executeFullReport(audioUrl: string): Promise<{ } } - const totalElapsed = Math.round((Date.now() - startTime) / 1000 * 100) / 100; + const totalElapsed = Math.round(((Date.now() - startTime) / 1000) * 100) / 100; return { report, elapsed_seconds: totalElapsed }; } diff --git a/lib/flamingo/getFlamingoPresetsHandler.ts b/lib/flamingo/getFlamingoPresetsHandler.ts index 1ab0f8de1..f33d491db 100644 --- a/lib/flamingo/getFlamingoPresetsHandler.ts +++ b/lib/flamingo/getFlamingoPresetsHandler.ts @@ -10,11 +10,10 @@ import { validateAuthContext } from "@/lib/auth/validateAuthContext"; * Returns a list of all available analysis presets. * Requires authentication via x-api-key header or Authorization bearer token. * + * @param request * @returns A NextResponse with the list of available presets. */ -export async function getFlamingoPresetsHandler( - request: NextRequest, -): Promise { +export async function getFlamingoPresetsHandler(request: NextRequest): Promise { const authResult = await validateAuthContext(request); if (authResult instanceof NextResponse) { return authResult; diff --git a/lib/flamingo/isFlamingoGenerateResult.ts b/lib/flamingo/isFlamingoGenerateResult.ts index a3f87c0a5..288acdd0b 100644 --- a/lib/flamingo/isFlamingoGenerateResult.ts +++ b/lib/flamingo/isFlamingoGenerateResult.ts @@ -14,14 +14,8 @@ export interface FlamingoGenerateResult { * @param value - Unknown parsed JSON payload * @returns True when payload has the expected response and elapsed_seconds fields */ -export function isFlamingoGenerateResult( - value: unknown, -): value is FlamingoGenerateResult { +export function isFlamingoGenerateResult(value: unknown): value is FlamingoGenerateResult { if (!value || typeof value !== "object") return false; const candidate = value as Record; - return ( - typeof candidate.response === "string" && - typeof candidate.elapsed_seconds === "number" - ); + return typeof candidate.response === "string" && typeof candidate.elapsed_seconds === "number"; } - diff --git a/lib/flamingo/postFlamingoGenerateHandler.ts b/lib/flamingo/postFlamingoGenerateHandler.ts index 11dd6219e..bb3c1ef9a 100644 --- a/lib/flamingo/postFlamingoGenerateHandler.ts +++ b/lib/flamingo/postFlamingoGenerateHandler.ts @@ -14,9 +14,7 @@ import { processAnalyzeMusicRequest } from "@/lib/flamingo/processAnalyzeMusicRe * @param request - The incoming request with a JSON body. * @returns A NextResponse with the model output or an error. */ -export async function postFlamingoGenerateHandler( - request: NextRequest, -): Promise { +export async function postFlamingoGenerateHandler(request: NextRequest): Promise { let body: unknown; try { body = await request.json(); @@ -44,8 +42,7 @@ export async function postFlamingoGenerateHandler( try { result = await processAnalyzeMusicRequest(validated); } catch (err) { - const message = - err instanceof Error ? err.message : "Flamingo inference failed"; + const message = err instanceof Error ? err.message : "Flamingo inference failed"; return NextResponse.json( { status: "error", error: message }, { status: 500, headers: getCorsHeaders() }, diff --git a/lib/flamingo/presets/audienceProfile.ts b/lib/flamingo/presets/audienceProfile.ts index 54b1f3d6c..125738a7d 100644 --- a/lib/flamingo/presets/audienceProfile.ts +++ b/lib/flamingo/presets/audienceProfile.ts @@ -11,5 +11,5 @@ export const audienceProfilePreset: PresetConfig = { params: { max_new_tokens: 1024, temperature: 0.5, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/presets/catalogMetadata.ts b/lib/flamingo/presets/catalogMetadata.ts index 600d35a43..0bcc4b2cd 100644 --- a/lib/flamingo/presets/catalogMetadata.ts +++ b/lib/flamingo/presets/catalogMetadata.ts @@ -11,5 +11,5 @@ export const catalogMetadataPreset: PresetConfig = { params: { max_new_tokens: 1024, temperature: 0.3, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/presets/condenseRepetitions.ts b/lib/flamingo/presets/condenseRepetitions.ts index 5011cfbd7..cd851e4d4 100644 --- a/lib/flamingo/presets/condenseRepetitions.ts +++ b/lib/flamingo/presets/condenseRepetitions.ts @@ -9,10 +9,7 @@ * @param minRepeats - Minimum repetitions to trigger condensing (default 3) * @returns Text with repetitions condensed */ -export function condenseRepetitions( - text: string, - minRepeats: number = 3, -): string { +export function condenseRepetitions(text: string, minRepeats: number = 3): string { // Split on comma+space boundaries const tokens = text.split(/,\s*/); const result: string[] = []; @@ -39,4 +36,3 @@ export function condenseRepetitions( return result.join(", "); } - diff --git a/lib/flamingo/presets/contentAdvisory.ts b/lib/flamingo/presets/contentAdvisory.ts index 60aa8e909..2e2a83f1b 100644 --- a/lib/flamingo/presets/contentAdvisory.ts +++ b/lib/flamingo/presets/contentAdvisory.ts @@ -11,5 +11,5 @@ export const contentAdvisoryPreset: PresetConfig = { params: { max_new_tokens: 256, temperature: 0.2, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/presets/deduplicateArray.ts b/lib/flamingo/presets/deduplicateArray.ts index 7d57ad400..f8a2785ff 100644 --- a/lib/flamingo/presets/deduplicateArray.ts +++ b/lib/flamingo/presets/deduplicateArray.ts @@ -7,4 +7,3 @@ export function deduplicateArray(items: T[]): T[] { return [...new Set(items)]; } - diff --git a/lib/flamingo/presets/extractOneCycle.ts b/lib/flamingo/presets/extractOneCycle.ts index c01d3ad68..68ebb11a6 100644 --- a/lib/flamingo/presets/extractOneCycle.ts +++ b/lib/flamingo/presets/extractOneCycle.ts @@ -27,4 +27,3 @@ export function extractOneCycle(items: T[]): T[] { return items; } - diff --git a/lib/flamingo/presets/getAllPresets.ts b/lib/flamingo/presets/getAllPresets.ts index f9012f2fd..511c6f699 100644 --- a/lib/flamingo/presets/getAllPresets.ts +++ b/lib/flamingo/presets/getAllPresets.ts @@ -10,4 +10,3 @@ import { PRESETS } from "./presetRegistry"; export function getAllPresets(): PresetConfig[] { return Object.values(PRESETS); } - diff --git a/lib/flamingo/presets/getPreset.ts b/lib/flamingo/presets/getPreset.ts index 044055af4..5ef73d455 100644 --- a/lib/flamingo/presets/getPreset.ts +++ b/lib/flamingo/presets/getPreset.ts @@ -10,4 +10,3 @@ import { PRESETS } from "./presetRegistry"; export function getPreset(name: string): PresetConfig | undefined { return PRESETS[name]; } - diff --git a/lib/flamingo/presets/getPresetSummaries.ts b/lib/flamingo/presets/getPresetSummaries.ts index d43077dff..f47cb5cb0 100644 --- a/lib/flamingo/presets/getPresetSummaries.ts +++ b/lib/flamingo/presets/getPresetSummaries.ts @@ -15,7 +15,7 @@ interface PresetSummary { * @returns Array of preset summaries (name, label, description, requiresAudio, responseFormat) */ export function getPresetSummaries(): PresetSummary[] { - const individual = Object.values(PRESETS).map((p) => ({ + const individual = Object.values(PRESETS).map(p => ({ name: p.name, label: p.label, description: p.description, @@ -35,4 +35,3 @@ export function getPresetSummaries(): PresetSummary[] { }, ]; } - diff --git a/lib/flamingo/presets/lyricTranscription.ts b/lib/flamingo/presets/lyricTranscription.ts index 01ff0f698..629c6dd16 100644 --- a/lib/flamingo/presets/lyricTranscription.ts +++ b/lib/flamingo/presets/lyricTranscription.ts @@ -5,11 +5,10 @@ import { condenseRepetitions } from "./postProcessors"; export const lyricTranscriptionPreset: PresetConfig = { name: "lyric_transcription", label: "Lyric Transcription", - description: - "Transcribes complete lyrics with section headers (Verse, Chorus, Bridge, etc).", + description: "Transcribes complete lyrics with section headers (Verse, Chorus, Bridge, etc).", prompt: `Transcribe the complete lyrics of this song. Format with section headers in brackets like [Verse 1], [Chorus], [Bridge], [Outro]. Include every distinct lyric line. Break lines where the singer naturally pauses.`, params: { max_new_tokens: 2048, temperature: 0.1, do_sample: true }, requiresAudio: true, responseFormat: "text", - parseResponse: (raw) => condenseRepetitions(raw), + parseResponse: raw => condenseRepetitions(raw), }; diff --git a/lib/flamingo/presets/moodTags.ts b/lib/flamingo/presets/moodTags.ts index 555ab5efc..5cf6129d7 100644 --- a/lib/flamingo/presets/moodTags.ts +++ b/lib/flamingo/presets/moodTags.ts @@ -5,11 +5,10 @@ import { parseJsonLike } from "./postProcessors"; export const moodTagsPreset: PresetConfig = { name: "mood_tags", label: "Mood Tags", - description: - "Returns mood/vibe/energy tags for playlist curation and music discovery.", + description: "Returns mood/vibe/energy tags for playlist curation and music discovery.", prompt: `Listen to this track and return ONLY a valid JSON object (use double quotes) with two fields: "tags" (array of 8-10 mood/vibe/energy tags that could be used for playlist curation and music discovery, e.g. "dreamy", "late-night", "heartbreak", "chill"), and "primary_mood" (single word that best captures the overall feeling). No other text.`, params: { max_new_tokens: 256, temperature: 0.3, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/presets/musicTheory.ts b/lib/flamingo/presets/musicTheory.ts index 7e5d5e469..cbaf47119 100644 --- a/lib/flamingo/presets/musicTheory.ts +++ b/lib/flamingo/presets/musicTheory.ts @@ -11,13 +11,11 @@ export const musicTheoryPreset: PresetConfig = { params: { max_new_tokens: 512, temperature: 0.3, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => { + parseResponse: raw => { const parsed = parseJsonLike(raw) as Record; // Extract one cycle from potentially repeated chord progression if (Array.isArray(parsed.chord_progression)) { - parsed.chord_progression = extractOneCycle( - parsed.chord_progression as string[], - ); + parsed.chord_progression = extractOneCycle(parsed.chord_progression as string[]); } return parsed; }, diff --git a/lib/flamingo/presets/parseJsonLike.ts b/lib/flamingo/presets/parseJsonLike.ts index 638d715c4..fec3169ee 100644 --- a/lib/flamingo/presets/parseJsonLike.ts +++ b/lib/flamingo/presets/parseJsonLike.ts @@ -27,4 +27,3 @@ export function parseJsonLike(raw: string): unknown { return JSON.parse(fixed); } - diff --git a/lib/flamingo/presets/presetRegistry.ts b/lib/flamingo/presets/presetRegistry.ts index 9de075097..062890bbb 100644 --- a/lib/flamingo/presets/presetRegistry.ts +++ b/lib/flamingo/presets/presetRegistry.ts @@ -35,8 +35,4 @@ export const PRESETS: Record = { * All valid preset names (including full_report). * Used for Zod enum validation in the request schema. */ -export const PRESET_NAMES = [ - ...Object.keys(PRESETS), - FULL_REPORT_PRESET_NAME, -] as const; - +export const PRESET_NAMES = [...Object.keys(PRESETS), FULL_REPORT_PRESET_NAME] as const; diff --git a/lib/flamingo/presets/similarArtists.ts b/lib/flamingo/presets/similarArtists.ts index 62214ed73..92c029335 100644 --- a/lib/flamingo/presets/similarArtists.ts +++ b/lib/flamingo/presets/similarArtists.ts @@ -11,5 +11,5 @@ export const similarArtistsPreset: PresetConfig = { params: { max_new_tokens: 512, temperature: 0.5, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/presets/syncBriefMatch.ts b/lib/flamingo/presets/syncBriefMatch.ts index 59c2bfdaa..920755484 100644 --- a/lib/flamingo/presets/syncBriefMatch.ts +++ b/lib/flamingo/presets/syncBriefMatch.ts @@ -11,5 +11,5 @@ export const syncBriefMatchPreset: PresetConfig = { params: { max_new_tokens: 1024, temperature: 0.4, do_sample: true }, requiresAudio: true, responseFormat: "json", - parseResponse: (raw) => parseJsonLike(raw), + parseResponse: raw => parseJsonLike(raw), }; diff --git a/lib/flamingo/processAnalyzeMusicRequest.ts b/lib/flamingo/processAnalyzeMusicRequest.ts index 263c4e74f..cd89a479e 100644 --- a/lib/flamingo/processAnalyzeMusicRequest.ts +++ b/lib/flamingo/processAnalyzeMusicRequest.ts @@ -26,10 +26,7 @@ interface AnalysisError { error: string; } -export type AnalyzeMusicResult = - | FullReportSuccess - | AnalysisSuccess - | AnalysisError; +export type AnalyzeMusicResult = FullReportSuccess | AnalysisSuccess | AnalysisError; /** * Shared business logic for music analysis. @@ -49,9 +46,7 @@ export async function processAnalyzeMusicRequest( error: "audio_url is required for the full_report preset", }; } - const { report, elapsed_seconds } = await executeFullReport( - params.audio_url, - ); + const { report, elapsed_seconds } = await executeFullReport(params.audio_url); return { type: "success", preset: "full_report", report, elapsed_seconds }; } diff --git a/lib/flamingo/validateFlamingoGenerateBody.ts b/lib/flamingo/validateFlamingoGenerateBody.ts index 691c66f03..e158e6501 100644 --- a/lib/flamingo/validateFlamingoGenerateBody.ts +++ b/lib/flamingo/validateFlamingoGenerateBody.ts @@ -23,11 +23,11 @@ export const flamingoGenerateBodySchema = z top_p: z.number().min(0).max(1).optional().default(1.0), do_sample: z.boolean().optional().default(false), }) - .refine((data) => data.preset || data.prompt, { + .refine(data => data.preset || data.prompt, { message: "Either 'preset' or 'prompt' is required", path: ["preset"], }) - .refine((data) => !(data.preset && data.prompt), { + .refine(data => !(data.preset && data.prompt), { message: "Provide either 'preset' or 'prompt', not both", path: ["prompt"], }); @@ -41,9 +41,7 @@ export type FlamingoGenerateBody = z.infer; * @param body - The raw request body (parsed JSON). * @returns A NextResponse with an error if validation fails, or the validated body if it passes. */ -export function validateFlamingoGenerateBody( - body: unknown, -): NextResponse | FlamingoGenerateBody { +export function validateFlamingoGenerateBody(body: unknown): NextResponse | FlamingoGenerateBody { const result = flamingoGenerateBodySchema.safeParse(body); if (!result.success) { diff --git a/lib/github/__tests__/deleteAccountGithubRepos.test.ts b/lib/github/__tests__/deleteAccountGithubRepos.test.ts index 39af4ac1e..2043b0928 100644 --- a/lib/github/__tests__/deleteAccountGithubRepos.test.ts +++ b/lib/github/__tests__/deleteAccountGithubRepos.test.ts @@ -1,5 +1,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { deleteAccountGithubRepos } from "../deleteAccountGithubRepos"; +import { deleteGithubRepo } from "../deleteGithubRepo"; +import { findOrgReposByAccountId } from "../findOrgReposByAccountId"; + vi.mock("@/lib/github/deleteGithubRepo", () => ({ deleteGithubRepo: vi.fn(), })); @@ -8,10 +12,6 @@ vi.mock("@/lib/github/findOrgReposByAccountId", () => ({ findOrgReposByAccountId: vi.fn(), })); -import { deleteAccountGithubRepos } from "../deleteAccountGithubRepos"; -import { deleteGithubRepo } from "../deleteGithubRepo"; -import { findOrgReposByAccountId } from "../findOrgReposByAccountId"; - describe("deleteAccountGithubRepos", () => { const mockAccountId = "550e8400-e29b-41d4-a716-446655440000"; const mockRepoUrl = "https://github.com/recoupable/test-repo"; diff --git a/lib/github/__tests__/findOrgReposByAccountId.test.ts b/lib/github/__tests__/findOrgReposByAccountId.test.ts index 4b3d8b4fa..3d36e26aa 100644 --- a/lib/github/__tests__/findOrgReposByAccountId.test.ts +++ b/lib/github/__tests__/findOrgReposByAccountId.test.ts @@ -15,7 +15,11 @@ describe("findOrgReposByAccountId", () => { vi.mocked(global.fetch).mockResolvedValue({ ok: true, json: async () => [ - { name: "artist-name-550e8400-e29b-41d4-a716-446655440000", html_url: "https://github.com/recoupable/artist-name-550e8400-e29b-41d4-a716-446655440000" }, + { + name: "artist-name-550e8400-e29b-41d4-a716-446655440000", + html_url: + "https://github.com/recoupable/artist-name-550e8400-e29b-41d4-a716-446655440000", + }, { name: "other-repo", html_url: "https://github.com/recoupable/other-repo" }, ], } as Response); diff --git a/lib/github/__tests__/getRepoGitModules.test.ts b/lib/github/__tests__/getRepoGitModules.test.ts index 6cc87f951..28189e360 100644 --- a/lib/github/__tests__/getRepoGitModules.test.ts +++ b/lib/github/__tests__/getRepoGitModules.test.ts @@ -43,10 +43,9 @@ describe("getRepoGitModules", () => { it("works without GITHUB_TOKEN", async () => { delete process.env.GITHUB_TOKEN; vi.spyOn(global, "fetch").mockResolvedValueOnce( - new Response( - `[submodule "sub"]\n\tpath = sub\n\turl = https://github.com/owner/sub`, - { status: 200 }, - ), + new Response(`[submodule "sub"]\n\tpath = sub\n\turl = https://github.com/owner/sub`, { + status: 200, + }), ); const result = await getRepoGitModules({ owner: "owner", repo: "repo", branch: "develop" }); diff --git a/lib/github/expandSubmoduleEntries.ts b/lib/github/expandSubmoduleEntries.ts index 9531bee1a..3082c63b8 100644 --- a/lib/github/expandSubmoduleEntries.ts +++ b/lib/github/expandSubmoduleEntries.ts @@ -11,9 +11,15 @@ interface SubmoduleRef { * Resolves submodule URLs from .gitmodules, fetches each submodule's tree, * and merges the results into the regular entries with correct path prefixes. * + * @param regularEntries.regularEntries * @param regularEntries - Non-submodule file tree entries * @param submoduleEntries - Submodule references (type "commit" from GitHub Trees API) * @param repo - Repository context for fetching .gitmodules + * @param regularEntries.submoduleEntries + * @param regularEntries.repo + * @param regularEntries.repo.owner + * @param regularEntries.repo.repo + * @param regularEntries.repo.branch * @returns Combined file tree entries with submodules expanded as directories */ export async function expandSubmoduleEntries({ diff --git a/lib/github/findOrgReposByAccountId.ts b/lib/github/findOrgReposByAccountId.ts index 18a50e7b1..be37bba64 100644 --- a/lib/github/findOrgReposByAccountId.ts +++ b/lib/github/findOrgReposByAccountId.ts @@ -13,16 +13,13 @@ export async function findOrgReposByAccountId(accountId: string): Promise; - return repos - .filter((repo) => repo.name.includes(accountId)) - .map((repo) => repo.html_url); + return repos.filter(repo => repo.name.includes(accountId)).map(repo => repo.html_url); } catch (error) { console.error("Error searching org repos:", error); return []; diff --git a/lib/github/getOrgRepoUrls.ts b/lib/github/getOrgRepoUrls.ts index 1aca55c13..d16d5543c 100644 --- a/lib/github/getOrgRepoUrls.ts +++ b/lib/github/getOrgRepoUrls.ts @@ -11,10 +11,7 @@ import { parseGitHubRepoUrl } from "./parseGitHubRepoUrl"; * @param branch - Branch to read .gitmodules from (defaults to "main") * @returns Array of org repo URLs, or empty array if none found */ -export async function getOrgRepoUrls( - githubRepoUrl: string, - branch = "main", -): Promise { +export async function getOrgRepoUrls(githubRepoUrl: string, branch = "main"): Promise { const repoInfo = parseGitHubRepoUrl(githubRepoUrl); if (!repoInfo) return []; diff --git a/lib/github/getRepoFileTree.ts b/lib/github/getRepoFileTree.ts index bceeaae56..14147bcf3 100644 --- a/lib/github/getRepoFileTree.ts +++ b/lib/github/getRepoFileTree.ts @@ -40,7 +40,9 @@ export async function getRepoFileTree(githubRepoUrl: string): Promise ({ experimental_createMCPClient: vi.fn(), })); @@ -8,9 +11,6 @@ vi.mock("@/lib/networking/getBaseUrl", () => ({ getBaseUrl: vi.fn().mockReturnValue("https://test.vercel.app"), })); -import { getMcpTools } from "../getMcpTools"; -import { experimental_createMCPClient } from "@ai-sdk/mcp"; - const mockCreateMCPClient = vi.mocked(experimental_createMCPClient); describe("getMcpTools", () => { diff --git a/lib/mcp/__tests__/verifyApiKey.test.ts b/lib/mcp/__tests__/verifyApiKey.test.ts index 4b244d2ce..137250ca5 100644 --- a/lib/mcp/__tests__/verifyApiKey.test.ts +++ b/lib/mcp/__tests__/verifyApiKey.test.ts @@ -1,6 +1,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { verifyBearerToken } from "../verifyApiKey"; +import { getAccountIdByAuthToken } from "@/lib/privy/getAccountIdByAuthToken"; +import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; + vi.mock("@/lib/privy/getAccountIdByAuthToken", () => ({ getAccountIdByAuthToken: vi.fn(), })); @@ -9,9 +12,6 @@ vi.mock("@/lib/keys/getApiKeyDetails", () => ({ getApiKeyDetails: vi.fn(), })); -import { getAccountIdByAuthToken } from "@/lib/privy/getAccountIdByAuthToken"; -import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; - describe("verifyBearerToken", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/mcp/resolveAccountId.ts b/lib/mcp/resolveAccountId.ts index 100dcafd7..1e0e7bcc2 100644 --- a/lib/mcp/resolveAccountId.ts +++ b/lib/mcp/resolveAccountId.ts @@ -16,6 +16,8 @@ export interface ResolveAccountIdResult { * Validates access when an org API key attempts to use an account_id override. * * @param params - The auth info and optional account_id override. + * @param params.authInfo + * @param params.accountIdOverride * @returns The resolved accountId or an error message. */ export async function resolveAccountId({ diff --git a/lib/mcp/tools/__tests__/registerSendEmailTool.test.ts b/lib/mcp/tools/__tests__/registerSendEmailTool.test.ts index 1d880847b..0da1be9e9 100644 --- a/lib/mcp/tools/__tests__/registerSendEmailTool.test.ts +++ b/lib/mcp/tools/__tests__/registerSendEmailTool.test.ts @@ -37,7 +37,8 @@ describe("registerSendEmailTool", () => { it("returns success when email is sent successfully", async () => { mockProcessAndSendEmail.mockResolvedValue({ success: true, - message: "Email sent successfully from Agent by Recoup to test@example.com. CC: none.", + message: + "Email sent successfully from Agent by Recoup to test@example.com. CC: none.", id: "email-123", }); diff --git a/lib/mcp/tools/__tests__/registerWebDeepResearchTool.test.ts b/lib/mcp/tools/__tests__/registerWebDeepResearchTool.test.ts index 64ee27670..2474e309d 100644 --- a/lib/mcp/tools/__tests__/registerWebDeepResearchTool.test.ts +++ b/lib/mcp/tools/__tests__/registerWebDeepResearchTool.test.ts @@ -115,10 +115,7 @@ describe("registerWebDeepResearchTool", () => { messages: [{ role: "user", content: "Research this topic" }], }); - expect(mockChatWithPerplexity).toHaveBeenCalledWith( - expect.any(Array), - "sonar-deep-research", - ); + expect(mockChatWithPerplexity).toHaveBeenCalledWith(expect.any(Array), "sonar-deep-research"); }); it("handles no citations gracefully", async () => { diff --git a/lib/mcp/tools/artistSocials/registerGetArtistSocialsTool.ts b/lib/mcp/tools/artistSocials/registerGetArtistSocialsTool.ts index 54d216ea2..4fe6b10c1 100644 --- a/lib/mcp/tools/artistSocials/registerGetArtistSocialsTool.ts +++ b/lib/mcp/tools/artistSocials/registerGetArtistSocialsTool.ts @@ -26,4 +26,3 @@ export function registerGetArtistSocialsTool(server: McpServer): void { }, ); } - diff --git a/lib/mcp/tools/artistSocials/registerUpdateArtistSocialsTool.ts b/lib/mcp/tools/artistSocials/registerUpdateArtistSocialsTool.ts index 898e1dc59..864b0f68c 100644 --- a/lib/mcp/tools/artistSocials/registerUpdateArtistSocialsTool.ts +++ b/lib/mcp/tools/artistSocials/registerUpdateArtistSocialsTool.ts @@ -55,12 +55,9 @@ export function registerUpdateArtistSocialsTool(server: McpServer): void { } catch (error) { console.error("Error updating artist socials:", error); const errorMessage = - error instanceof Error - ? error.message - : "Failed to update artist socials."; + error instanceof Error ? error.message : "Failed to update artist socials."; return getToolResultError(errorMessage); } }, ); } - diff --git a/lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.ts b/lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.ts index 42056f75c..d438bdd32 100644 --- a/lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.ts +++ b/lib/mcp/tools/artists/__tests__/registerCreateNewArtistTool.test.ts @@ -3,6 +3,8 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js"; import type { ServerRequest, ServerNotification } from "@modelcontextprotocol/sdk/types.js"; +import { registerCreateNewArtistTool } from "../registerCreateNewArtistTool"; + const mockCreateArtistInDb = vi.fn(); const mockCopyRoom = vi.fn(); const mockCanAccessAccount = vi.fn(); @@ -19,12 +21,14 @@ vi.mock("@/lib/organizations/canAccessAccount", () => ({ canAccessAccount: (...args: unknown[]) => mockCanAccessAccount(...args), })); -import { registerCreateNewArtistTool } from "../registerCreateNewArtistTool"; - type ServerRequestHandlerExtra = RequestHandlerExtra; /** * Creates a mock extra object with optional authInfo. + * + * @param authInfo + * @param authInfo.accountId + * @param authInfo.orgId */ function createMockExtra(authInfo?: { accountId?: string; diff --git a/lib/mcp/tools/artists/registerCreateNewArtistTool.ts b/lib/mcp/tools/artists/registerCreateNewArtistTool.ts index cad178067..7495bcbf8 100644 --- a/lib/mcp/tools/artists/registerCreateNewArtistTool.ts +++ b/lib/mcp/tools/artists/registerCreateNewArtistTool.ts @@ -4,10 +4,7 @@ import type { ServerRequest, ServerNotification } from "@modelcontextprotocol/sd import { z } from "zod"; import type { McpAuthInfo } from "@/lib/mcp/verifyApiKey"; import { resolveAccountId } from "@/lib/mcp/resolveAccountId"; -import { - createArtistInDb, - type CreateArtistResult, -} from "@/lib/artists/createArtistInDb"; +import { createArtistInDb, type CreateArtistResult } from "@/lib/artists/createArtistInDb"; import { copyRoom } from "@/lib/rooms/copyRoom"; import { getToolResultSuccess } from "@/lib/mcp/getToolResultSuccess"; import { getToolResultError } from "@/lib/mcp/getToolResultError"; @@ -69,7 +66,10 @@ export function registerCreateNewArtistTool(server: McpServer): void { "The organization_id parameter is optional — use the organization_id from the system prompt context to link the artist to the user's selected organization.", inputSchema: createNewArtistSchema, }, - async (args: CreateNewArtistArgs, extra: RequestHandlerExtra) => { + async ( + args: CreateNewArtistArgs, + extra: RequestHandlerExtra, + ) => { try { const { name, account_id, active_conversation_id, organization_id } = args; diff --git a/lib/mcp/tools/flamingo/registerAnalyzeMusicTool.ts b/lib/mcp/tools/flamingo/registerAnalyzeMusicTool.ts index 08936e50b..d4a0d84df 100644 --- a/lib/mcp/tools/flamingo/registerAnalyzeMusicTool.ts +++ b/lib/mcp/tools/flamingo/registerAnalyzeMusicTool.ts @@ -50,8 +50,7 @@ export function registerAnalyzeMusicTool(server: McpServer): void { try { result = await processAnalyzeMusicRequest(args); } catch (err) { - const message = - err instanceof Error ? err.message : "Flamingo inference failed"; + const message = err instanceof Error ? err.message : "Flamingo inference failed"; return getToolResultError(`Music analysis failed: ${message}`); } diff --git a/lib/mcp/tools/registerWebDeepResearchTool.ts b/lib/mcp/tools/registerWebDeepResearchTool.ts index df9f5d8e6..ae84f4996 100644 --- a/lib/mcp/tools/registerWebDeepResearchTool.ts +++ b/lib/mcp/tools/registerWebDeepResearchTool.ts @@ -58,7 +58,9 @@ export function registerWebDeepResearchTool(server: McpServer): void { return getToolResultSuccess(finalContent); } catch (error) { return getToolResultError( - error instanceof Error ? `Deep research failed: ${error.message}` : "Deep research failed", + error instanceof Error + ? `Deep research failed: ${error.message}` + : "Deep research failed", ); } }, diff --git a/lib/mcp/tools/sandbox/__tests__/registerPromptSandboxTool.test.ts b/lib/mcp/tools/sandbox/__tests__/registerPromptSandboxTool.test.ts index 1b344d256..054b08073 100644 --- a/lib/mcp/tools/sandbox/__tests__/registerPromptSandboxTool.test.ts +++ b/lib/mcp/tools/sandbox/__tests__/registerPromptSandboxTool.test.ts @@ -73,13 +73,11 @@ describe("registerPromptSandboxTool", () => { it("returns error when resolveAccountId returns an error", async () => { mockResolveAccountId.mockResolvedValue({ accountId: null, - error: "Authentication required. Provide an API key via Authorization: Bearer header, or provide account_id from the system prompt context.", + error: + "Authentication required. Provide an API key via Authorization: Bearer header, or provide account_id from the system prompt context.", }); - const result = await registeredHandler( - { prompt: "say hello" }, - createMockExtra(), - ); + const result = await registeredHandler({ prompt: "say hello" }, createMockExtra()); expect(result).toEqual({ content: [ @@ -97,10 +95,7 @@ describe("registerPromptSandboxTool", () => { error: null, }); - const result = await registeredHandler( - { prompt: "say hello" }, - createMockExtra(), - ); + const result = await registeredHandler({ prompt: "say hello" }, createMockExtra()); expect(result).toEqual({ content: [ diff --git a/lib/mcp/tools/search/registerSearchGoogleImagesTool.ts b/lib/mcp/tools/search/registerSearchGoogleImagesTool.ts index 2853f500c..d1e18d6ee 100644 --- a/lib/mcp/tools/search/registerSearchGoogleImagesTool.ts +++ b/lib/mcp/tools/search/registerSearchGoogleImagesTool.ts @@ -21,15 +21,21 @@ const searchGoogleImagesSchema = z.object({ imageSize: z .enum(["l", "m", "i"]) .optional() - .describe("Image size: 'l' (large, recommended), 'm' (medium), 'i' (icon/small). Leave unset if unsure."), + .describe( + "Image size: 'l' (large, recommended), 'm' (medium), 'i' (icon/small). Leave unset if unsure.", + ), imageType: z .enum(["photo", "clipart", "lineart", "animated"]) .optional() - .describe("Type of image: 'photo' (default, recommended), 'clipart', 'lineart', 'animated'. Leave unset if unsure."), + .describe( + "Type of image: 'photo' (default, recommended), 'clipart', 'lineart', 'animated'. Leave unset if unsure.", + ), aspectRatio: z .enum(["square", "wide", "tall", "panoramic"]) .optional() - .describe("Aspect ratio filter. Only use if specifically requested. Leave unset for general searches."), + .describe( + "Aspect ratio filter. Only use if specifically requested. Leave unset for general searches.", + ), }); type SearchGoogleImagesArgs = z.infer; @@ -64,9 +70,15 @@ export function registerSearchGoogleImagesTool(server: McpServer): void { const { query, limit = DEFAULT_IMAGE_LIMIT, imageSize, imageType, aspectRatio } = args; try { - const response = await searchGoogleImages({ query, limit, imageSize, imageType, aspectRatio }); + const response = await searchGoogleImages({ + query, + limit, + imageSize, + imageType, + aspectRatio, + }); - const images = (response.images_results ?? []).map((img) => ({ + const images = (response.images_results ?? []).map(img => ({ position: img.position, thumbnail: img.thumbnail, original: img.original, diff --git a/lib/mcp/tools/tasks/__tests__/registerGetTaskRunStatusTool.test.ts b/lib/mcp/tools/tasks/__tests__/registerGetTaskRunStatusTool.test.ts index 8557432f6..f98472657 100644 --- a/lib/mcp/tools/tasks/__tests__/registerGetTaskRunStatusTool.test.ts +++ b/lib/mcp/tools/tasks/__tests__/registerGetTaskRunStatusTool.test.ts @@ -73,13 +73,11 @@ describe("registerGetTaskRunStatusTool", () => { it("returns error when resolveAccountId returns an error", async () => { mockResolveAccountId.mockResolvedValue({ accountId: null, - error: "Authentication required. Provide an API key via Authorization: Bearer header, or provide account_id from the system prompt context.", + error: + "Authentication required. Provide an API key via Authorization: Bearer header, or provide account_id from the system prompt context.", }); - const result = await registeredHandler( - { runId: "run_123" }, - createMockExtra(), - ); + const result = await registeredHandler({ runId: "run_123" }, createMockExtra()); expect(result).toEqual({ content: [ @@ -97,10 +95,7 @@ describe("registerGetTaskRunStatusTool", () => { error: null, }); - const result = await registeredHandler( - { runId: "run_123" }, - createMockExtra(), - ); + const result = await registeredHandler({ runId: "run_123" }, createMockExtra()); expect(result).toEqual({ content: [ diff --git a/lib/mcp/tools/transcribe/index.ts b/lib/mcp/tools/transcribe/index.ts index 01ff8e193..dedbb17cb 100644 --- a/lib/mcp/tools/transcribe/index.ts +++ b/lib/mcp/tools/transcribe/index.ts @@ -9,4 +9,3 @@ import { registerTranscribeAudioTool } from "./registerTranscribeAudioTool"; export function registerTranscribeTools(server: McpServer): void { registerTranscribeAudioTool(server); } - diff --git a/lib/mcp/tools/transcribe/registerTranscribeAudioTool.ts b/lib/mcp/tools/transcribe/registerTranscribeAudioTool.ts index 0d7818221..d8a64f798 100644 --- a/lib/mcp/tools/transcribe/registerTranscribeAudioTool.ts +++ b/lib/mcp/tools/transcribe/registerTranscribeAudioTool.ts @@ -15,6 +15,10 @@ const transcribeAudioSchema = z.object({ type TranscribeAudioArgs = z.infer; +/** + * + * @param server + */ export function registerTranscribeAudioTool(server: McpServer): void { server.registerTool( "transcribe_audio", @@ -48,4 +52,3 @@ export function registerTranscribeAudioTool(server: McpServer): void { }, ); } - diff --git a/lib/messages/__tests__/convertToUiMessages.test.ts b/lib/messages/__tests__/convertToUiMessages.test.ts index 75280068f..a54104306 100644 --- a/lib/messages/__tests__/convertToUiMessages.test.ts +++ b/lib/messages/__tests__/convertToUiMessages.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import convertToUiMessages from "../convertToUiMessages"; + // Mock generateUUID before importing the module vi.mock("@/lib/uuid/generateUUID", () => ({ default: vi.fn(() => "generated-uuid"), generateUUID: vi.fn(() => "generated-uuid"), })); -import convertToUiMessages from "../convertToUiMessages"; - describe("convertToUiMessages", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/messages/__tests__/extractImageUrlsFromMessages.test.ts b/lib/messages/__tests__/extractImageUrlsFromMessages.test.ts index ccc125ead..f1bbbd553 100644 --- a/lib/messages/__tests__/extractImageUrlsFromMessages.test.ts +++ b/lib/messages/__tests__/extractImageUrlsFromMessages.test.ts @@ -10,9 +10,7 @@ describe("extractImageUrlsFromMessages", () => { }); it("returns empty array for messages without parts", () => { - const messages: UIMessage[] = [ - { id: "1", role: "user", content: "Hello" } as UIMessage, - ]; + const messages: UIMessage[] = [{ id: "1", role: "user", content: "Hello" } as UIMessage]; const result = extractImageUrlsFromMessages(messages); expect(result).toEqual([]); }); @@ -23,9 +21,7 @@ describe("extractImageUrlsFromMessages", () => { id: "1", role: "user", content: "Check this image", - parts: [ - { type: "file", mediaType: "image/png", url: "https://example.com/image.png" }, - ], + parts: [{ type: "file", mediaType: "image/png", url: "https://example.com/image.png" }], } as UIMessage, ]; const result = extractImageUrlsFromMessages(messages); @@ -38,17 +34,13 @@ describe("extractImageUrlsFromMessages", () => { id: "1", role: "user", content: "Image 1", - parts: [ - { type: "file", mediaType: "image/png", url: "https://example.com/1.png" }, - ], + parts: [{ type: "file", mediaType: "image/png", url: "https://example.com/1.png" }], } as UIMessage, { id: "2", role: "user", content: "Image 2", - parts: [ - { type: "file", mediaType: "image/jpeg", url: "https://example.com/2.jpg" }, - ], + parts: [{ type: "file", mediaType: "image/jpeg", url: "https://example.com/2.jpg" }], } as UIMessage, ]; const result = extractImageUrlsFromMessages(messages); @@ -240,10 +232,7 @@ describe("extractImageUrlsFromMessages", () => { } as UIMessage, ]; const result = extractImageUrlsFromMessages(messages); - expect(result).toEqual([ - "https://example.com/valid.png", - "https://example.com/valid.gif", - ]); + expect(result).toEqual(["https://example.com/valid.png", "https://example.com/valid.gif"]); }); }); }); diff --git a/lib/messages/__tests__/getLatestUserMessageText.test.ts b/lib/messages/__tests__/getLatestUserMessageText.test.ts index 855cd33e0..f99dd7b36 100644 --- a/lib/messages/__tests__/getLatestUserMessageText.test.ts +++ b/lib/messages/__tests__/getLatestUserMessageText.test.ts @@ -112,9 +112,7 @@ describe("getLatestUserMessageText", () => { id: "1", role: "user", content: "Hello", - parts: [ - { type: "file", mediaType: "image/png", url: "https://example.com/image.png" }, - ], + parts: [{ type: "file", mediaType: "image/png", url: "https://example.com/image.png" }], }, ]; diff --git a/lib/messages/__tests__/getTextContent.test.ts b/lib/messages/__tests__/getTextContent.test.ts index 9820e6ace..1822bb4a3 100644 --- a/lib/messages/__tests__/getTextContent.test.ts +++ b/lib/messages/__tests__/getTextContent.test.ts @@ -40,9 +40,7 @@ describe("getTextContent", () => { }); it("returns empty string when no text parts exist", () => { - const content = [ - { type: "image" as const, image: "data:image/png;base64,..." }, - ] as any; + const content = [{ type: "image" as const, image: "data:image/png;base64,..." }] as any; expect(getTextContent(content)).toBe(""); }); }); diff --git a/lib/messages/convertToUiMessages.ts b/lib/messages/convertToUiMessages.ts index 7318f238b..c517f39f4 100644 --- a/lib/messages/convertToUiMessages.ts +++ b/lib/messages/convertToUiMessages.ts @@ -23,7 +23,7 @@ type InputMessage = UIMessage | ModelMessage; * @returns Array of messages in UIMessage format */ export default function convertToUiMessages(messages: InputMessage[]): UIMessage[] { - return messages.map((message) => { + return messages.map(message => { if (isUiMessage(message)) { return message; } diff --git a/lib/messages/getLatestUserMessageText.ts b/lib/messages/getLatestUserMessageText.ts index 2d83f5062..9433ffbf0 100644 --- a/lib/messages/getLatestUserMessageText.ts +++ b/lib/messages/getLatestUserMessageText.ts @@ -7,7 +7,7 @@ import { UIMessage } from "ai"; * @returns The text content of the latest user message, or empty string if none found */ export default function getLatestUserMessageText(messages: UIMessage[]): string { - const userMessages = messages.filter((msg) => msg.role === "user"); + const userMessages = messages.filter(msg => msg.role === "user"); const latestUserMessage = userMessages[userMessages.length - 1]; - return latestUserMessage?.parts?.find((part) => part.type === "text")?.text || ""; + return latestUserMessage?.parts?.find(part => part.type === "text")?.text || ""; } diff --git a/lib/messages/getTextContent.ts b/lib/messages/getTextContent.ts index 8f54bd1a3..8423c1549 100644 --- a/lib/messages/getTextContent.ts +++ b/lib/messages/getTextContent.ts @@ -13,6 +13,6 @@ export default function getTextContent(content: ModelMessage["content"]): string // Content is an array of parts - extract and join text parts return content .filter((part): part is { type: "text"; text: string } => part.type === "text") - .map((part) => part.text) + .map(part => part.text) .join(""); } diff --git a/lib/notifications/__tests__/createNotificationHandler.test.ts b/lib/notifications/__tests__/createNotificationHandler.test.ts index 7d95a758f..60b6e5bac 100644 --- a/lib/notifications/__tests__/createNotificationHandler.test.ts +++ b/lib/notifications/__tests__/createNotificationHandler.test.ts @@ -26,6 +26,10 @@ vi.mock("@/lib/networking/safeParseJson", () => ({ safeParseJson: vi.fn(async (req: Request) => req.json()), })); +/** + * + * @param body + */ function createRequest(body: unknown): NextRequest { return new NextRequest("https://recoup-api.vercel.app/api/notifications", { method: "POST", @@ -84,7 +88,8 @@ describe("createNotificationHandler", () => { it("sends email to account owner with text body", async () => { mockProcessAndSendEmail.mockResolvedValue({ success: true, - message: "Email sent successfully from Agent by Recoup to owner@example.com. CC: none.", + message: + "Email sent successfully from Agent by Recoup to owner@example.com. CC: none.", id: "email-123", }); diff --git a/lib/notifications/__tests__/validateCreateNotificationBody.test.ts b/lib/notifications/__tests__/validateCreateNotificationBody.test.ts index ba0c15ef2..645ccedc7 100644 --- a/lib/notifications/__tests__/validateCreateNotificationBody.test.ts +++ b/lib/notifications/__tests__/validateCreateNotificationBody.test.ts @@ -16,6 +16,11 @@ vi.mock("@/lib/networking/safeParseJson", () => ({ safeParseJson: vi.fn(async (req: Request) => req.json()), })); +/** + * + * @param body + * @param headers + */ function createRequest(body: unknown, headers: Record = {}): NextRequest { const defaultHeaders: Record = { "Content-Type": "application/json" }; return new NextRequest("http://localhost/api/notifications", { @@ -175,10 +180,7 @@ describe("validateCreateNotificationBody", () => { describe("auth errors", () => { it("returns 401 when auth is missing", async () => { mockValidateAuthContext.mockResolvedValue( - NextResponse.json( - { status: "error", error: "Unauthorized" }, - { status: 401 }, - ), + NextResponse.json({ status: "error", error: "Unauthorized" }, { status: 401 }), ); const request = createRequest({ subject: "Test" }); diff --git a/lib/organizations/__tests__/canAccessAccount.test.ts b/lib/organizations/__tests__/canAccessAccount.test.ts index 54f5a2318..b7d93047d 100644 --- a/lib/organizations/__tests__/canAccessAccount.test.ts +++ b/lib/organizations/__tests__/canAccessAccount.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { canAccessAccount } from "../canAccessAccount"; +import { getAccountOrganizations } from "@/lib/supabase/account_organization_ids/getAccountOrganizations"; + // Mock RECOUP_ORG_ID constant vi.mock("@/lib/const", () => ({ RECOUP_ORG_ID: "recoup-admin-org-id", @@ -11,8 +13,6 @@ vi.mock("@/lib/supabase/account_organization_ids/getAccountOrganizations", () => getAccountOrganizations: vi.fn(), })); -import { getAccountOrganizations } from "@/lib/supabase/account_organization_ids/getAccountOrganizations"; - describe("canAccessAccount", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/organizations/__tests__/validateOrganizationAccess.test.ts b/lib/organizations/__tests__/validateOrganizationAccess.test.ts index 27f26fdba..2182d5f14 100644 --- a/lib/organizations/__tests__/validateOrganizationAccess.test.ts +++ b/lib/organizations/__tests__/validateOrganizationAccess.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { validateOrganizationAccess } from "../validateOrganizationAccess"; +import { getAccountOrganizations } from "@/lib/supabase/account_organization_ids/getAccountOrganizations"; + // Mock getAccountOrganizations supabase lib vi.mock("@/lib/supabase/account_organization_ids/getAccountOrganizations", () => ({ getAccountOrganizations: vi.fn(), })); -import { getAccountOrganizations } from "@/lib/supabase/account_organization_ids/getAccountOrganizations"; - const mockGetAccountOrganizations = vi.mocked(getAccountOrganizations); describe("validateOrganizationAccess", () => { diff --git a/lib/organizations/addArtistToOrgHandler.ts b/lib/organizations/addArtistToOrgHandler.ts index c422bcdc2..561cd9ce1 100644 --- a/lib/organizations/addArtistToOrgHandler.ts +++ b/lib/organizations/addArtistToOrgHandler.ts @@ -62,4 +62,3 @@ export async function addArtistToOrgHandler(request: NextRequest): Promise { +export async function canAccessAccount(params: CanAccessAccountParams): Promise { const { orgId, targetAccountId } = params; if (!orgId || !targetAccountId) { diff --git a/lib/organizations/createOrganizationHandler.ts b/lib/organizations/createOrganizationHandler.ts index 92fc2b237..81548908a 100644 --- a/lib/organizations/createOrganizationHandler.ts +++ b/lib/organizations/createOrganizationHandler.ts @@ -61,4 +61,3 @@ export async function createOrganizationHandler(request: NextRequest): Promise(); return rawOrgs @@ -37,4 +39,3 @@ export function formatAccountOrganizations(rawOrgs: AccountOrganization[]): Form organization_image: org.organization?.account_info?.[0]?.image || null, })); } - diff --git a/lib/organizations/validateAddArtistToOrgBody.ts b/lib/organizations/validateAddArtistToOrgBody.ts index 6b57dc13a..42cd49c89 100644 --- a/lib/organizations/validateAddArtistToOrgBody.ts +++ b/lib/organizations/validateAddArtistToOrgBody.ts @@ -4,7 +4,9 @@ import { z } from "zod"; export const addArtistToOrgBodySchema = z.object({ artistId: z.string({ message: "artistId is required" }).uuid("artistId must be a valid UUID"), - organizationId: z.string({ message: "organizationId is required" }).uuid("organizationId must be a valid UUID"), + organizationId: z + .string({ message: "organizationId is required" }) + .uuid("organizationId must be a valid UUID"), }); export type AddArtistToOrgBody = z.infer; @@ -35,4 +37,3 @@ export function validateAddArtistToOrgBody(body: unknown): NextResponse | AddArt return result.data; } - diff --git a/lib/organizations/validateCreateOrganizationBody.ts b/lib/organizations/validateCreateOrganizationBody.ts index 1ae1f4808..5026b2a31 100644 --- a/lib/organizations/validateCreateOrganizationBody.ts +++ b/lib/organizations/validateCreateOrganizationBody.ts @@ -37,4 +37,3 @@ export function validateCreateOrganizationBody( return result.data; } - diff --git a/lib/perplexity/chatWithPerplexity.ts b/lib/perplexity/chatWithPerplexity.ts index 476d1c375..cf779d05e 100644 --- a/lib/perplexity/chatWithPerplexity.ts +++ b/lib/perplexity/chatWithPerplexity.ts @@ -44,7 +44,9 @@ export async function chatWithPerplexity( if (!response.ok) { const errorText = await response.text(); - throw new Error(`Perplexity API error: ${response.status} ${response.statusText}\n${errorText}`); + throw new Error( + `Perplexity API error: ${response.status} ${response.statusText}\n${errorText}`, + ); } const data = await response.json(); diff --git a/lib/prompts/getSystemPrompt.ts b/lib/prompts/getSystemPrompt.ts index 549646701..5077609a2 100644 --- a/lib/prompts/getSystemPrompt.ts +++ b/lib/prompts/getSystemPrompt.ts @@ -13,6 +13,7 @@ import { AccountWithDetails } from "@/lib/supabase/accounts/getAccountWithDetail * @param params.artistInstruction - The artist instruction * @param params.conversationName - The name of the conversation * @param params.accountWithDetails - The account with details + * @param params.orgId * @returns The system prompt */ export function getSystemPrompt({ diff --git a/lib/pulse/__tests__/buildGetPulsesParams.test.ts b/lib/pulse/__tests__/buildGetPulsesParams.test.ts index 1ff1e8528..50cd90e78 100644 --- a/lib/pulse/__tests__/buildGetPulsesParams.test.ts +++ b/lib/pulse/__tests__/buildGetPulsesParams.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { buildGetPulsesParams } from "../buildGetPulsesParams"; +import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; + vi.mock("@/lib/organizations/canAccessAccount", () => ({ canAccessAccount: vi.fn(), })); @@ -9,8 +11,6 @@ vi.mock("@/lib/const", () => ({ RECOUP_ORG_ID: "recoup-org-id", })); -import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; - describe("buildGetPulsesParams", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/pulse/__tests__/getPulsesHandler.test.ts b/lib/pulse/__tests__/getPulsesHandler.test.ts index f63cba29d..028d1af7e 100644 --- a/lib/pulse/__tests__/getPulsesHandler.test.ts +++ b/lib/pulse/__tests__/getPulsesHandler.test.ts @@ -2,6 +2,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest } from "next/server"; import { getPulsesHandler } from "../getPulsesHandler"; +import { validateGetPulsesRequest } from "../validateGetPulsesRequest"; +import { selectPulseAccounts } from "@/lib/supabase/pulse_accounts/selectPulseAccounts"; + // Mock dependencies vi.mock("../validateGetPulsesRequest", () => ({ validateGetPulsesRequest: vi.fn(), @@ -15,9 +18,6 @@ vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => new Headers()), })); -import { validateGetPulsesRequest } from "../validateGetPulsesRequest"; -import { selectPulseAccounts } from "@/lib/supabase/pulse_accounts/selectPulseAccounts"; - describe("getPulsesHandler", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/pulse/__tests__/updatePulsesHandler.test.ts b/lib/pulse/__tests__/updatePulsesHandler.test.ts index 825bf9cb1..64d796a1e 100644 --- a/lib/pulse/__tests__/updatePulsesHandler.test.ts +++ b/lib/pulse/__tests__/updatePulsesHandler.test.ts @@ -2,6 +2,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest } from "next/server"; import { updatePulsesHandler } from "../updatePulsesHandler"; +import { validateUpdatePulsesRequest } from "../validateUpdatePulsesRequest"; +import { upsertPulseAccount } from "@/lib/supabase/pulse_accounts/upsertPulseAccount"; + // Mock dependencies vi.mock("../validateUpdatePulsesRequest", () => ({ validateUpdatePulsesRequest: vi.fn(), @@ -15,9 +18,6 @@ vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => new Headers()), })); -import { validateUpdatePulsesRequest } from "../validateUpdatePulsesRequest"; -import { upsertPulseAccount } from "@/lib/supabase/pulse_accounts/upsertPulseAccount"; - describe("updatePulsesHandler", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/pulse/__tests__/validateGetPulsesRequest.test.ts b/lib/pulse/__tests__/validateGetPulsesRequest.test.ts index 7219d9c90..6e1ecc681 100644 --- a/lib/pulse/__tests__/validateGetPulsesRequest.test.ts +++ b/lib/pulse/__tests__/validateGetPulsesRequest.test.ts @@ -2,6 +2,9 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest, NextResponse } from "next/server"; import { validateGetPulsesRequest } from "../validateGetPulsesRequest"; +import { validateAuthContext } from "@/lib/auth/validateAuthContext"; +import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; + // Mock dependencies vi.mock("@/lib/auth/validateAuthContext", () => ({ validateAuthContext: vi.fn(), @@ -19,9 +22,6 @@ vi.mock("@/lib/const", () => ({ RECOUP_ORG_ID: "recoup-org-id", })); -import { validateAuthContext } from "@/lib/auth/validateAuthContext"; -import { canAccessAccount } from "@/lib/organizations/canAccessAccount"; - describe("validateGetPulsesRequest", () => { beforeEach(() => { vi.clearAllMocks(); @@ -144,12 +144,9 @@ describe("validateGetPulsesRequest", () => { authToken: "test-token", }); - const request = new NextRequest( - `http://localhost/api/pulses?account_id=${otherAccountId}`, - { - headers: { "x-api-key": "test-api-key" }, - }, - ); + const request = new NextRequest(`http://localhost/api/pulses?account_id=${otherAccountId}`, { + headers: { "x-api-key": "test-api-key" }, + }); const result = await validateGetPulsesRequest(request); expect(result).toBeInstanceOf(NextResponse); @@ -167,12 +164,9 @@ describe("validateGetPulsesRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(true); - const request = new NextRequest( - `http://localhost/api/pulses?account_id=${targetAccountId}`, - { - headers: { "x-api-key": "test-api-key" }, - }, - ); + const request = new NextRequest(`http://localhost/api/pulses?account_id=${targetAccountId}`, { + headers: { "x-api-key": "test-api-key" }, + }); const result = await validateGetPulsesRequest(request); expect(canAccessAccount).toHaveBeenCalledWith({ @@ -194,12 +188,9 @@ describe("validateGetPulsesRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(false); - const request = new NextRequest( - `http://localhost/api/pulses?account_id=${notInOrgId}`, - { - headers: { "x-api-key": "test-api-key" }, - }, - ); + const request = new NextRequest(`http://localhost/api/pulses?account_id=${notInOrgId}`, { + headers: { "x-api-key": "test-api-key" }, + }); const result = await validateGetPulsesRequest(request); expect(canAccessAccount).toHaveBeenCalledWith({ @@ -221,12 +212,9 @@ describe("validateGetPulsesRequest", () => { }); vi.mocked(canAccessAccount).mockResolvedValue(true); // Admin always has access - const request = new NextRequest( - `http://localhost/api/pulses?account_id=${anyAccountId}`, - { - headers: { "x-api-key": "recoup-admin-key" }, - }, - ); + const request = new NextRequest(`http://localhost/api/pulses?account_id=${anyAccountId}`, { + headers: { "x-api-key": "recoup-admin-key" }, + }); const result = await validateGetPulsesRequest(request); expect(canAccessAccount).toHaveBeenCalledWith({ diff --git a/lib/rooms/__tests__/copyRoom.test.ts b/lib/rooms/__tests__/copyRoom.test.ts index 0f1a876ed..94d32b4db 100644 --- a/lib/rooms/__tests__/copyRoom.test.ts +++ b/lib/rooms/__tests__/copyRoom.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { copyRoom } from "../copyRoom"; + const mockSelectRoom = vi.fn(); const mockUpsertRoom = vi.fn(); @@ -15,8 +17,6 @@ vi.mock("@/lib/uuid/generateUUID", () => ({ default: () => "generated-uuid-123", })); -import { copyRoom } from "../copyRoom"; - describe("copyRoom", () => { const mockSourceRoom = { id: "source-room-123", diff --git a/lib/rooms/copyRoom.ts b/lib/rooms/copyRoom.ts index 1cf8e5d46..b5d4f0f63 100644 --- a/lib/rooms/copyRoom.ts +++ b/lib/rooms/copyRoom.ts @@ -10,10 +10,7 @@ import generateUUID from "@/lib/uuid/generateUUID"; * @param artistId - The ID of the artist for the new room * @returns The ID of the new room or null if operation failed */ -export async function copyRoom( - sourceRoomId: string, - artistId: string, -): Promise { +export async function copyRoom(sourceRoomId: string, artistId: string): Promise { try { // Get the source room data const sourceRoom = await selectRoom(sourceRoomId); diff --git a/lib/sandbox/__tests__/createSandboxFromSnapshot.test.ts b/lib/sandbox/__tests__/createSandboxFromSnapshot.test.ts index a4db1b612..887d136c2 100644 --- a/lib/sandbox/__tests__/createSandboxFromSnapshot.test.ts +++ b/lib/sandbox/__tests__/createSandboxFromSnapshot.test.ts @@ -12,13 +12,11 @@ vi.mock("@/lib/sandbox/createSandbox", () => ({ })); vi.mock("@/lib/supabase/account_snapshots/selectAccountSnapshots", () => ({ - selectAccountSnapshots: (...args: unknown[]) => - mockSelectAccountSnapshots(...args), + selectAccountSnapshots: (...args: unknown[]) => mockSelectAccountSnapshots(...args), })); vi.mock("@/lib/supabase/account_sandboxes/insertAccountSandbox", () => ({ - insertAccountSandbox: (...args: unknown[]) => - mockInsertAccountSandbox(...args), + insertAccountSandbox: (...args: unknown[]) => mockInsertAccountSandbox(...args), })); describe("createSandboxFromSnapshot", () => { diff --git a/lib/sandbox/__tests__/getActiveSandbox.test.ts b/lib/sandbox/__tests__/getActiveSandbox.test.ts index 9cfe3dbad..581337076 100644 --- a/lib/sandbox/__tests__/getActiveSandbox.test.ts +++ b/lib/sandbox/__tests__/getActiveSandbox.test.ts @@ -12,8 +12,7 @@ vi.mock("@vercel/sandbox", () => ({ })); vi.mock("@/lib/supabase/account_sandboxes/selectAccountSandboxes", () => ({ - selectAccountSandboxes: (...args: unknown[]) => - mockSelectAccountSandboxes(...args), + selectAccountSandboxes: (...args: unknown[]) => mockSelectAccountSandboxes(...args), })); describe("getActiveSandbox", () => { @@ -22,18 +21,14 @@ describe("getActiveSandbox", () => { }); it("returns sandbox when most recent is running", async () => { - mockSelectAccountSandboxes.mockResolvedValue([ - { sandbox_id: "sbx_123", account_id: "acc_1" }, - ]); + mockSelectAccountSandboxes.mockResolvedValue([{ sandbox_id: "sbx_123", account_id: "acc_1" }]); const mockSandbox = { sandboxId: "sbx_123", status: "running", runCommand: vi.fn(), }; - vi.mocked(Sandbox.get).mockResolvedValue( - mockSandbox as unknown as Sandbox, - ); + vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as unknown as Sandbox); const result = await getActiveSandbox("acc_1"); @@ -62,9 +57,7 @@ describe("getActiveSandbox", () => { sandboxId: "sbx_stopped", status: "stopped", }; - vi.mocked(Sandbox.get).mockResolvedValue( - mockSandbox as unknown as Sandbox, - ); + vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as unknown as Sandbox); const result = await getActiveSandbox("acc_1"); diff --git a/lib/sandbox/__tests__/getOrCreateSandbox.test.ts b/lib/sandbox/__tests__/getOrCreateSandbox.test.ts index 749ae70ff..56e641bc9 100644 --- a/lib/sandbox/__tests__/getOrCreateSandbox.test.ts +++ b/lib/sandbox/__tests__/getOrCreateSandbox.test.ts @@ -11,8 +11,7 @@ vi.mock("../getActiveSandbox", () => ({ })); vi.mock("../createSandboxFromSnapshot", () => ({ - createSandboxFromSnapshot: (...args: unknown[]) => - mockCreateSandboxFromSnapshot(...args), + createSandboxFromSnapshot: (...args: unknown[]) => mockCreateSandboxFromSnapshot(...args), })); describe("getOrCreateSandbox", () => { diff --git a/lib/sandbox/__tests__/getSandboxesFileHandler.test.ts b/lib/sandbox/__tests__/getSandboxesFileHandler.test.ts index 69690ac08..b8a772600 100644 --- a/lib/sandbox/__tests__/getSandboxesFileHandler.test.ts +++ b/lib/sandbox/__tests__/getSandboxesFileHandler.test.ts @@ -41,7 +41,7 @@ describe("getSandboxesFileHandler", () => { beforeEach(() => { vi.clearAllMocks(); // Default: resolveSubmodulePath passes through unchanged - vi.mocked(resolveSubmodulePath).mockImplementation(async (params) => params); + vi.mocked(resolveSubmodulePath).mockImplementation(async params => params); }); it("returns error response when validation fails", async () => { diff --git a/lib/sandbox/getActiveSandbox.ts b/lib/sandbox/getActiveSandbox.ts index 24fdf8f3f..faa220ad9 100644 --- a/lib/sandbox/getActiveSandbox.ts +++ b/lib/sandbox/getActiveSandbox.ts @@ -7,9 +7,7 @@ import { selectAccountSandboxes } from "@/lib/supabase/account_sandboxes/selectA * @param accountId - The account ID to find an active sandbox for * @returns The running Sandbox instance, or null if none found */ -export async function getActiveSandbox( - accountId: string, -): Promise { +export async function getActiveSandbox(accountId: string): Promise { const sandboxes = await selectAccountSandboxes({ accountIds: [accountId], }); diff --git a/lib/sandbox/runClaudeCode.ts b/lib/sandbox/runClaudeCode.ts index ccf83eec0..196fed228 100644 --- a/lib/sandbox/runClaudeCode.ts +++ b/lib/sandbox/runClaudeCode.ts @@ -9,7 +9,7 @@ import type { Sandbox } from "@vercel/sandbox"; */ export async function runClaudeCode(sandbox: Sandbox, prompt: string): Promise { const script = `claude --permission-mode acceptEdits --model opus '${prompt}'`; - + await sandbox.writeFiles([ { path: "/vercel/sandbox/ralph-once.sh", diff --git a/lib/segments/createSegmentResponses.ts b/lib/segments/createSegmentResponses.ts index c9269ab08..ec25b5db2 100644 --- a/lib/segments/createSegmentResponses.ts +++ b/lib/segments/createSegmentResponses.ts @@ -27,4 +27,3 @@ export const errorResponse = (message: string) => ({ data: [], count: 0, }); - diff --git a/lib/slack/chat/bot.ts b/lib/slack/chat/bot.ts deleted file mode 100644 index ff7017e98..000000000 --- a/lib/slack/chat/bot.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Chat, ConsoleLogger } from "chat"; -import { SlackAdapter } from "@chat-adapter/slack"; -import { createIoRedisState } from "@chat-adapter/state-ioredis"; -import redis from "@/lib/redis/connection"; -import type { SlackChatThreadState } from "./types"; -import { validateSlackChatEnv } from "./validateEnv"; - -const logger = new ConsoleLogger(); - -type SlackChatAdapters = { - slack: SlackAdapter; -}; - -/** - * Creates a new Chat bot instance configured with a single Slack adapter - * for the Record Label Agent. - * - * @returns A configured Chat instance - */ -export function createSlackChatBot() { - validateSlackChatEnv(); - - // ioredis is configured with lazyConnect: true, so we must - // explicitly connect before the state adapter listens for "ready". - if (redis.status === "wait") { - redis.connect().catch(() => { - throw new Error("[slack-chat] Redis failed to connect"); - }); - } - - const state = createIoRedisState({ - client: redis, - keyPrefix: "chat", - logger, - }); - - const slack = new SlackAdapter({ - botToken: process.env.SLACK_CHAT_BOT_TOKEN!, - signingSecret: process.env.SLACK_CHAT_SIGNING_SECRET!, - logger, - }); - - return new Chat({ - userName: "Record Label Agent", - adapters: { slack }, - state, - }); -} - -export type SlackChatBot = ReturnType; - -/** - * Singleton bot instance. - * Does NOT call registerSingleton() to avoid conflicting with the coding-agent bot. - */ -export const slackChatBot = createSlackChatBot(); diff --git a/lib/slack/chat/handlers/handleSlackChatMessage.ts b/lib/slack/chat/handlers/handleSlackChatMessage.ts deleted file mode 100644 index 5838d84a8..000000000 --- a/lib/slack/chat/handlers/handleSlackChatMessage.ts +++ /dev/null @@ -1,129 +0,0 @@ -import type { UIMessage } from "ai"; -import type { SlackChatThreadState } from "../types"; -import type { ChatRequestBody } from "@/lib/chat/validateChatRequest"; -import { getMessages } from "@/lib/messages/getMessages"; -import convertToUiMessages from "@/lib/messages/convertToUiMessages"; -import { validateMessages } from "@/lib/chat/validateMessages"; -import { setupConversation } from "@/lib/chat/setupConversation"; -import { setupChatRequest } from "@/lib/chat/setupChatRequest"; -import { saveChatCompletion } from "@/lib/chat/saveChatCompletion"; -import { getApiKeyDetails } from "@/lib/keys/getApiKeyDetails"; -import selectMemories from "@/lib/supabase/memories/selectMemories"; - -/** - * Shared handler for both onNewMention and onSubscribedMessage. - * Generates an AI response and posts it back to the Slack thread. - * - * @param thread - The Chat SDK thread instance - * @param thread.state - Promise resolving to the current thread state - * @param thread.post - Posts a message to the thread - * @param thread.setState - Updates the thread state - * @param text - The user's message text - */ -export async function handleSlackChatMessage( - thread: { - state: Promise; - post: (message: string) => Promise; - setState: (state: SlackChatThreadState) => Promise; - }, - text: string, -) { - const currentState = await thread.state; - - // Prevent concurrent generation in the same thread - if (currentState?.status === "generating") { - await thread.post("I'm still working on a response. Please wait a moment."); - return; - } - - const authToken = process.env.SLACK_CHAT_API_KEY!; - - // Derive account from the API key — no hardcoded account ID - const keyDetails = await getApiKeyDetails(authToken); - if (!keyDetails) { - console.error("[slack-chat] Invalid SLACK_CHAT_API_KEY — could not resolve account"); - await thread.post("Sorry, I'm not configured correctly. Please contact support."); - return; - } - - const { accountId, orgId } = keyDetails; - - await thread.setState({ - status: "generating", - prompt: text, - roomId: currentState?.roomId, - }); - - await thread.post("Thinking..."); - - let finalRoomId = currentState?.roomId; - - try { - // Build current message as UIMessage - const newMessages = getMessages(text, "user"); - const newUiMessages = convertToUiMessages(newMessages); - const { lastMessage } = validateMessages(newUiMessages); - - // Setup conversation: create room if needed, persist user message - const { roomId } = await setupConversation({ - accountId, - roomId: currentState?.roomId, - topic: text.slice(0, 100), - promptMessage: lastMessage, - memoryId: lastMessage.id, - }); - - finalRoomId = roomId; - - // Load full conversation history from the room (includes the message we just saved) - const memories = await selectMemories(roomId, { ascending: true }); - const historyMessages: UIMessage[] = (memories ?? []) - .filter(m => { - const content = m.content as unknown as { role?: string; parts?: unknown[] }; - return content?.role && content?.parts; - }) - .map(m => { - const content = m.content as unknown as UIMessage; - return { - id: m.id, - role: content.role, - parts: content.parts, - }; - }); - - const allUiMessages = convertToUiMessages( - historyMessages.length > 0 ? historyMessages : newUiMessages, - ); - - // Build ChatRequestBody — accountId inferred from API key - const body: ChatRequestBody = { - messages: allUiMessages, - accountId, - orgId, - roomId, - authToken, - }; - - const chatConfig = await setupChatRequest(body); - const result = await chatConfig.agent.generate(chatConfig); - - // Persist assistant response - try { - await saveChatCompletion({ text: result.text, roomId }); - } catch (error) { - console.error("[slack-chat] Failed to persist assistant message:", error); - } - - // Post response to Slack thread - await thread.post(result.text); - } catch (error) { - console.error("[slack-chat] Generation failed:", error); - await thread.post("Sorry, something went wrong. Please try again."); - } finally { - await thread.setState({ - status: "idle", - prompt: text, - roomId: finalRoomId, - }); - } -} diff --git a/lib/slack/chat/handlers/onNewMention.ts b/lib/slack/chat/handlers/onNewMention.ts deleted file mode 100644 index 215b9ef2b..000000000 --- a/lib/slack/chat/handlers/onNewMention.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { SlackChatBot } from "../bot"; -import { handleSlackChatMessage } from "./handleSlackChatMessage"; - -/** - * Registers the onNewMention handler on the Slack chat bot. - * Subscribes to the thread for follow-up messages, then generates a response. - * - * @param bot - The Slack chat bot instance - */ -export function registerOnNewMention(bot: SlackChatBot) { - bot.onNewMention(async (thread, message) => { - try { - await thread.subscribe(); - await handleSlackChatMessage(thread, message.text); - } catch (error) { - console.error("[slack-chat] onNewMention error:", error); - } - }); -} diff --git a/lib/slack/chat/handlers/onSubscribedMessage.ts b/lib/slack/chat/handlers/onSubscribedMessage.ts deleted file mode 100644 index a084d320d..000000000 --- a/lib/slack/chat/handlers/onSubscribedMessage.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { SlackChatBot } from "../bot"; -import { handleSlackChatMessage } from "./handleSlackChatMessage"; - -/** - * Registers the onSubscribedMessage handler on the Slack chat bot. - * Reuses the existing roomId from thread state for conversational memory. - * - * @param bot - The Slack chat bot instance - */ -export function registerOnSubscribedMessage(bot: SlackChatBot) { - bot.onSubscribedMessage(async (thread, message) => { - try { - await handleSlackChatMessage(thread, message.text); - } catch (error) { - console.error("[slack-chat] onSubscribedMessage error:", error); - } - }); -} diff --git a/lib/slack/chat/handlers/registerHandlers.ts b/lib/slack/chat/handlers/registerHandlers.ts deleted file mode 100644 index 075d2cfe0..000000000 --- a/lib/slack/chat/handlers/registerHandlers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { slackChatBot } from "../bot"; -import { registerOnNewMention } from "./onNewMention"; -import { registerOnSubscribedMessage } from "./onSubscribedMessage"; - -/** - * Registers all Slack chat bot event handlers on the bot singleton. - * Import this file once to attach handlers to the bot. - */ -registerOnNewMention(slackChatBot); -registerOnSubscribedMessage(slackChatBot); diff --git a/lib/slack/chat/types.ts b/lib/slack/chat/types.ts deleted file mode 100644 index 10f5a28c2..000000000 --- a/lib/slack/chat/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Thread state for the Slack chat bot. - * Stored in Redis via Chat SDK's state adapter. - */ -export interface SlackChatThreadState { - status: "idle" | "generating"; - prompt: string; - /** Persists across thread messages so the chat has memory. */ - roomId?: string; -} diff --git a/lib/slack/chat/validateEnv.ts b/lib/slack/chat/validateEnv.ts deleted file mode 100644 index f043cef0a..000000000 --- a/lib/slack/chat/validateEnv.ts +++ /dev/null @@ -1,20 +0,0 @@ -const REQUIRED_ENV_VARS = [ - "SLACK_CHAT_BOT_TOKEN", - "SLACK_CHAT_SIGNING_SECRET", - "SLACK_CHAT_API_KEY", - "REDIS_URL", -] as const; - -/** - * Validates that all required environment variables for the Slack chat bot are set. - * Throws an error listing all missing variables. - */ -export function validateSlackChatEnv(): void { - const missing: string[] = REQUIRED_ENV_VARS.filter(name => !process.env[name]); - - if (missing.length > 0) { - throw new Error( - `[slack-chat] Missing required environment variables:\n${missing.map(v => ` - ${v}`).join("\n")}`, - ); - } -} diff --git a/lib/slack/handleUrlVerification.ts b/lib/slack/handleUrlVerification.ts deleted file mode 100644 index 5c29b3a9e..000000000 --- a/lib/slack/handleUrlVerification.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { NextRequest } from "next/server"; - -/** - * Handles Slack url_verification challenge before bot initialization. - * This avoids blocking on Redis/adapter initialization during setup. - * - * @param request - The incoming webhook request - * @returns A Response with the challenge if verified, or null to continue processing - */ -export async function handleUrlVerification(request: NextRequest): Promise { - const body = await request - .clone() - .json() - .catch(() => null); - - if (body?.type === "url_verification" && typeof body?.challenge === "string") { - return Response.json({ challenge: body.challenge }); - } - - return null; -} diff --git a/lib/spotify/getSpotifyFollowers.ts b/lib/spotify/getSpotifyFollowers.ts index da4903686..acd1c3be8 100644 --- a/lib/spotify/getSpotifyFollowers.ts +++ b/lib/spotify/getSpotifyFollowers.ts @@ -37,6 +37,7 @@ interface SpotifySearchResponse { /** * Get Spotify follower count for an artist + * * @param artistName - The name of the artist to search for * @returns Promise - The follower count of the first matching artist */ @@ -48,9 +49,7 @@ export async function getSpotifyFollowers(artistName: string): Promise { const response = await fetch(url); if (!response.ok) { - throw new Error( - `API request failed: ${response.status} ${response.statusText}` - ); + throw new Error(`API request failed: ${response.status} ${response.statusText}`); } const data: SpotifySearchResponse = await response.json(); @@ -61,10 +60,7 @@ export async function getSpotifyFollowers(artistName: string): Promise { return data.artists.items[0].followers.total; } catch (error) { - console.error( - `Error fetching Spotify followers for "${artistName}":`, - error - ); + console.error(`Error fetching Spotify followers for "${artistName}":`, error); throw error; } } diff --git a/lib/supabase/account_artist_ids/__tests__/insertAccountArtistId.test.ts b/lib/supabase/account_artist_ids/__tests__/insertAccountArtistId.test.ts index 2087aeda9..725b88924 100644 --- a/lib/supabase/account_artist_ids/__tests__/insertAccountArtistId.test.ts +++ b/lib/supabase/account_artist_ids/__tests__/insertAccountArtistId.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { insertAccountArtistId } from "../insertAccountArtistId"; + const mockFrom = vi.fn(); const mockInsert = vi.fn(); const mockSelect = vi.fn(); @@ -11,8 +13,6 @@ vi.mock("@/lib/supabase/serverClient", () => ({ }, })); -import { insertAccountArtistId } from "../insertAccountArtistId"; - describe("insertAccountArtistId", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/account_artist_ids/__tests__/selectAccountArtistId.test.ts b/lib/supabase/account_artist_ids/__tests__/selectAccountArtistId.test.ts index 12c6935b1..cd06f9b97 100644 --- a/lib/supabase/account_artist_ids/__tests__/selectAccountArtistId.test.ts +++ b/lib/supabase/account_artist_ids/__tests__/selectAccountArtistId.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { selectAccountArtistId } from "../selectAccountArtistId"; +import supabase from "../../serverClient"; + vi.mock("../../serverClient", () => { const mockFrom = vi.fn(); return { @@ -8,8 +10,6 @@ vi.mock("../../serverClient", () => { }; }); -import supabase from "../../serverClient"; - describe("selectAccountArtistId", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/account_artist_ids/getAccountArtistIds.ts b/lib/supabase/account_artist_ids/getAccountArtistIds.ts index 834c48abc..42b550d07 100644 --- a/lib/supabase/account_artist_ids/getAccountArtistIds.ts +++ b/lib/supabase/account_artist_ids/getAccountArtistIds.ts @@ -8,7 +8,9 @@ export type AccountArtistRow = ArtistQueryRow & { artist_id: string; pinned: boo * Get all artists for an array of artist IDs or account IDs, with full info. * Returns raw data - formatting should be done by caller. * - * @param params Object with artistIds or accountIds array + * @param params - Object with artistIds or accountIds array + * @param params.artistIds + * @param params.accountIds * @returns Array of raw artist rows from database */ export async function getAccountArtistIds(params: { @@ -46,4 +48,3 @@ export async function getAccountArtistIds(params: { return (data || []) as unknown as AccountArtistRow[]; } - diff --git a/lib/supabase/account_artist_ids/selectAccountArtistId.ts b/lib/supabase/account_artist_ids/selectAccountArtistId.ts index 8031957e6..baddf7772 100644 --- a/lib/supabase/account_artist_ids/selectAccountArtistId.ts +++ b/lib/supabase/account_artist_ids/selectAccountArtistId.ts @@ -7,10 +7,7 @@ import supabase from "../serverClient"; * @param artistId - The artist ID * @returns The row if found, null if not found or on error */ -export async function selectAccountArtistId( - accountId: string, - artistId: string, -) { +export async function selectAccountArtistId(accountId: string, artistId: string) { const { data, error } = await supabase .from("account_artist_ids") .select("artist_id") diff --git a/lib/supabase/account_info/insertAccountInfo.ts b/lib/supabase/account_info/insertAccountInfo.ts index b83bb4a38..b9ae6e343 100644 --- a/lib/supabase/account_info/insertAccountInfo.ts +++ b/lib/supabase/account_info/insertAccountInfo.ts @@ -19,4 +19,3 @@ export async function insertAccountInfo( return data || null; } - diff --git a/lib/supabase/account_organization_ids/__tests__/selectAccountOrganizationIds.test.ts b/lib/supabase/account_organization_ids/__tests__/selectAccountOrganizationIds.test.ts index d4c7a5953..de672a2a6 100644 --- a/lib/supabase/account_organization_ids/__tests__/selectAccountOrganizationIds.test.ts +++ b/lib/supabase/account_organization_ids/__tests__/selectAccountOrganizationIds.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { selectAccountOrganizationIds } from "../selectAccountOrganizationIds"; +import supabase from "../../serverClient"; + vi.mock("../../serverClient", () => { const mockFrom = vi.fn(); return { @@ -8,8 +10,6 @@ vi.mock("../../serverClient", () => { }; }); -import supabase from "../../serverClient"; - describe("selectAccountOrganizationIds", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/account_organization_ids/addAccountToOrganization.ts b/lib/supabase/account_organization_ids/addAccountToOrganization.ts index 846ae7b42..115a57105 100644 --- a/lib/supabase/account_organization_ids/addAccountToOrganization.ts +++ b/lib/supabase/account_organization_ids/addAccountToOrganization.ts @@ -27,4 +27,3 @@ export async function addAccountToOrganization( return data?.id || null; } - diff --git a/lib/supabase/account_organization_ids/selectAccountOrganizationIds.ts b/lib/supabase/account_organization_ids/selectAccountOrganizationIds.ts index 68fd66182..5be4a4c10 100644 --- a/lib/supabase/account_organization_ids/selectAccountOrganizationIds.ts +++ b/lib/supabase/account_organization_ids/selectAccountOrganizationIds.ts @@ -7,10 +7,7 @@ import supabase from "../serverClient"; * @param orgIds - Organization IDs to check membership against * @returns Array of matching rows, or null on error */ -export async function selectAccountOrganizationIds( - accountId: string, - orgIds: string[], -) { +export async function selectAccountOrganizationIds(accountId: string, orgIds: string[]) { if (!orgIds.length) return []; const { data, error } = await supabase diff --git a/lib/supabase/account_sandboxes/__tests__/insertAccountSandbox.test.ts b/lib/supabase/account_sandboxes/__tests__/insertAccountSandbox.test.ts index 15e605d99..f370a34dd 100644 --- a/lib/supabase/account_sandboxes/__tests__/insertAccountSandbox.test.ts +++ b/lib/supabase/account_sandboxes/__tests__/insertAccountSandbox.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { insertAccountSandbox } from "../insertAccountSandbox"; + const mockFrom = vi.fn(); const mockInsert = vi.fn(); const mockSelect = vi.fn(); @@ -11,8 +13,6 @@ vi.mock("@/lib/supabase/serverClient", () => ({ }, })); -import { insertAccountSandbox } from "../insertAccountSandbox"; - describe("insertAccountSandbox", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/account_snapshots/__tests__/upsertAccountSnapshot.test.ts b/lib/supabase/account_snapshots/__tests__/upsertAccountSnapshot.test.ts index de71fd24f..cf198d030 100644 --- a/lib/supabase/account_snapshots/__tests__/upsertAccountSnapshot.test.ts +++ b/lib/supabase/account_snapshots/__tests__/upsertAccountSnapshot.test.ts @@ -79,8 +79,7 @@ describe("upsertAccountSnapshot", () => { it("returns error when account_id foreign key constraint fails", async () => { const mockError = { - message: - 'insert or update on table "account_snapshots" violates foreign key constraint', + message: 'insert or update on table "account_snapshots" violates foreign key constraint', code: "23503", }; mockSingle.mockResolvedValue({ data: null, error: mockError }); diff --git a/lib/supabase/account_workspace_ids/__tests__/selectAccountWorkspaceId.test.ts b/lib/supabase/account_workspace_ids/__tests__/selectAccountWorkspaceId.test.ts index e3611d226..135134c34 100644 --- a/lib/supabase/account_workspace_ids/__tests__/selectAccountWorkspaceId.test.ts +++ b/lib/supabase/account_workspace_ids/__tests__/selectAccountWorkspaceId.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { selectAccountWorkspaceId } from "../selectAccountWorkspaceId"; +import supabase from "../../serverClient"; + vi.mock("../../serverClient", () => { const mockFrom = vi.fn(); return { @@ -8,8 +10,6 @@ vi.mock("../../serverClient", () => { }; }); -import supabase from "../../serverClient"; - describe("selectAccountWorkspaceId", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/account_workspace_ids/getAccountWorkspaceIds.ts b/lib/supabase/account_workspace_ids/getAccountWorkspaceIds.ts index 989fe9bab..4ca7ad8ee 100644 --- a/lib/supabase/account_workspace_ids/getAccountWorkspaceIds.ts +++ b/lib/supabase/account_workspace_ids/getAccountWorkspaceIds.ts @@ -10,7 +10,7 @@ export type AccountWorkspaceRow = Omit & { * Get all workspaces for an account, with full info. * Returns raw data - formatting should be done by caller. * - * @param accountId The owner's account ID + * @param accountId - The owner's account ID * @returns Array of raw workspace rows from database */ export async function getAccountWorkspaceIds(accountId: string): Promise { @@ -39,4 +39,3 @@ export async function getAccountWorkspaceIds(accountId: string): Promise ({ }, })); -import { selectAccountWithSocials } from "../selectAccountWithSocials"; - describe("selectAccountWithSocials", () => { beforeEach(() => { vi.clearAllMocks(); @@ -27,7 +27,13 @@ describe("selectAccountWithSocials", () => { name: "Test Artist", timestamp: 1704067200000, account_socials: [{ id: "social-1", platform: "spotify" }], - account_info: [{ id: "info-1", image: "https://example.com/image.jpg", updated_at: "2024-01-01T12:00:00Z" }], + account_info: [ + { + id: "info-1", + image: "https://example.com/image.jpg", + updated_at: "2024-01-01T12:00:00Z", + }, + ], }; mockSingle.mockResolvedValue({ data: mockData, error: null }); diff --git a/lib/supabase/accounts/selectAccounts.ts b/lib/supabase/accounts/selectAccounts.ts index 1770011f2..8b54c3bd4 100644 --- a/lib/supabase/accounts/selectAccounts.ts +++ b/lib/supabase/accounts/selectAccounts.ts @@ -10,19 +10,14 @@ import type { Tables } from "@/types/database.types"; * @param accountId - A single account ID string, or an array of account IDs * @returns Array of account records (empty array if not found or on error) */ -export async function selectAccounts( - accountId: string | string[], -): Promise[]> { +export async function selectAccounts(accountId: string | string[]): Promise[]> { const ids = Array.isArray(accountId) ? accountId : [accountId]; if (ids.length === 0) { return []; } - const { data, error } = await supabase - .from("accounts") - .select("*") - .in("id", ids); + const { data, error } = await supabase.from("accounts").select("*").in("id", ids); if (error) { throw error; diff --git a/lib/supabase/artist_organization_ids/__tests__/selectArtistOrganizationIds.test.ts b/lib/supabase/artist_organization_ids/__tests__/selectArtistOrganizationIds.test.ts index b1df57141..405eac75e 100644 --- a/lib/supabase/artist_organization_ids/__tests__/selectArtistOrganizationIds.test.ts +++ b/lib/supabase/artist_organization_ids/__tests__/selectArtistOrganizationIds.test.ts @@ -1,6 +1,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { selectArtistOrganizationIds } from "../selectArtistOrganizationIds"; +import supabase from "../../serverClient"; + vi.mock("../../serverClient", () => { const mockFrom = vi.fn(); return { @@ -8,8 +10,6 @@ vi.mock("../../serverClient", () => { }; }); -import supabase from "../../serverClient"; - describe("selectArtistOrganizationIds", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/artist_organization_ids/addArtistToOrganization.ts b/lib/supabase/artist_organization_ids/addArtistToOrganization.ts index 5f8f4feb9..7714adbe1 100644 --- a/lib/supabase/artist_organization_ids/addArtistToOrganization.ts +++ b/lib/supabase/artist_organization_ids/addArtistToOrganization.ts @@ -31,4 +31,3 @@ export async function addArtistToOrganization( return data?.id || null; } - diff --git a/lib/supabase/artist_organization_ids/getArtistsByOrganization.ts b/lib/supabase/artist_organization_ids/getArtistsByOrganization.ts index d67a85562..3a3fb49e0 100644 --- a/lib/supabase/artist_organization_ids/getArtistsByOrganization.ts +++ b/lib/supabase/artist_organization_ids/getArtistsByOrganization.ts @@ -43,4 +43,3 @@ export async function getArtistsByOrganization(organizationIds: string[]): Promi return (data || []) as unknown as ArtistOrgRow[]; } - diff --git a/lib/supabase/files/createFileRecord.ts b/lib/supabase/files/createFileRecord.ts index 6b06744b1..3182de110 100644 --- a/lib/supabase/files/createFileRecord.ts +++ b/lib/supabase/files/createFileRecord.ts @@ -25,10 +25,10 @@ export interface CreateFileRecordParams { /** * Create a file record in the database + * + * @param params */ -export async function createFileRecord( - params: CreateFileRecordParams -): Promise { +export async function createFileRecord(params: CreateFileRecordParams): Promise { const { ownerAccountId, artistAccountId, @@ -61,4 +61,3 @@ export async function createFileRecord( return data; } - diff --git a/lib/supabase/pulse_accounts/__tests__/selectPulseAccounts.test.ts b/lib/supabase/pulse_accounts/__tests__/selectPulseAccounts.test.ts index be7cfd6f4..3bb902588 100644 --- a/lib/supabase/pulse_accounts/__tests__/selectPulseAccounts.test.ts +++ b/lib/supabase/pulse_accounts/__tests__/selectPulseAccounts.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { selectPulseAccounts } from "../selectPulseAccounts"; + const mockFrom = vi.fn(); const mockSelect = vi.fn(); const mockIn = vi.fn(); @@ -11,8 +13,6 @@ vi.mock("@/lib/supabase/serverClient", () => ({ }, })); -import { selectPulseAccounts } from "../selectPulseAccounts"; - describe("selectPulseAccounts", () => { beforeEach(() => { vi.clearAllMocks(); @@ -107,16 +107,31 @@ describe("selectPulseAccounts", () => { mockEq.mockReturnValue({ eq: mockChainedEq }); const pulses = [ - { id: "pulse-1", account_id: "member-1", active: true, accounts: { account_organization_ids: { organization_id: "org-123" } } }, - { id: "pulse-2", account_id: "member-2", active: false, accounts: { account_organization_ids: { organization_id: "org-123" } } }, + { + id: "pulse-1", + account_id: "member-1", + active: true, + accounts: { account_organization_ids: { organization_id: "org-123" } }, + }, + { + id: "pulse-2", + account_id: "member-2", + active: false, + accounts: { account_organization_ids: { organization_id: "org-123" } }, + }, ]; mockEq.mockResolvedValue({ data: pulses, error: null }); const result = await selectPulseAccounts({ orgId: "org-123" }); expect(mockFrom).toHaveBeenCalledWith("pulse_accounts"); - expect(mockSelect).toHaveBeenCalledWith("*, accounts!inner(account_organization_ids!account_organization_ids_account_id_fkey!inner(organization_id))"); - expect(mockEq).toHaveBeenCalledWith("accounts.account_organization_ids.organization_id", "org-123"); + expect(mockSelect).toHaveBeenCalledWith( + "*, accounts!inner(account_organization_ids!account_organization_ids_account_id_fkey!inner(organization_id))", + ); + expect(mockEq).toHaveBeenCalledWith( + "accounts.account_organization_ids.organization_id", + "org-123", + ); // Result should strip the joined data expect(result).toEqual([ { id: "pulse-1", account_id: "member-1", active: true }, @@ -128,13 +143,25 @@ describe("selectPulseAccounts", () => { const mockChainedEq = vi.fn(); mockEq.mockReturnValue({ eq: mockChainedEq }); - const pulses = [{ id: "pulse-1", account_id: "member-1", active: true, accounts: { account_organization_ids: { organization_id: "org-123" } } }]; + const pulses = [ + { + id: "pulse-1", + account_id: "member-1", + active: true, + accounts: { account_organization_ids: { organization_id: "org-123" } }, + }, + ]; mockChainedEq.mockResolvedValue({ data: pulses, error: null }); const result = await selectPulseAccounts({ orgId: "org-123", active: true }); - expect(mockSelect).toHaveBeenCalledWith("*, accounts!inner(account_organization_ids!account_organization_ids_account_id_fkey!inner(organization_id))"); - expect(mockEq).toHaveBeenCalledWith("accounts.account_organization_ids.organization_id", "org-123"); + expect(mockSelect).toHaveBeenCalledWith( + "*, accounts!inner(account_organization_ids!account_organization_ids_account_id_fkey!inner(organization_id))", + ); + expect(mockEq).toHaveBeenCalledWith( + "accounts.account_organization_ids.organization_id", + "org-123", + ); expect(mockChainedEq).toHaveBeenCalledWith("active", true); // Result should strip the joined data expect(result).toEqual([{ id: "pulse-1", account_id: "member-1", active: true }]); diff --git a/lib/supabase/pulse_accounts/__tests__/upsertPulseAccount.test.ts b/lib/supabase/pulse_accounts/__tests__/upsertPulseAccount.test.ts index 0e19bcdae..4873e2e4b 100644 --- a/lib/supabase/pulse_accounts/__tests__/upsertPulseAccount.test.ts +++ b/lib/supabase/pulse_accounts/__tests__/upsertPulseAccount.test.ts @@ -1,5 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +import { upsertPulseAccount } from "../upsertPulseAccount"; + const mockFrom = vi.fn(); const mockUpsert = vi.fn(); const mockSelect = vi.fn(); @@ -10,8 +12,6 @@ vi.mock("@/lib/supabase/serverClient", () => ({ }, })); -import { upsertPulseAccount } from "../upsertPulseAccount"; - describe("upsertPulseAccount", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/lib/supabase/song_artists/insertSongArtists.ts b/lib/supabase/song_artists/insertSongArtists.ts index bec45fae1..69878d6d2 100644 --- a/lib/supabase/song_artists/insertSongArtists.ts +++ b/lib/supabase/song_artists/insertSongArtists.ts @@ -5,13 +5,12 @@ export type SongArtistInsert = TablesInsert<"song_artists">; /** * Inserts song-artist relationships, skipping duplicates. + * + * @param songArtists */ -export async function insertSongArtists( - songArtists: SongArtistInsert[] -): Promise { +export async function insertSongArtists(songArtists: SongArtistInsert[]): Promise { const records = songArtists.filter( - (record): record is SongArtistInsert => - Boolean(record.song) && Boolean(record.artist) + (record): record is SongArtistInsert => Boolean(record.song) && Boolean(record.artist), ); if (records.length === 0) { @@ -19,16 +18,12 @@ export async function insertSongArtists( } const deduped = [ - ...new Map( - records.map((record) => [`${record.song}-${record.artist}`, record]) - ).values(), + ...new Map(records.map(record => [`${record.song}-${record.artist}`, record])).values(), ]; - const { error } = await supabase - .from("song_artists") - .upsert(deduped, { - onConflict: "song,artist", - }); + const { error } = await supabase.from("song_artists").upsert(deduped, { + onConflict: "song,artist", + }); if (error) { throw new Error(`Failed to insert song artists: ${error.message}`); diff --git a/lib/supabase/storage/uploadFileByKey.ts b/lib/supabase/storage/uploadFileByKey.ts index c04f2bd3c..ae1491730 100644 --- a/lib/supabase/storage/uploadFileByKey.ts +++ b/lib/supabase/storage/uploadFileByKey.ts @@ -3,6 +3,12 @@ import { SUPABASE_STORAGE_BUCKET } from "@/lib/const"; /** * Upload file to Supabase storage by key + * + * @param key + * @param file + * @param options + * @param options.contentType + * @param options.upsert */ export async function uploadFileByKey( key: string, @@ -10,17 +16,14 @@ export async function uploadFileByKey( options: { contentType?: string; upsert?: boolean; - } = {} + } = {}, ): Promise { - const { error } = await supabase.storage - .from(SUPABASE_STORAGE_BUCKET) - .upload(key, file, { - contentType: options.contentType || "application/octet-stream", - upsert: options.upsert ?? false, - }); + const { error } = await supabase.storage.from(SUPABASE_STORAGE_BUCKET).upload(key, file, { + contentType: options.contentType || "application/octet-stream", + upsert: options.upsert ?? false, + }); if (error) { throw new Error(`Failed to upload file: ${error.message}`); } } - diff --git a/lib/tasks/__tests__/deleteTask.test.ts b/lib/tasks/__tests__/deleteTask.test.ts index 79d2cb0e8..df95eb632 100644 --- a/lib/tasks/__tests__/deleteTask.test.ts +++ b/lib/tasks/__tests__/deleteTask.test.ts @@ -1,5 +1,11 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; +// Import after mocks +import { deleteTask } from "../deleteTask"; +import { selectScheduledActions } from "@/lib/supabase/scheduled_actions/selectScheduledActions"; +import { deleteScheduledAction } from "@/lib/supabase/scheduled_actions/deleteScheduledAction"; +import { deleteSchedule } from "@/lib/trigger/deleteSchedule"; + // Mock external dependencies vi.mock("@/lib/supabase/scheduled_actions/selectScheduledActions", () => ({ selectScheduledActions: vi.fn(), @@ -13,12 +19,6 @@ vi.mock("@/lib/trigger/deleteSchedule", () => ({ deleteSchedule: vi.fn(), })); -// Import after mocks -import { deleteTask } from "../deleteTask"; -import { selectScheduledActions } from "@/lib/supabase/scheduled_actions/selectScheduledActions"; -import { deleteScheduledAction } from "@/lib/supabase/scheduled_actions/deleteScheduledAction"; -import { deleteSchedule } from "@/lib/trigger/deleteSchedule"; - const mockSelectScheduledActions = vi.mocked(selectScheduledActions); const mockDeleteScheduledAction = vi.mocked(deleteScheduledAction); const mockDeleteSchedule = vi.mocked(deleteSchedule); @@ -129,13 +129,13 @@ describe("deleteTask", () => { // Track when each operation starts and completes mockDeleteSchedule.mockImplementation(async () => { executionOrder.push("deleteSchedule:start"); - await new Promise((resolve) => setTimeout(resolve, 10)); + await new Promise(resolve => setTimeout(resolve, 10)); executionOrder.push("deleteSchedule:end"); }); mockDeleteScheduledAction.mockImplementation(async () => { executionOrder.push("deleteScheduledAction:start"); - await new Promise((resolve) => setTimeout(resolve, 10)); + await new Promise(resolve => setTimeout(resolve, 10)); executionOrder.push("deleteScheduledAction:end"); }); diff --git a/lib/tasks/__tests__/getTaskRunHandler.test.ts b/lib/tasks/__tests__/getTaskRunHandler.test.ts index bce2ce57d..6f764de64 100644 --- a/lib/tasks/__tests__/getTaskRunHandler.test.ts +++ b/lib/tasks/__tests__/getTaskRunHandler.test.ts @@ -23,6 +23,9 @@ vi.mock("@/lib/networking/getCorsHeaders", () => ({ getCorsHeaders: vi.fn(() => ({ "Access-Control-Allow-Origin": "*" })), })); +/** + * + */ function createMockRequest(): NextRequest { return { url: "http://localhost:3000/api/tasks/runs", @@ -94,7 +97,11 @@ describe("getTaskRunHandler", () => { describe("list mode", () => { it("returns empty runs array", async () => { - vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ mode: "list", accountId: "acc_123", limit: 20 }); + vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ + mode: "list", + accountId: "acc_123", + limit: 20, + }); vi.mocked(listTaskRuns).mockResolvedValue([]); const response = await getTaskRunHandler(createMockRequest()); @@ -105,7 +112,11 @@ describe("getTaskRunHandler", () => { }); it("returns populated runs array", async () => { - vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ mode: "list", accountId: "acc_123", limit: 20 }); + vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ + mode: "list", + accountId: "acc_123", + limit: 20, + }); vi.mocked(listTaskRuns).mockResolvedValue([mockRun]); const response = await getTaskRunHandler(createMockRequest()); @@ -116,7 +127,11 @@ describe("getTaskRunHandler", () => { }); it("calls listTaskRuns with accountId and limit", async () => { - vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ mode: "list", accountId: "acc_456", limit: 50 }); + vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ + mode: "list", + accountId: "acc_456", + limit: 50, + }); vi.mocked(listTaskRuns).mockResolvedValue([]); await getTaskRunHandler(createMockRequest()); @@ -125,7 +140,11 @@ describe("getTaskRunHandler", () => { }); it("returns 500 when listTaskRuns throws", async () => { - vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ mode: "list", accountId: "acc_123", limit: 20 }); + vi.mocked(validateGetTaskRunQuery).mockResolvedValue({ + mode: "list", + accountId: "acc_123", + limit: 20, + }); vi.mocked(listTaskRuns).mockRejectedValue(new Error("API error")); const response = await getTaskRunHandler(createMockRequest()); diff --git a/lib/tasks/__tests__/validateGetTaskRunQuery.test.ts b/lib/tasks/__tests__/validateGetTaskRunQuery.test.ts index 132e6afcd..5e4f72d43 100644 --- a/lib/tasks/__tests__/validateGetTaskRunQuery.test.ts +++ b/lib/tasks/__tests__/validateGetTaskRunQuery.test.ts @@ -14,6 +14,8 @@ vi.mock("@/lib/auth/validateAuthContext", () => ({ /** * Creates a mock NextRequest with the given URL. + * + * @param url */ function createMockRequest(url: string): NextRequest { return { diff --git a/lib/tasks/validateGetTaskRunQuery.ts b/lib/tasks/validateGetTaskRunQuery.ts index b83f4a165..ca59abf0f 100644 --- a/lib/tasks/validateGetTaskRunQuery.ts +++ b/lib/tasks/validateGetTaskRunQuery.ts @@ -10,12 +10,7 @@ const getTaskRunQuerySchema = z.object({ .min(1) .transform(val => val.trim()) .optional(), - limit: z.coerce - .number() - .int() - .min(1) - .max(100) - .default(20), + limit: z.coerce.number().int().min(1).max(100).default(20), }); export type ValidatedRetrieveQuery = { mode: "retrieve"; runId: string }; diff --git a/lib/telegram/sendErrorNotification.ts b/lib/telegram/sendErrorNotification.ts index ad9fe2e50..1e6404e79 100644 --- a/lib/telegram/sendErrorNotification.ts +++ b/lib/telegram/sendErrorNotification.ts @@ -18,12 +18,7 @@ export interface ErrorContext { */ function formatErrorMessage(context: ErrorContext): string { const { path, error, roomId, email } = context; - const lines = [ - `*Error in ${path}*`, - "", - `*Error:* ${error.name}`, - `*Message:* ${error.message}`, - ]; + const lines = [`*Error in ${path}*`, "", `*Error:* ${error.name}`, `*Message:* ${error.message}`]; if (roomId) { lines.push(`*Room ID:* ${roomId}`); diff --git a/lib/transcribe/formatTranscriptMd.ts b/lib/transcribe/formatTranscriptMd.ts index dc052de1b..77a5b7275 100644 --- a/lib/transcribe/formatTranscriptMd.ts +++ b/lib/transcribe/formatTranscriptMd.ts @@ -33,4 +33,3 @@ export function formatTranscriptMd( return md; } - diff --git a/lib/transcribe/index.ts b/lib/transcribe/index.ts index 38430b562..df8cd3734 100644 --- a/lib/transcribe/index.ts +++ b/lib/transcribe/index.ts @@ -11,4 +11,3 @@ export { saveAudioToFiles } from "./saveAudioToFiles"; export { saveTranscriptToFiles } from "./saveTranscriptToFiles"; export { processAudioTranscription } from "./processAudioTranscription"; export * from "./types"; - diff --git a/lib/transcribe/processAudioTranscription.ts b/lib/transcribe/processAudioTranscription.ts index 5663be021..0e05905a7 100644 --- a/lib/transcribe/processAudioTranscription.ts +++ b/lib/transcribe/processAudioTranscription.ts @@ -7,6 +7,8 @@ import { ProcessTranscriptionParams, ProcessTranscriptionResult } from "./types" /** * Fetches audio from URL, transcribes it with OpenAI Whisper, and saves both * the original audio and transcript markdown to the customer's files. + * + * @param params */ export async function processAudioTranscription( params: ProcessTranscriptionParams, @@ -64,10 +66,13 @@ export async function processAudioTranscription( }; } +/** + * + * @param contentType + */ function getExtensionFromContentType(contentType: string): string { if (contentType.includes("wav")) return "wav"; if (contentType.includes("m4a") || contentType.includes("mp4")) return "m4a"; if (contentType.includes("webm")) return "webm"; return "mp3"; } - diff --git a/lib/transcribe/saveAudioToFiles.ts b/lib/transcribe/saveAudioToFiles.ts index 4c082e616..2124e5121 100644 --- a/lib/transcribe/saveAudioToFiles.ts +++ b/lib/transcribe/saveAudioToFiles.ts @@ -2,9 +2,19 @@ import { uploadFileByKey } from "@/lib/supabase/storage/uploadFileByKey"; import { createFileRecord } from "@/lib/supabase/files/createFileRecord"; import { SaveAudioParams, FileRecord } from "./types"; +/** + * + * @param params + */ export async function saveAudioToFiles(params: SaveAudioParams): Promise { - const { audioBlob, contentType, fileName, ownerAccountId, artistAccountId, title = "Audio" } = - params; + const { + audioBlob, + contentType, + fileName, + ownerAccountId, + artistAccountId, + title = "Audio", + } = params; const safeFileName = fileName.replace(/[^a-zA-Z0-9._-]/g, "_"); const storageKey = `files/${ownerAccountId}/${artistAccountId}/${safeFileName}`; diff --git a/lib/transcribe/saveTranscriptToFiles.ts b/lib/transcribe/saveTranscriptToFiles.ts index 627feb6dc..fa7518c5d 100644 --- a/lib/transcribe/saveTranscriptToFiles.ts +++ b/lib/transcribe/saveTranscriptToFiles.ts @@ -2,6 +2,10 @@ import { uploadFileByKey } from "@/lib/supabase/storage/uploadFileByKey"; import { createFileRecord } from "@/lib/supabase/files/createFileRecord"; import { SaveTranscriptParams, FileRecord } from "./types"; +/** + * + * @param params + */ export async function saveTranscriptToFiles(params: SaveTranscriptParams): Promise { const { markdown, ownerAccountId, artistAccountId, title = "Transcription" } = params; diff --git a/lib/transcribe/transcribeAudio.ts b/lib/transcribe/transcribeAudio.ts index 2dcf31b6b..429eee42e 100644 --- a/lib/transcribe/transcribeAudio.ts +++ b/lib/transcribe/transcribeAudio.ts @@ -56,7 +56,7 @@ export async function transcribeAudio( const data: WhisperVerboseResponse = await response.json(); // Map OpenAI segments to our chunk format - const chunks = data.segments?.map((seg) => ({ + const chunks = data.segments?.map(seg => ({ timestamp: [seg.start, seg.end] as [number, number], text: seg.text, })); @@ -67,4 +67,3 @@ export async function transcribeAudio( language: data.language, }; } - diff --git a/lib/transcribe/types.ts b/lib/transcribe/types.ts index 68b134f28..916e699cd 100644 --- a/lib/transcribe/types.ts +++ b/lib/transcribe/types.ts @@ -56,6 +56,8 @@ export interface ProcessTranscriptionResult { /** * Formats transcription errors into user-friendly messages. * Centralizes error message logic to avoid duplication. + * + * @param error */ export function formatTranscriptionError(error: unknown): { message: string; status: number } { const rawMessage = error instanceof Error ? error.message : "Transcription failed"; @@ -64,7 +66,10 @@ export function formatTranscriptionError(error: unknown): { message: string; sta return { message: "OpenAI API key is not configured", status: 500 }; } if (rawMessage.includes("fetch audio") || rawMessage.includes("Failed to fetch")) { - return { message: "Could not fetch the audio file. Please check the URL is accessible.", status: 400 }; + return { + message: "Could not fetch the audio file. Please check the URL is accessible.", + status: 400, + }; } if (rawMessage.includes("25 MB") || rawMessage.includes("file size")) { return { message: "Audio file exceeds the 25MB limit", status: 413 }; @@ -75,4 +80,3 @@ export function formatTranscriptionError(error: unknown): { message: string; sta return { message: rawMessage, status: 500 }; } - diff --git a/lib/trigger/triggerCreateContent.ts b/lib/trigger/triggerCreateContent.ts index 86dab6c81..e87325399 100644 --- a/lib/trigger/triggerCreateContent.ts +++ b/lib/trigger/triggerCreateContent.ts @@ -16,9 +16,10 @@ export interface TriggerCreateContentPayload { /** * Triggers the create-content task in Trigger.dev. + * + * @param payload */ export async function triggerCreateContent(payload: TriggerCreateContentPayload) { const handle = await tasks.trigger(CREATE_CONTENT_TASK_ID, payload); return handle; } - diff --git a/lib/workspaces/createWorkspacePostHandler.ts b/lib/workspaces/createWorkspacePostHandler.ts index 8acf48948..0a7c7ac6e 100644 --- a/lib/workspaces/createWorkspacePostHandler.ts +++ b/lib/workspaces/createWorkspacePostHandler.ts @@ -20,9 +20,7 @@ import { createWorkspaceInDb } from "@/lib/workspaces/createWorkspaceInDb"; * @param request - The request object containing JSON body * @returns A NextResponse with workspace data or error */ -export async function createWorkspacePostHandler( - request: NextRequest, -): Promise { +export async function createWorkspacePostHandler(request: NextRequest): Promise { const validated = await validateCreateWorkspaceBody(request); if (validated instanceof NextResponse) { return validated; @@ -42,10 +40,7 @@ export async function createWorkspacePostHandler( ); } - return NextResponse.json( - { workspace }, - { status: 201, headers: getCorsHeaders() }, - ); + return NextResponse.json({ workspace }, { status: 201, headers: getCorsHeaders() }); } catch (error) { const message = error instanceof Error ? error.message : "Failed to create workspace"; return NextResponse.json( diff --git a/lib/youtube/fetchYouTubeChannelInfo.ts b/lib/youtube/fetchYouTubeChannelInfo.ts index 2ffd976e5..151555121 100644 --- a/lib/youtube/fetchYouTubeChannelInfo.ts +++ b/lib/youtube/fetchYouTubeChannelInfo.ts @@ -148,4 +148,3 @@ export async function fetchYouTubeChannelInfo({ }; } } - diff --git a/lib/youtube/getDefaultDateRange.ts b/lib/youtube/getDefaultDateRange.ts index 4e6e92bde..d2f54954b 100644 --- a/lib/youtube/getDefaultDateRange.ts +++ b/lib/youtube/getDefaultDateRange.ts @@ -14,4 +14,3 @@ export function getDefaultDateRange(): { startDate: string; endDate: string } { endDate: endDate.toISOString().split("T")[0], }; } - diff --git a/lib/youtube/isTokenExpired.ts b/lib/youtube/isTokenExpired.ts index 81a044a6c..d28629132 100644 --- a/lib/youtube/isTokenExpired.ts +++ b/lib/youtube/isTokenExpired.ts @@ -10,4 +10,3 @@ export function isTokenExpired(expiresAt: string): boolean { const oneMinuteInMs = 60 * 1000; return expirationTime <= now + oneMinuteInMs; } - diff --git a/next.config.ts b/next.config.ts index 6880abd5a..7160da7fc 100644 --- a/next.config.ts +++ b/next.config.ts @@ -5,12 +5,7 @@ const nextConfig: NextConfig = { RESOURCE_WALLET_ADDRESS: process.env.RESOURCE_WALLET_ADDRESS, }, experimental: { - optimizePackageImports: [ - 'date-fns', - '@ai-sdk/anthropic', - '@ai-sdk/openai', - '@ai-sdk/google', - ], + optimizePackageImports: ["date-fns", "@ai-sdk/anthropic", "@ai-sdk/openai", "@ai-sdk/google"], }, async headers() { return [ @@ -19,7 +14,10 @@ const nextConfig: NextConfig = { headers: [ { key: "Access-Control-Allow-Origin", value: "*" }, { key: "Access-Control-Allow-Methods", value: "GET, POST, PUT, DELETE, OPTIONS, PATCH" }, - { key: "Access-Control-Allow-Headers", value: "Content-Type, Authorization, X-Requested-With, x-api-key" }, + { + key: "Access-Control-Allow-Headers", + value: "Content-Type, Authorization, X-Requested-With, x-api-key", + }, ], }, ]; diff --git a/types/database.types.ts b/types/database.types.ts index 27d5db1a6..50b0a8ef6 100644 --- a/types/database.types.ts +++ b/types/database.types.ts @@ -1,3869 +1,3863 @@ -export type Json = - | string - | number - | boolean - | null - | { [key: string]: Json | undefined } - | Json[] +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; export type Database = { // Allows to automatically instantiate createClient with right options // instead of createClient(URL, KEY) __InternalSupabase: { - PostgrestVersion: "12.2.3 (519615d)" - } + PostgrestVersion: "12.2.3 (519615d)"; + }; public: { Tables: { account_api_keys: { Row: { - account: string | null - created_at: string - id: string - key_hash: string | null - last_used: string | null - name: string - } - Insert: { - account?: string | null - created_at?: string - id?: string - key_hash?: string | null - last_used?: string | null - name: string - } - Update: { - account?: string | null - created_at?: string - id?: string - key_hash?: string | null - last_used?: string | null - name?: string - } + account: string | null; + created_at: string; + id: string; + key_hash: string | null; + last_used: string | null; + name: string; + }; + Insert: { + account?: string | null; + created_at?: string; + id?: string; + key_hash?: string | null; + last_used?: string | null; + name: string; + }; + Update: { + account?: string | null; + created_at?: string; + id?: string; + key_hash?: string | null; + last_used?: string | null; + name?: string; + }; Relationships: [ { - foreignKeyName: "account_api_keys_account_fkey" - columns: ["account"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_api_keys_account_fkey"; + columns: ["account"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_artist_ids: { Row: { - account_id: string | null - artist_id: string | null - id: string - pinned: boolean - updated_at: string | null - } - Insert: { - account_id?: string | null - artist_id?: string | null - id?: string - pinned?: boolean - updated_at?: string | null - } - Update: { - account_id?: string | null - artist_id?: string | null - id?: string - pinned?: boolean - updated_at?: string | null - } + account_id: string | null; + artist_id: string | null; + id: string; + pinned: boolean; + updated_at: string | null; + }; + Insert: { + account_id?: string | null; + artist_id?: string | null; + id?: string; + pinned?: boolean; + updated_at?: string | null; + }; + Update: { + account_id?: string | null; + artist_id?: string | null; + id?: string; + pinned?: boolean; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "account_artist_ids_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_artist_ids_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_artist_ids_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_artist_ids_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_catalogs: { Row: { - account: string - catalog: string - created_at: string - id: string - updated_at: string - } - Insert: { - account: string - catalog: string - created_at?: string - id?: string - updated_at?: string - } - Update: { - account?: string - catalog?: string - created_at?: string - id?: string - updated_at?: string - } + account: string; + catalog: string; + created_at: string; + id: string; + updated_at: string; + }; + Insert: { + account: string; + catalog: string; + created_at?: string; + id?: string; + updated_at?: string; + }; + Update: { + account?: string; + catalog?: string; + created_at?: string; + id?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "account_catalogs_account_fkey" - columns: ["account"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_catalogs_account_fkey"; + columns: ["account"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_catalogs_catalog_fkey" - columns: ["catalog"] - isOneToOne: false - referencedRelation: "catalogs" - referencedColumns: ["id"] + foreignKeyName: "account_catalogs_catalog_fkey"; + columns: ["catalog"]; + isOneToOne: false; + referencedRelation: "catalogs"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_emails: { Row: { - account_id: string | null - email: string | null - id: string - updated_at: string - } - Insert: { - account_id?: string | null - email?: string | null - id?: string - updated_at?: string - } - Update: { - account_id?: string | null - email?: string | null - id?: string - updated_at?: string - } + account_id: string | null; + email: string | null; + id: string; + updated_at: string; + }; + Insert: { + account_id?: string | null; + email?: string | null; + id?: string; + updated_at?: string; + }; + Update: { + account_id?: string | null; + email?: string | null; + id?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "account_emails_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_emails_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_info: { Row: { - account_id: string | null - company_name: string | null - id: string - image: string | null - instruction: string | null - job_title: string | null - knowledges: Json | null - label: string | null - organization: string | null - role_type: string | null - updated_at: string - } - Insert: { - account_id?: string | null - company_name?: string | null - id?: string - image?: string | null - instruction?: string | null - job_title?: string | null - knowledges?: Json | null - label?: string | null - organization?: string | null - role_type?: string | null - updated_at?: string - } - Update: { - account_id?: string | null - company_name?: string | null - id?: string - image?: string | null - instruction?: string | null - job_title?: string | null - knowledges?: Json | null - label?: string | null - organization?: string | null - role_type?: string | null - updated_at?: string - } + account_id: string | null; + company_name: string | null; + id: string; + image: string | null; + instruction: string | null; + job_title: string | null; + knowledges: Json | null; + label: string | null; + organization: string | null; + role_type: string | null; + updated_at: string; + }; + Insert: { + account_id?: string | null; + company_name?: string | null; + id?: string; + image?: string | null; + instruction?: string | null; + job_title?: string | null; + knowledges?: Json | null; + label?: string | null; + organization?: string | null; + role_type?: string | null; + updated_at?: string; + }; + Update: { + account_id?: string | null; + company_name?: string | null; + id?: string; + image?: string | null; + instruction?: string | null; + job_title?: string | null; + knowledges?: Json | null; + label?: string | null; + organization?: string | null; + role_type?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "account_info_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_info_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_organization_ids: { Row: { - account_id: string | null - id: string - organization_id: string | null - updated_at: string | null - } - Insert: { - account_id?: string | null - id?: string - organization_id?: string | null - updated_at?: string | null - } - Update: { - account_id?: string | null - id?: string - organization_id?: string | null - updated_at?: string | null - } + account_id: string | null; + id: string; + organization_id: string | null; + updated_at: string | null; + }; + Insert: { + account_id?: string | null; + id?: string; + organization_id?: string | null; + updated_at?: string | null; + }; + Update: { + account_id?: string | null; + id?: string; + organization_id?: string | null; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "account_organization_ids_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_organization_ids_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_organization_ids_organization_id_fkey" - columns: ["organization_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_organization_ids_organization_id_fkey"; + columns: ["organization_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_phone_numbers: { Row: { - account_id: string - id: string - phone_number: string - updated_at: string | null - } - Insert: { - account_id: string - id?: string - phone_number: string - updated_at?: string | null - } - Update: { - account_id?: string - id?: string - phone_number?: string - updated_at?: string | null - } + account_id: string; + id: string; + phone_number: string; + updated_at: string | null; + }; + Insert: { + account_id: string; + id?: string; + phone_number: string; + updated_at?: string | null; + }; + Update: { + account_id?: string; + id?: string; + phone_number?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "account_phone_numbers_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_phone_numbers_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_sandboxes: { Row: { - account_id: string - created_at: string - id: string - sandbox_id: string - } - Insert: { - account_id: string - created_at?: string - id?: string - sandbox_id: string - } - Update: { - account_id?: string - created_at?: string - id?: string - sandbox_id?: string - } + account_id: string; + created_at: string; + id: string; + sandbox_id: string; + }; + Insert: { + account_id: string; + created_at?: string; + id?: string; + sandbox_id: string; + }; + Update: { + account_id?: string; + created_at?: string; + id?: string; + sandbox_id?: string; + }; Relationships: [ { - foreignKeyName: "account_sandboxes_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_sandboxes_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_snapshots: { Row: { - account_id: string - created_at: string | null - expires_at: string - github_repo: string | null - snapshot_id: string - } - Insert: { - account_id: string - created_at?: string | null - expires_at: string - github_repo?: string | null - snapshot_id: string - } - Update: { - account_id?: string - created_at?: string | null - expires_at?: string - github_repo?: string | null - snapshot_id?: string - } + account_id: string; + created_at: string | null; + expires_at: string; + github_repo: string | null; + snapshot_id: string; + }; + Insert: { + account_id: string; + created_at?: string | null; + expires_at: string; + github_repo?: string | null; + snapshot_id: string; + }; + Update: { + account_id?: string; + created_at?: string | null; + expires_at?: string; + github_repo?: string | null; + snapshot_id?: string; + }; Relationships: [ { - foreignKeyName: "account_snapshots_account_id_fkey" - columns: ["account_id"] - isOneToOne: true - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_snapshots_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: true; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_socials: { Row: { - account_id: string | null - id: string - social_id: string - } + account_id: string | null; + id: string; + social_id: string; + }; Insert: { - account_id?: string | null - id?: string - social_id?: string - } + account_id?: string | null; + id?: string; + social_id?: string; + }; Update: { - account_id?: string | null - id?: string - social_id?: string - } + account_id?: string | null; + id?: string; + social_id?: string; + }; Relationships: [ { - foreignKeyName: "account_socials_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_socials_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_socials_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "account_socials_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_wallets: { Row: { - account_id: string - id: string - updated_at: string | null - wallet: string - } - Insert: { - account_id: string - id?: string - updated_at?: string | null - wallet: string - } - Update: { - account_id?: string - id?: string - updated_at?: string | null - wallet?: string - } + account_id: string; + id: string; + updated_at: string | null; + wallet: string; + }; + Insert: { + account_id: string; + id?: string; + updated_at?: string | null; + wallet: string; + }; + Update: { + account_id?: string; + id?: string; + updated_at?: string | null; + wallet?: string; + }; Relationships: [ { - foreignKeyName: "account_wallets_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_wallets_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; account_workspace_ids: { Row: { - account_id: string | null - id: string - updated_at: string | null - workspace_id: string | null - } - Insert: { - account_id?: string | null - id?: string - updated_at?: string | null - workspace_id?: string | null - } - Update: { - account_id?: string | null - id?: string - updated_at?: string | null - workspace_id?: string | null - } + account_id: string | null; + id: string; + updated_at: string | null; + workspace_id: string | null; + }; + Insert: { + account_id?: string | null; + id?: string; + updated_at?: string | null; + workspace_id?: string | null; + }; + Update: { + account_id?: string | null; + id?: string; + updated_at?: string | null; + workspace_id?: string | null; + }; Relationships: [ { - foreignKeyName: "account_workspace_ids_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_workspace_ids_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_workspace_ids_workspace_id_fkey" - columns: ["workspace_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_workspace_ids_workspace_id_fkey"; + columns: ["workspace_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; accounts: { Row: { - id: string - name: string | null - timestamp: number | null - } - Insert: { - id?: string - name?: string | null - timestamp?: number | null - } - Update: { - id?: string - name?: string | null - timestamp?: number | null - } - Relationships: [] - } + id: string; + name: string | null; + timestamp: number | null; + }; + Insert: { + id?: string; + name?: string | null; + timestamp?: number | null; + }; + Update: { + id?: string; + name?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; accounts_memberships: { Row: { - account_id: string - account_role: string - created_at: string - created_by: string | null - updated_at: string - updated_by: string | null - user_id: string - } - Insert: { - account_id: string - account_role: string - created_at?: string - created_by?: string | null - updated_at?: string - updated_by?: string | null - user_id: string - } - Update: { - account_id?: string - account_role?: string - created_at?: string - created_by?: string | null - updated_at?: string - updated_by?: string | null - user_id?: string - } + account_id: string; + account_role: string; + created_at: string; + created_by: string | null; + updated_at: string; + updated_by: string | null; + user_id: string; + }; + Insert: { + account_id: string; + account_role: string; + created_at?: string; + created_by?: string | null; + updated_at?: string; + updated_by?: string | null; + user_id: string; + }; + Update: { + account_id?: string; + account_role?: string; + created_at?: string; + created_by?: string | null; + updated_at?: string; + updated_by?: string | null; + user_id?: string; + }; Relationships: [ { - foreignKeyName: "accounts_memberships_account_role_fkey" - columns: ["account_role"] - isOneToOne: false - referencedRelation: "roles" - referencedColumns: ["name"] + foreignKeyName: "accounts_memberships_account_role_fkey"; + columns: ["account_role"]; + isOneToOne: false; + referencedRelation: "roles"; + referencedColumns: ["name"]; }, - ] - } + ]; + }; admin_expenses: { Row: { - amount: number - category: string - created_at: string | null - created_by: string | null - id: string - is_active: boolean | null - item_name: string - updated_at: string | null - } - Insert: { - amount?: number - category: string - created_at?: string | null - created_by?: string | null - id?: string - is_active?: boolean | null - item_name: string - updated_at?: string | null - } - Update: { - amount?: number - category?: string - created_at?: string | null - created_by?: string | null - id?: string - is_active?: boolean | null - item_name?: string - updated_at?: string | null - } - Relationships: [] - } + amount: number; + category: string; + created_at: string | null; + created_by: string | null; + id: string; + is_active: boolean | null; + item_name: string; + updated_at: string | null; + }; + Insert: { + amount?: number; + category: string; + created_at?: string | null; + created_by?: string | null; + id?: string; + is_active?: boolean | null; + item_name: string; + updated_at?: string | null; + }; + Update: { + amount?: number; + category?: string; + created_at?: string | null; + created_by?: string | null; + id?: string; + is_active?: boolean | null; + item_name?: string; + updated_at?: string | null; + }; + Relationships: []; + }; admin_user_profiles: { Row: { - company: string | null - context_notes: string | null - created_at: string | null - email: string - id: string - job_title: string | null - last_contact_date: string | null - meeting_notes: string | null - observations: string | null - opportunities: string | null - pain_points: string | null - sentiment: string | null - tags: string[] | null - updated_at: string | null - } - Insert: { - company?: string | null - context_notes?: string | null - created_at?: string | null - email: string - id?: string - job_title?: string | null - last_contact_date?: string | null - meeting_notes?: string | null - observations?: string | null - opportunities?: string | null - pain_points?: string | null - sentiment?: string | null - tags?: string[] | null - updated_at?: string | null - } - Update: { - company?: string | null - context_notes?: string | null - created_at?: string | null - email?: string - id?: string - job_title?: string | null - last_contact_date?: string | null - meeting_notes?: string | null - observations?: string | null - opportunities?: string | null - pain_points?: string | null - sentiment?: string | null - tags?: string[] | null - updated_at?: string | null - } - Relationships: [] - } + company: string | null; + context_notes: string | null; + created_at: string | null; + email: string; + id: string; + job_title: string | null; + last_contact_date: string | null; + meeting_notes: string | null; + observations: string | null; + opportunities: string | null; + pain_points: string | null; + sentiment: string | null; + tags: string[] | null; + updated_at: string | null; + }; + Insert: { + company?: string | null; + context_notes?: string | null; + created_at?: string | null; + email: string; + id?: string; + job_title?: string | null; + last_contact_date?: string | null; + meeting_notes?: string | null; + observations?: string | null; + opportunities?: string | null; + pain_points?: string | null; + sentiment?: string | null; + tags?: string[] | null; + updated_at?: string | null; + }; + Update: { + company?: string | null; + context_notes?: string | null; + created_at?: string | null; + email?: string; + id?: string; + job_title?: string | null; + last_contact_date?: string | null; + meeting_notes?: string | null; + observations?: string | null; + opportunities?: string | null; + pain_points?: string | null; + sentiment?: string | null; + tags?: string[] | null; + updated_at?: string | null; + }; + Relationships: []; + }; agent_status: { Row: { - agent_id: string - id: string - progress: number | null - social_id: string - status: number | null - updated_at: string - } - Insert: { - agent_id?: string - id?: string - progress?: number | null - social_id: string - status?: number | null - updated_at?: string - } - Update: { - agent_id?: string - id?: string - progress?: number | null - social_id?: string - status?: number | null - updated_at?: string - } + agent_id: string; + id: string; + progress: number | null; + social_id: string; + status: number | null; + updated_at: string; + }; + Insert: { + agent_id?: string; + id?: string; + progress?: number | null; + social_id: string; + status?: number | null; + updated_at?: string; + }; + Update: { + agent_id?: string; + id?: string; + progress?: number | null; + social_id?: string; + status?: number | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "agent_status_agent_id_fkey" - columns: ["agent_id"] - isOneToOne: false - referencedRelation: "agents" - referencedColumns: ["id"] + foreignKeyName: "agent_status_agent_id_fkey"; + columns: ["agent_id"]; + isOneToOne: false; + referencedRelation: "agents"; + referencedColumns: ["id"]; }, { - foreignKeyName: "agent_status_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "agent_status_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; agent_template_favorites: { Row: { - created_at: string | null - template_id: string - user_id: string - } + created_at: string | null; + template_id: string; + user_id: string; + }; Insert: { - created_at?: string | null - template_id: string - user_id: string - } + created_at?: string | null; + template_id: string; + user_id: string; + }; Update: { - created_at?: string | null - template_id?: string - user_id?: string - } + created_at?: string | null; + template_id?: string; + user_id?: string; + }; Relationships: [ { - foreignKeyName: "agent_template_favorites_template_id_fkey" - columns: ["template_id"] - isOneToOne: false - referencedRelation: "agent_templates" - referencedColumns: ["id"] + foreignKeyName: "agent_template_favorites_template_id_fkey"; + columns: ["template_id"]; + isOneToOne: false; + referencedRelation: "agent_templates"; + referencedColumns: ["id"]; }, { - foreignKeyName: "agent_template_favorites_user_id_fkey" - columns: ["user_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "agent_template_favorites_user_id_fkey"; + columns: ["user_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; agent_template_shares: { Row: { - created_at: string | null - template_id: string - user_id: string - } + created_at: string | null; + template_id: string; + user_id: string; + }; Insert: { - created_at?: string | null - template_id: string - user_id: string - } + created_at?: string | null; + template_id: string; + user_id: string; + }; Update: { - created_at?: string | null - template_id?: string - user_id?: string - } + created_at?: string | null; + template_id?: string; + user_id?: string; + }; Relationships: [ { - foreignKeyName: "agent_template_shares_template_id_fkey" - columns: ["template_id"] - isOneToOne: false - referencedRelation: "agent_templates" - referencedColumns: ["id"] + foreignKeyName: "agent_template_shares_template_id_fkey"; + columns: ["template_id"]; + isOneToOne: false; + referencedRelation: "agent_templates"; + referencedColumns: ["id"]; }, { - foreignKeyName: "agent_template_shares_user_id_fkey" - columns: ["user_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "agent_template_shares_user_id_fkey"; + columns: ["user_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; agent_templates: { Row: { - created_at: string - creator: string | null - description: string - favorites_count: number - id: string - is_private: boolean - prompt: string - tags: string[] - title: string - updated_at: string | null - } - Insert: { - created_at?: string - creator?: string | null - description: string - favorites_count?: number - id?: string - is_private?: boolean - prompt: string - tags?: string[] - title: string - updated_at?: string | null - } - Update: { - created_at?: string - creator?: string | null - description?: string - favorites_count?: number - id?: string - is_private?: boolean - prompt?: string - tags?: string[] - title?: string - updated_at?: string | null - } + created_at: string; + creator: string | null; + description: string; + favorites_count: number; + id: string; + is_private: boolean; + prompt: string; + tags: string[]; + title: string; + updated_at: string | null; + }; + Insert: { + created_at?: string; + creator?: string | null; + description: string; + favorites_count?: number; + id?: string; + is_private?: boolean; + prompt: string; + tags?: string[]; + title: string; + updated_at?: string | null; + }; + Update: { + created_at?: string; + creator?: string | null; + description?: string; + favorites_count?: number; + id?: string; + is_private?: boolean; + prompt?: string; + tags?: string[]; + title?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "agent_templates_creator_fkey" - columns: ["creator"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "agent_templates_creator_fkey"; + columns: ["creator"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; agents: { Row: { - id: string - updated_at: string - } + id: string; + updated_at: string; + }; Insert: { - id?: string - updated_at?: string - } + id?: string; + updated_at?: string; + }; Update: { - id?: string - updated_at?: string - } - Relationships: [] - } + id?: string; + updated_at?: string; + }; + Relationships: []; + }; app_store_link_clicked: { Row: { - clientId: string | null - id: string | null - timestamp: number | null - } - Insert: { - clientId?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - clientId?: string | null - id?: string | null - timestamp?: number | null - } - Relationships: [] - } + clientId: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + clientId?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + clientId?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; apple_login_button_clicked: { Row: { - campaignId: string | null - clientId: string | null - fanId: string | null - game: string | null - id: string | null - timestamp: number | null - } - Insert: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: number | null - } + campaignId: string | null; + clientId: string | null; + fanId: string | null; + game: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; Relationships: [ { - foreignKeyName: "apple_login_button_clicked_campaignId_fkey" - columns: ["campaignId"] - isOneToOne: false - referencedRelation: "campaigns" - referencedColumns: ["id"] + foreignKeyName: "apple_login_button_clicked_campaignId_fkey"; + columns: ["campaignId"]; + isOneToOne: false; + referencedRelation: "campaigns"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; apple_music: { Row: { - fanId: string | null - game: string | null - id: string | null - syncid: string | null - syncId: string | null - timestamp: number | null - } - Insert: { - fanId?: string | null - game?: string | null - id?: string | null - syncid?: string | null - syncId?: string | null - timestamp?: number | null - } - Update: { - fanId?: string | null - game?: string | null - id?: string | null - syncid?: string | null - syncId?: string | null - timestamp?: number | null - } - Relationships: [] - } + fanId: string | null; + game: string | null; + id: string | null; + syncid: string | null; + syncId: string | null; + timestamp: number | null; + }; + Insert: { + fanId?: string | null; + game?: string | null; + id?: string | null; + syncid?: string | null; + syncId?: string | null; + timestamp?: number | null; + }; + Update: { + fanId?: string | null; + game?: string | null; + id?: string | null; + syncid?: string | null; + syncId?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; apple_play_button_clicked: { Row: { - appleId: string | null - campaignId: string | null - clientId: string | null - fanId: string | null - game: string | null - id: string - timestamp: number | null - } - Insert: { - appleId?: string | null - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string - timestamp?: number | null - } - Update: { - appleId?: string | null - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string - timestamp?: number | null - } + appleId: string | null; + campaignId: string | null; + clientId: string | null; + fanId: string | null; + game: string | null; + id: string; + timestamp: number | null; + }; + Insert: { + appleId?: string | null; + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string; + timestamp?: number | null; + }; + Update: { + appleId?: string | null; + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string; + timestamp?: number | null; + }; Relationships: [ { - foreignKeyName: "apple_play_button_clicked_campaignId_fkey" - columns: ["campaignId"] - isOneToOne: false - referencedRelation: "campaigns" - referencedColumns: ["id"] + foreignKeyName: "apple_play_button_clicked_campaignId_fkey"; + columns: ["campaignId"]; + isOneToOne: false; + referencedRelation: "campaigns"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; artist_fan_segment: { Row: { - artist_social_id: string | null - fan_social_id: string | null - id: string - segment_name: string | null - updated_at: string - } - Insert: { - artist_social_id?: string | null - fan_social_id?: string | null - id?: string - segment_name?: string | null - updated_at?: string - } - Update: { - artist_social_id?: string | null - fan_social_id?: string | null - id?: string - segment_name?: string | null - updated_at?: string - } + artist_social_id: string | null; + fan_social_id: string | null; + id: string; + segment_name: string | null; + updated_at: string; + }; + Insert: { + artist_social_id?: string | null; + fan_social_id?: string | null; + id?: string; + segment_name?: string | null; + updated_at?: string; + }; + Update: { + artist_social_id?: string | null; + fan_social_id?: string | null; + id?: string; + segment_name?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "artist_fan_segment_artist_social_id_fkey" - columns: ["artist_social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "artist_fan_segment_artist_social_id_fkey"; + columns: ["artist_social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, { - foreignKeyName: "artist_fan_segment_fan_social_id_fkey" - columns: ["fan_social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "artist_fan_segment_fan_social_id_fkey"; + columns: ["fan_social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; artist_organization_ids: { Row: { - artist_id: string - created_at: string | null - id: string - organization_id: string - updated_at: string | null - } - Insert: { - artist_id: string - created_at?: string | null - id?: string - organization_id: string - updated_at?: string | null - } - Update: { - artist_id?: string - created_at?: string | null - id?: string - organization_id?: string - updated_at?: string | null - } + artist_id: string; + created_at: string | null; + id: string; + organization_id: string; + updated_at: string | null; + }; + Insert: { + artist_id: string; + created_at?: string | null; + id?: string; + organization_id: string; + updated_at?: string | null; + }; + Update: { + artist_id?: string; + created_at?: string | null; + id?: string; + organization_id?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "artist_organization_ids_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "artist_organization_ids_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "artist_organization_ids_organization_id_fkey" - columns: ["organization_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "artist_organization_ids_organization_id_fkey"; + columns: ["organization_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; artist_segments: { Row: { - artist_account_id: string - id: string - segment_id: string - updated_at: string | null - } - Insert: { - artist_account_id: string - id?: string - segment_id: string - updated_at?: string | null - } - Update: { - artist_account_id?: string - id?: string - segment_id?: string - updated_at?: string | null - } + artist_account_id: string; + id: string; + segment_id: string; + updated_at: string | null; + }; + Insert: { + artist_account_id: string; + id?: string; + segment_id: string; + updated_at?: string | null; + }; + Update: { + artist_account_id?: string; + id?: string; + segment_id?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "artist_segments_artist_account_id_fkey" - columns: ["artist_account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "artist_segments_artist_account_id_fkey"; + columns: ["artist_account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "artist_segments_segment_id_fkey" - columns: ["segment_id"] - isOneToOne: false - referencedRelation: "segments" - referencedColumns: ["id"] + foreignKeyName: "artist_segments_segment_id_fkey"; + columns: ["segment_id"]; + isOneToOne: false; + referencedRelation: "segments"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; billing_customers: { Row: { - account_id: string - customer_id: string - email: string | null - id: number - provider: Database["public"]["Enums"]["billing_provider"] - } - Insert: { - account_id: string - customer_id: string - email?: string | null - id?: number - provider: Database["public"]["Enums"]["billing_provider"] - } - Update: { - account_id?: string - customer_id?: string - email?: string | null - id?: number - provider?: Database["public"]["Enums"]["billing_provider"] - } - Relationships: [] - } + account_id: string; + customer_id: string; + email: string | null; + id: number; + provider: Database["public"]["Enums"]["billing_provider"]; + }; + Insert: { + account_id: string; + customer_id: string; + email?: string | null; + id?: number; + provider: Database["public"]["Enums"]["billing_provider"]; + }; + Update: { + account_id?: string; + customer_id?: string; + email?: string | null; + id?: number; + provider?: Database["public"]["Enums"]["billing_provider"]; + }; + Relationships: []; + }; campaigns: { Row: { - artist_id: string | null - clientId: string | null - id: string - timestamp: number | null - } - Insert: { - artist_id?: string | null - clientId?: string | null - id?: string - timestamp?: number | null - } - Update: { - artist_id?: string | null - clientId?: string | null - id?: string - timestamp?: number | null - } + artist_id: string | null; + clientId: string | null; + id: string; + timestamp: number | null; + }; + Insert: { + artist_id?: string | null; + clientId?: string | null; + id?: string; + timestamp?: number | null; + }; + Update: { + artist_id?: string | null; + clientId?: string | null; + id?: string; + timestamp?: number | null; + }; Relationships: [ { - foreignKeyName: "campaigns_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "campaigns_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; catalog_songs: { Row: { - catalog: string - created_at: string - id: string - song: string - updated_at: string - } - Insert: { - catalog: string - created_at?: string - id?: string - song: string - updated_at?: string - } - Update: { - catalog?: string - created_at?: string - id?: string - song?: string - updated_at?: string - } + catalog: string; + created_at: string; + id: string; + song: string; + updated_at: string; + }; + Insert: { + catalog: string; + created_at?: string; + id?: string; + song: string; + updated_at?: string; + }; + Update: { + catalog?: string; + created_at?: string; + id?: string; + song?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "catalog_songs_catalog_fkey" - columns: ["catalog"] - isOneToOne: false - referencedRelation: "catalogs" - referencedColumns: ["id"] + foreignKeyName: "catalog_songs_catalog_fkey"; + columns: ["catalog"]; + isOneToOne: false; + referencedRelation: "catalogs"; + referencedColumns: ["id"]; }, { - foreignKeyName: "catalog_songs_song_fkey" - columns: ["song"] - isOneToOne: false - referencedRelation: "songs" - referencedColumns: ["isrc"] + foreignKeyName: "catalog_songs_song_fkey"; + columns: ["song"]; + isOneToOne: false; + referencedRelation: "songs"; + referencedColumns: ["isrc"]; }, - ] - } + ]; + }; catalogs: { Row: { - created_at: string - id: string - name: string - updated_at: string - } - Insert: { - created_at?: string - id?: string - name: string - updated_at?: string - } - Update: { - created_at?: string - id?: string - name?: string - updated_at?: string - } - Relationships: [] - } + created_at: string; + id: string; + name: string; + updated_at: string; + }; + Insert: { + created_at?: string; + id?: string; + name: string; + updated_at?: string; + }; + Update: { + created_at?: string; + id?: string; + name?: string; + updated_at?: string; + }; + Relationships: []; + }; config: { Row: { - billing_provider: Database["public"]["Enums"]["billing_provider"] - enable_account_billing: boolean - enable_team_account_billing: boolean - enable_team_accounts: boolean - } - Insert: { - billing_provider?: Database["public"]["Enums"]["billing_provider"] - enable_account_billing?: boolean - enable_team_account_billing?: boolean - enable_team_accounts?: boolean - } - Update: { - billing_provider?: Database["public"]["Enums"]["billing_provider"] - enable_account_billing?: boolean - enable_team_account_billing?: boolean - enable_team_accounts?: boolean - } - Relationships: [] - } + billing_provider: Database["public"]["Enums"]["billing_provider"]; + enable_account_billing: boolean; + enable_team_account_billing: boolean; + enable_team_accounts: boolean; + }; + Insert: { + billing_provider?: Database["public"]["Enums"]["billing_provider"]; + enable_account_billing?: boolean; + enable_team_account_billing?: boolean; + enable_team_accounts?: boolean; + }; + Update: { + billing_provider?: Database["public"]["Enums"]["billing_provider"]; + enable_account_billing?: boolean; + enable_team_account_billing?: boolean; + enable_team_accounts?: boolean; + }; + Relationships: []; + }; cookie_players: { Row: { - game: string | null - id: string | null - timestamp: number | null - uniquePlayerID: string | null - } - Insert: { - game?: string | null - id?: string | null - timestamp?: number | null - uniquePlayerID?: string | null - } - Update: { - game?: string | null - id?: string | null - timestamp?: number | null - uniquePlayerID?: string | null - } - Relationships: [] - } + game: string | null; + id: string | null; + timestamp: number | null; + uniquePlayerID: string | null; + }; + Insert: { + game?: string | null; + id?: string | null; + timestamp?: number | null; + uniquePlayerID?: string | null; + }; + Update: { + game?: string | null; + id?: string | null; + timestamp?: number | null; + uniquePlayerID?: string | null; + }; + Relationships: []; + }; credits_usage: { Row: { - account_id: string - id: number - remaining_credits: number - timestamp: string | null - } - Insert: { - account_id: string - id?: number - remaining_credits?: number - timestamp?: string | null - } - Update: { - account_id?: string - id?: number - remaining_credits?: number - timestamp?: string | null - } + account_id: string; + id: number; + remaining_credits: number; + timestamp: string | null; + }; + Insert: { + account_id: string; + id?: number; + remaining_credits?: number; + timestamp?: string | null; + }; + Update: { + account_id?: string; + id?: number; + remaining_credits?: number; + timestamp?: string | null; + }; Relationships: [ { - foreignKeyName: "credits_usage_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "credits_usage_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; cta_redirect: { Row: { - clientId: string - id: number - timestamp: string | null - url: string | null - } - Insert: { - clientId: string - id?: number - timestamp?: string | null - url?: string | null - } - Update: { - clientId?: string - id?: number - timestamp?: string | null - url?: string | null - } - Relationships: [] - } + clientId: string; + id: number; + timestamp: string | null; + url: string | null; + }; + Insert: { + clientId: string; + id?: number; + timestamp?: string | null; + url?: string | null; + }; + Update: { + clientId?: string; + id?: number; + timestamp?: string | null; + url?: string | null; + }; + Relationships: []; + }; error_logs: { Row: { - account_id: string | null - created_at: string - error_message: string | null - error_timestamp: string | null - error_type: string | null - id: string - last_message: string | null - raw_message: string - room_id: string | null - stack_trace: string | null - telegram_message_id: number | null - tool_name: string | null - } - Insert: { - account_id?: string | null - created_at?: string - error_message?: string | null - error_timestamp?: string | null - error_type?: string | null - id?: string - last_message?: string | null - raw_message: string - room_id?: string | null - stack_trace?: string | null - telegram_message_id?: number | null - tool_name?: string | null - } - Update: { - account_id?: string | null - created_at?: string - error_message?: string | null - error_timestamp?: string | null - error_type?: string | null - id?: string - last_message?: string | null - raw_message?: string - room_id?: string | null - stack_trace?: string | null - telegram_message_id?: number | null - tool_name?: string | null - } + account_id: string | null; + created_at: string; + error_message: string | null; + error_timestamp: string | null; + error_type: string | null; + id: string; + last_message: string | null; + raw_message: string; + room_id: string | null; + stack_trace: string | null; + telegram_message_id: number | null; + tool_name: string | null; + }; + Insert: { + account_id?: string | null; + created_at?: string; + error_message?: string | null; + error_timestamp?: string | null; + error_type?: string | null; + id?: string; + last_message?: string | null; + raw_message: string; + room_id?: string | null; + stack_trace?: string | null; + telegram_message_id?: number | null; + tool_name?: string | null; + }; + Update: { + account_id?: string | null; + created_at?: string; + error_message?: string | null; + error_timestamp?: string | null; + error_type?: string | null; + id?: string; + last_message?: string | null; + raw_message?: string; + room_id?: string | null; + stack_trace?: string | null; + telegram_message_id?: number | null; + tool_name?: string | null; + }; Relationships: [ { - foreignKeyName: "error_logs_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "error_logs_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "error_logs_room_id_fkey" - columns: ["room_id"] - isOneToOne: false - referencedRelation: "rooms" - referencedColumns: ["id"] + foreignKeyName: "error_logs_room_id_fkey"; + columns: ["room_id"]; + isOneToOne: false; + referencedRelation: "rooms"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; fan_segments: { Row: { - fan_social_id: string - id: string - segment_id: string - updated_at: string | null - } - Insert: { - fan_social_id: string - id?: string - segment_id: string - updated_at?: string | null - } - Update: { - fan_social_id?: string - id?: string - segment_id?: string - updated_at?: string | null - } + fan_social_id: string; + id: string; + segment_id: string; + updated_at: string | null; + }; + Insert: { + fan_social_id: string; + id?: string; + segment_id: string; + updated_at?: string | null; + }; + Update: { + fan_social_id?: string; + id?: string; + segment_id?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "fan_segments_fan_social_id_fkey" - columns: ["fan_social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "fan_segments_fan_social_id_fkey"; + columns: ["fan_social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, { - foreignKeyName: "fan_segments_segment_id_fkey" - columns: ["segment_id"] - isOneToOne: false - referencedRelation: "segments" - referencedColumns: ["id"] + foreignKeyName: "fan_segments_segment_id_fkey"; + columns: ["segment_id"]; + isOneToOne: false; + referencedRelation: "segments"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; fans: { Row: { - account_status: string | null - apple_token: string | null - campaign_id: string | null - campaign_interaction_count: number | null - campaignId: string | null - city: string | null - click_through_rate: number | null - clientId: string | null - consent_given: boolean | null - country: string | null - custom_tags: Json | null - discord_username: string | null - display_name: string | null - email: string | null - email_open_rate: number | null - engagement_level: string | null - episodes: Json | null - explicit_content_filter_enabled: boolean | null - explicit_content_filter_locked: boolean | null - "explicit_content.filter_enabled": boolean | null - "explicit_content.filter_locked": boolean | null - external_urls_spotify: string | null - "external_urls.spotify": string | null - facebook_profile_url: string | null - first_stream_date: string | null - followedArtists: Json | null - followers_total: number | null - "followers.href": string | null - "followers.total": number | null - gamification_points: number | null - genres: Json | null - heavyRotations: Json | null - href: string | null - id: string - images: Json | null - instagram_handle: string | null - last_campaign_interaction: string | null - last_login: string | null - last_purchase_date: string | null - last_stream_date: string | null - linkedin_profile_url: string | null - os_type: string | null - playlist: Json | null - preferences: Json | null - preferred_artists: Json | null - preferred_device: string | null - product: string | null - recentlyPlayed: Json | null - recommendations: Json | null - recommended_events: Json | null - reddit_username: string | null - saved_podcasts: Json | null - savedAlbums: Json | null - savedAudioBooks: Json | null - savedShows: Json | null - savedTracks: Json | null - social_shares: number | null - spotify_token: string | null - subscription_tier: string | null - testField: string | null - tiktok_handle: string | null - time_zone: string | null - timestamp: string | null - top_artists_long_term: Json | null - top_artists_medium_term: Json | null - top_tracks_long_term: Json | null - top_tracks_medium_term: Json | null - top_tracks_short_term: Json | null - topArtists: Json | null - topTracks: Json | null - total_spent: number | null - total_streams: number | null - twitter_handle: string | null - type: string | null - uri: string | null - youtube_channel_url: string | null - } - Insert: { - account_status?: string | null - apple_token?: string | null - campaign_id?: string | null - campaign_interaction_count?: number | null - campaignId?: string | null - city?: string | null - click_through_rate?: number | null - clientId?: string | null - consent_given?: boolean | null - country?: string | null - custom_tags?: Json | null - discord_username?: string | null - display_name?: string | null - email?: string | null - email_open_rate?: number | null - engagement_level?: string | null - episodes?: Json | null - explicit_content_filter_enabled?: boolean | null - explicit_content_filter_locked?: boolean | null - "explicit_content.filter_enabled"?: boolean | null - "explicit_content.filter_locked"?: boolean | null - external_urls_spotify?: string | null - "external_urls.spotify"?: string | null - facebook_profile_url?: string | null - first_stream_date?: string | null - followedArtists?: Json | null - followers_total?: number | null - "followers.href"?: string | null - "followers.total"?: number | null - gamification_points?: number | null - genres?: Json | null - heavyRotations?: Json | null - href?: string | null - id?: string - images?: Json | null - instagram_handle?: string | null - last_campaign_interaction?: string | null - last_login?: string | null - last_purchase_date?: string | null - last_stream_date?: string | null - linkedin_profile_url?: string | null - os_type?: string | null - playlist?: Json | null - preferences?: Json | null - preferred_artists?: Json | null - preferred_device?: string | null - product?: string | null - recentlyPlayed?: Json | null - recommendations?: Json | null - recommended_events?: Json | null - reddit_username?: string | null - saved_podcasts?: Json | null - savedAlbums?: Json | null - savedAudioBooks?: Json | null - savedShows?: Json | null - savedTracks?: Json | null - social_shares?: number | null - spotify_token?: string | null - subscription_tier?: string | null - testField?: string | null - tiktok_handle?: string | null - time_zone?: string | null - timestamp?: string | null - top_artists_long_term?: Json | null - top_artists_medium_term?: Json | null - top_tracks_long_term?: Json | null - top_tracks_medium_term?: Json | null - top_tracks_short_term?: Json | null - topArtists?: Json | null - topTracks?: Json | null - total_spent?: number | null - total_streams?: number | null - twitter_handle?: string | null - type?: string | null - uri?: string | null - youtube_channel_url?: string | null - } - Update: { - account_status?: string | null - apple_token?: string | null - campaign_id?: string | null - campaign_interaction_count?: number | null - campaignId?: string | null - city?: string | null - click_through_rate?: number | null - clientId?: string | null - consent_given?: boolean | null - country?: string | null - custom_tags?: Json | null - discord_username?: string | null - display_name?: string | null - email?: string | null - email_open_rate?: number | null - engagement_level?: string | null - episodes?: Json | null - explicit_content_filter_enabled?: boolean | null - explicit_content_filter_locked?: boolean | null - "explicit_content.filter_enabled"?: boolean | null - "explicit_content.filter_locked"?: boolean | null - external_urls_spotify?: string | null - "external_urls.spotify"?: string | null - facebook_profile_url?: string | null - first_stream_date?: string | null - followedArtists?: Json | null - followers_total?: number | null - "followers.href"?: string | null - "followers.total"?: number | null - gamification_points?: number | null - genres?: Json | null - heavyRotations?: Json | null - href?: string | null - id?: string - images?: Json | null - instagram_handle?: string | null - last_campaign_interaction?: string | null - last_login?: string | null - last_purchase_date?: string | null - last_stream_date?: string | null - linkedin_profile_url?: string | null - os_type?: string | null - playlist?: Json | null - preferences?: Json | null - preferred_artists?: Json | null - preferred_device?: string | null - product?: string | null - recentlyPlayed?: Json | null - recommendations?: Json | null - recommended_events?: Json | null - reddit_username?: string | null - saved_podcasts?: Json | null - savedAlbums?: Json | null - savedAudioBooks?: Json | null - savedShows?: Json | null - savedTracks?: Json | null - social_shares?: number | null - spotify_token?: string | null - subscription_tier?: string | null - testField?: string | null - tiktok_handle?: string | null - time_zone?: string | null - timestamp?: string | null - top_artists_long_term?: Json | null - top_artists_medium_term?: Json | null - top_tracks_long_term?: Json | null - top_tracks_medium_term?: Json | null - top_tracks_short_term?: Json | null - topArtists?: Json | null - topTracks?: Json | null - total_spent?: number | null - total_streams?: number | null - twitter_handle?: string | null - type?: string | null - uri?: string | null - youtube_channel_url?: string | null - } + account_status: string | null; + apple_token: string | null; + campaign_id: string | null; + campaign_interaction_count: number | null; + campaignId: string | null; + city: string | null; + click_through_rate: number | null; + clientId: string | null; + consent_given: boolean | null; + country: string | null; + custom_tags: Json | null; + discord_username: string | null; + display_name: string | null; + email: string | null; + email_open_rate: number | null; + engagement_level: string | null; + episodes: Json | null; + explicit_content_filter_enabled: boolean | null; + explicit_content_filter_locked: boolean | null; + "explicit_content.filter_enabled": boolean | null; + "explicit_content.filter_locked": boolean | null; + external_urls_spotify: string | null; + "external_urls.spotify": string | null; + facebook_profile_url: string | null; + first_stream_date: string | null; + followedArtists: Json | null; + followers_total: number | null; + "followers.href": string | null; + "followers.total": number | null; + gamification_points: number | null; + genres: Json | null; + heavyRotations: Json | null; + href: string | null; + id: string; + images: Json | null; + instagram_handle: string | null; + last_campaign_interaction: string | null; + last_login: string | null; + last_purchase_date: string | null; + last_stream_date: string | null; + linkedin_profile_url: string | null; + os_type: string | null; + playlist: Json | null; + preferences: Json | null; + preferred_artists: Json | null; + preferred_device: string | null; + product: string | null; + recentlyPlayed: Json | null; + recommendations: Json | null; + recommended_events: Json | null; + reddit_username: string | null; + saved_podcasts: Json | null; + savedAlbums: Json | null; + savedAudioBooks: Json | null; + savedShows: Json | null; + savedTracks: Json | null; + social_shares: number | null; + spotify_token: string | null; + subscription_tier: string | null; + testField: string | null; + tiktok_handle: string | null; + time_zone: string | null; + timestamp: string | null; + top_artists_long_term: Json | null; + top_artists_medium_term: Json | null; + top_tracks_long_term: Json | null; + top_tracks_medium_term: Json | null; + top_tracks_short_term: Json | null; + topArtists: Json | null; + topTracks: Json | null; + total_spent: number | null; + total_streams: number | null; + twitter_handle: string | null; + type: string | null; + uri: string | null; + youtube_channel_url: string | null; + }; + Insert: { + account_status?: string | null; + apple_token?: string | null; + campaign_id?: string | null; + campaign_interaction_count?: number | null; + campaignId?: string | null; + city?: string | null; + click_through_rate?: number | null; + clientId?: string | null; + consent_given?: boolean | null; + country?: string | null; + custom_tags?: Json | null; + discord_username?: string | null; + display_name?: string | null; + email?: string | null; + email_open_rate?: number | null; + engagement_level?: string | null; + episodes?: Json | null; + explicit_content_filter_enabled?: boolean | null; + explicit_content_filter_locked?: boolean | null; + "explicit_content.filter_enabled"?: boolean | null; + "explicit_content.filter_locked"?: boolean | null; + external_urls_spotify?: string | null; + "external_urls.spotify"?: string | null; + facebook_profile_url?: string | null; + first_stream_date?: string | null; + followedArtists?: Json | null; + followers_total?: number | null; + "followers.href"?: string | null; + "followers.total"?: number | null; + gamification_points?: number | null; + genres?: Json | null; + heavyRotations?: Json | null; + href?: string | null; + id?: string; + images?: Json | null; + instagram_handle?: string | null; + last_campaign_interaction?: string | null; + last_login?: string | null; + last_purchase_date?: string | null; + last_stream_date?: string | null; + linkedin_profile_url?: string | null; + os_type?: string | null; + playlist?: Json | null; + preferences?: Json | null; + preferred_artists?: Json | null; + preferred_device?: string | null; + product?: string | null; + recentlyPlayed?: Json | null; + recommendations?: Json | null; + recommended_events?: Json | null; + reddit_username?: string | null; + saved_podcasts?: Json | null; + savedAlbums?: Json | null; + savedAudioBooks?: Json | null; + savedShows?: Json | null; + savedTracks?: Json | null; + social_shares?: number | null; + spotify_token?: string | null; + subscription_tier?: string | null; + testField?: string | null; + tiktok_handle?: string | null; + time_zone?: string | null; + timestamp?: string | null; + top_artists_long_term?: Json | null; + top_artists_medium_term?: Json | null; + top_tracks_long_term?: Json | null; + top_tracks_medium_term?: Json | null; + top_tracks_short_term?: Json | null; + topArtists?: Json | null; + topTracks?: Json | null; + total_spent?: number | null; + total_streams?: number | null; + twitter_handle?: string | null; + type?: string | null; + uri?: string | null; + youtube_channel_url?: string | null; + }; + Update: { + account_status?: string | null; + apple_token?: string | null; + campaign_id?: string | null; + campaign_interaction_count?: number | null; + campaignId?: string | null; + city?: string | null; + click_through_rate?: number | null; + clientId?: string | null; + consent_given?: boolean | null; + country?: string | null; + custom_tags?: Json | null; + discord_username?: string | null; + display_name?: string | null; + email?: string | null; + email_open_rate?: number | null; + engagement_level?: string | null; + episodes?: Json | null; + explicit_content_filter_enabled?: boolean | null; + explicit_content_filter_locked?: boolean | null; + "explicit_content.filter_enabled"?: boolean | null; + "explicit_content.filter_locked"?: boolean | null; + external_urls_spotify?: string | null; + "external_urls.spotify"?: string | null; + facebook_profile_url?: string | null; + first_stream_date?: string | null; + followedArtists?: Json | null; + followers_total?: number | null; + "followers.href"?: string | null; + "followers.total"?: number | null; + gamification_points?: number | null; + genres?: Json | null; + heavyRotations?: Json | null; + href?: string | null; + id?: string; + images?: Json | null; + instagram_handle?: string | null; + last_campaign_interaction?: string | null; + last_login?: string | null; + last_purchase_date?: string | null; + last_stream_date?: string | null; + linkedin_profile_url?: string | null; + os_type?: string | null; + playlist?: Json | null; + preferences?: Json | null; + preferred_artists?: Json | null; + preferred_device?: string | null; + product?: string | null; + recentlyPlayed?: Json | null; + recommendations?: Json | null; + recommended_events?: Json | null; + reddit_username?: string | null; + saved_podcasts?: Json | null; + savedAlbums?: Json | null; + savedAudioBooks?: Json | null; + savedShows?: Json | null; + savedTracks?: Json | null; + social_shares?: number | null; + spotify_token?: string | null; + subscription_tier?: string | null; + testField?: string | null; + tiktok_handle?: string | null; + time_zone?: string | null; + timestamp?: string | null; + top_artists_long_term?: Json | null; + top_artists_medium_term?: Json | null; + top_tracks_long_term?: Json | null; + top_tracks_medium_term?: Json | null; + top_tracks_short_term?: Json | null; + topArtists?: Json | null; + topTracks?: Json | null; + total_spent?: number | null; + total_streams?: number | null; + twitter_handle?: string | null; + type?: string | null; + uri?: string | null; + youtube_channel_url?: string | null; + }; Relationships: [ { - foreignKeyName: "fans_campaignId_fkey" - columns: ["campaignId"] - isOneToOne: false - referencedRelation: "campaigns" - referencedColumns: ["id"] + foreignKeyName: "fans_campaignId_fkey"; + columns: ["campaignId"]; + isOneToOne: false; + referencedRelation: "campaigns"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; files: { Row: { - artist_account_id: string - created_at: string - description: string | null - file_name: string - id: string - is_directory: boolean - mime_type: string | null - owner_account_id: string - size_bytes: number | null - storage_key: string - tags: string[] | null - updated_at: string - } - Insert: { - artist_account_id: string - created_at?: string - description?: string | null - file_name: string - id?: string - is_directory?: boolean - mime_type?: string | null - owner_account_id: string - size_bytes?: number | null - storage_key: string - tags?: string[] | null - updated_at?: string - } - Update: { - artist_account_id?: string - created_at?: string - description?: string | null - file_name?: string - id?: string - is_directory?: boolean - mime_type?: string | null - owner_account_id?: string - size_bytes?: number | null - storage_key?: string - tags?: string[] | null - updated_at?: string - } + artist_account_id: string; + created_at: string; + description: string | null; + file_name: string; + id: string; + is_directory: boolean; + mime_type: string | null; + owner_account_id: string; + size_bytes: number | null; + storage_key: string; + tags: string[] | null; + updated_at: string; + }; + Insert: { + artist_account_id: string; + created_at?: string; + description?: string | null; + file_name: string; + id?: string; + is_directory?: boolean; + mime_type?: string | null; + owner_account_id: string; + size_bytes?: number | null; + storage_key: string; + tags?: string[] | null; + updated_at?: string; + }; + Update: { + artist_account_id?: string; + created_at?: string; + description?: string | null; + file_name?: string; + id?: string; + is_directory?: boolean; + mime_type?: string | null; + owner_account_id?: string; + size_bytes?: number | null; + storage_key?: string; + tags?: string[] | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "files_artist_account_id_fkey" - columns: ["artist_account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "files_artist_account_id_fkey"; + columns: ["artist_account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "files_owner_account_id_fkey" - columns: ["owner_account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "files_owner_account_id_fkey"; + columns: ["owner_account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; follows: { Row: { - game: string | null - id: string | null - timestamp: number | null - } - Insert: { - game?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - game?: string | null - id?: string | null - timestamp?: number | null - } - Relationships: [] - } + game: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; founder_dashboard_chart_annotations: { Row: { - chart_type: string | null - created_at: string | null - event_date: string - event_description: string | null - id: string - } - Insert: { - chart_type?: string | null - created_at?: string | null - event_date: string - event_description?: string | null - id?: string - } - Update: { - chart_type?: string | null - created_at?: string | null - event_date?: string - event_description?: string | null - id?: string - } - Relationships: [] - } + chart_type: string | null; + created_at: string | null; + event_date: string; + event_description: string | null; + id: string; + }; + Insert: { + chart_type?: string | null; + created_at?: string | null; + event_date: string; + event_description?: string | null; + id?: string; + }; + Update: { + chart_type?: string | null; + created_at?: string | null; + event_date?: string; + event_description?: string | null; + id?: string; + }; + Relationships: []; + }; funnel_analytics: { Row: { - artist_id: string | null - handle: string | null - id: string - pilot_id: string | null - status: number | null - type: Database["public"]["Enums"]["social_type"] | null - updated_at: string - } - Insert: { - artist_id?: string | null - handle?: string | null - id?: string - pilot_id?: string | null - status?: number | null - type?: Database["public"]["Enums"]["social_type"] | null - updated_at?: string - } - Update: { - artist_id?: string | null - handle?: string | null - id?: string - pilot_id?: string | null - status?: number | null - type?: Database["public"]["Enums"]["social_type"] | null - updated_at?: string - } + artist_id: string | null; + handle: string | null; + id: string; + pilot_id: string | null; + status: number | null; + type: Database["public"]["Enums"]["social_type"] | null; + updated_at: string; + }; + Insert: { + artist_id?: string | null; + handle?: string | null; + id?: string; + pilot_id?: string | null; + status?: number | null; + type?: Database["public"]["Enums"]["social_type"] | null; + updated_at?: string; + }; + Update: { + artist_id?: string | null; + handle?: string | null; + id?: string; + pilot_id?: string | null; + status?: number | null; + type?: Database["public"]["Enums"]["social_type"] | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "funnel_analytics_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "funnel_analytics_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; funnel_analytics_accounts: { Row: { - account_id: string | null - analysis_id: string | null - created_at: string - id: string - updated_at: string | null - } - Insert: { - account_id?: string | null - analysis_id?: string | null - created_at?: string - id?: string - updated_at?: string | null - } - Update: { - account_id?: string | null - analysis_id?: string | null - created_at?: string - id?: string - updated_at?: string | null - } + account_id: string | null; + analysis_id: string | null; + created_at: string; + id: string; + updated_at: string | null; + }; + Insert: { + account_id?: string | null; + analysis_id?: string | null; + created_at?: string; + id?: string; + updated_at?: string | null; + }; + Update: { + account_id?: string | null; + analysis_id?: string | null; + created_at?: string; + id?: string; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "account_funnel_analytics_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "account_funnel_analytics_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "account_funnel_analytics_analysis_id_fkey" - columns: ["analysis_id"] - isOneToOne: false - referencedRelation: "funnel_analytics" - referencedColumns: ["id"] + foreignKeyName: "account_funnel_analytics_analysis_id_fkey"; + columns: ["analysis_id"]; + isOneToOne: false; + referencedRelation: "funnel_analytics"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; funnel_analytics_segments: { Row: { - analysis_id: string | null - created_at: string - icon: string | null - id: string - name: string | null - size: number | null - } - Insert: { - analysis_id?: string | null - created_at?: string - icon?: string | null - id?: string - name?: string | null - size?: number | null - } - Update: { - analysis_id?: string | null - created_at?: string - icon?: string | null - id?: string - name?: string | null - size?: number | null - } + analysis_id: string | null; + created_at: string; + icon: string | null; + id: string; + name: string | null; + size: number | null; + }; + Insert: { + analysis_id?: string | null; + created_at?: string; + icon?: string | null; + id?: string; + name?: string | null; + size?: number | null; + }; + Update: { + analysis_id?: string | null; + created_at?: string; + icon?: string | null; + id?: string; + name?: string | null; + size?: number | null; + }; Relationships: [ { - foreignKeyName: "funnel_analytics_segments_analysis_id_fkey" - columns: ["analysis_id"] - isOneToOne: false - referencedRelation: "funnel_analytics" - referencedColumns: ["id"] + foreignKeyName: "funnel_analytics_segments_analysis_id_fkey"; + columns: ["analysis_id"]; + isOneToOne: false; + referencedRelation: "funnel_analytics"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; funnel_reports: { Row: { - id: string - next_steps: string | null - report: string | null - stack_unique_id: string | null - timestamp: string - type: Database["public"]["Enums"]["social_type"] | null - } - Insert: { - id?: string - next_steps?: string | null - report?: string | null - stack_unique_id?: string | null - timestamp?: string - type?: Database["public"]["Enums"]["social_type"] | null - } - Update: { - id?: string - next_steps?: string | null - report?: string | null - stack_unique_id?: string | null - timestamp?: string - type?: Database["public"]["Enums"]["social_type"] | null - } - Relationships: [] - } + id: string; + next_steps: string | null; + report: string | null; + stack_unique_id: string | null; + timestamp: string; + type: Database["public"]["Enums"]["social_type"] | null; + }; + Insert: { + id?: string; + next_steps?: string | null; + report?: string | null; + stack_unique_id?: string | null; + timestamp?: string; + type?: Database["public"]["Enums"]["social_type"] | null; + }; + Update: { + id?: string; + next_steps?: string | null; + report?: string | null; + stack_unique_id?: string | null; + timestamp?: string; + type?: Database["public"]["Enums"]["social_type"] | null; + }; + Relationships: []; + }; game_start: { Row: { - clientId: string | null - fanId: Json | null - game: string | null - id: string | null - timestamp: number | null - } - Insert: { - clientId?: string | null - fanId?: Json | null - game?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - clientId?: string | null - fanId?: Json | null - game?: string | null - id?: string | null - timestamp?: number | null - } - Relationships: [] - } + clientId: string | null; + fanId: Json | null; + game: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + clientId?: string | null; + fanId?: Json | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + clientId?: string | null; + fanId?: Json | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; invitations: { Row: { - account_id: string - created_at: string - email: string - expires_at: string - id: number - invite_token: string - invited_by: string - role: string - updated_at: string - } - Insert: { - account_id: string - created_at?: string - email: string - expires_at?: string - id?: number - invite_token: string - invited_by: string - role: string - updated_at?: string - } - Update: { - account_id?: string - created_at?: string - email?: string - expires_at?: string - id?: number - invite_token?: string - invited_by?: string - role?: string - updated_at?: string - } + account_id: string; + created_at: string; + email: string; + expires_at: string; + id: number; + invite_token: string; + invited_by: string; + role: string; + updated_at: string; + }; + Insert: { + account_id: string; + created_at?: string; + email: string; + expires_at?: string; + id?: number; + invite_token: string; + invited_by: string; + role: string; + updated_at?: string; + }; + Update: { + account_id?: string; + created_at?: string; + email?: string; + expires_at?: string; + id?: number; + invite_token?: string; + invited_by?: string; + role?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "invitations_role_fkey" - columns: ["role"] - isOneToOne: false - referencedRelation: "roles" - referencedColumns: ["name"] + foreignKeyName: "invitations_role_fkey"; + columns: ["role"]; + isOneToOne: false; + referencedRelation: "roles"; + referencedColumns: ["name"]; }, - ] - } + ]; + }; ios_redirect: { Row: { - clientId: string | null - fanId: string | null - id: string | null - timestamp: number | null - } - Insert: { - clientId?: string | null - fanId?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - clientId?: string | null - fanId?: string | null - id?: string | null - timestamp?: number | null - } - Relationships: [] - } + clientId: string | null; + fanId: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + clientId?: string | null; + fanId?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + clientId?: string | null; + fanId?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; leaderboard: { Row: { - id: string | null - Name: string | null - Number: string | null - Score: string | null - Spotify: string | null - "Time._nanoseconds": string | null - "Time._seconds": string | null - } - Insert: { - id?: string | null - Name?: string | null - Number?: string | null - Score?: string | null - Spotify?: string | null - "Time._nanoseconds"?: string | null - "Time._seconds"?: string | null - } - Update: { - id?: string | null - Name?: string | null - Number?: string | null - Score?: string | null - Spotify?: string | null - "Time._nanoseconds"?: string | null - "Time._seconds"?: string | null - } - Relationships: [] - } + id: string | null; + Name: string | null; + Number: string | null; + Score: string | null; + Spotify: string | null; + "Time._nanoseconds": string | null; + "Time._seconds": string | null; + }; + Insert: { + id?: string | null; + Name?: string | null; + Number?: string | null; + Score?: string | null; + Spotify?: string | null; + "Time._nanoseconds"?: string | null; + "Time._seconds"?: string | null; + }; + Update: { + id?: string | null; + Name?: string | null; + Number?: string | null; + Score?: string | null; + Spotify?: string | null; + "Time._nanoseconds"?: string | null; + "Time._seconds"?: string | null; + }; + Relationships: []; + }; leaderboard_boogie: { Row: { - clientId: string | null - displayName: string | null - fanId: string | null - gameType: string | null - id: string | null - score: number | null - timestamp: string | null - } - Insert: { - clientId?: string | null - displayName?: string | null - fanId?: string | null - gameType?: string | null - id?: string | null - score?: number | null - timestamp?: string | null - } - Update: { - clientId?: string | null - displayName?: string | null - fanId?: string | null - gameType?: string | null - id?: string | null - score?: number | null - timestamp?: string | null - } - Relationships: [] - } + clientId: string | null; + displayName: string | null; + fanId: string | null; + gameType: string | null; + id: string | null; + score: number | null; + timestamp: string | null; + }; + Insert: { + clientId?: string | null; + displayName?: string | null; + fanId?: string | null; + gameType?: string | null; + id?: string | null; + score?: number | null; + timestamp?: string | null; + }; + Update: { + clientId?: string | null; + displayName?: string | null; + fanId?: string | null; + gameType?: string | null; + id?: string | null; + score?: number | null; + timestamp?: string | null; + }; + Relationships: []; + }; leaderboard_luh_tyler_3d: { Row: { - FanId: string | null - id: string | null - Score: string | null - ScorePerTime: string | null - Time: string | null - timestamp: string | null - UserName: string | null - } - Insert: { - FanId?: string | null - id?: string | null - Score?: string | null - ScorePerTime?: string | null - Time?: string | null - timestamp?: string | null - UserName?: string | null - } - Update: { - FanId?: string | null - id?: string | null - Score?: string | null - ScorePerTime?: string | null - Time?: string | null - timestamp?: string | null - UserName?: string | null - } - Relationships: [] - } + FanId: string | null; + id: string | null; + Score: string | null; + ScorePerTime: string | null; + Time: string | null; + timestamp: string | null; + UserName: string | null; + }; + Insert: { + FanId?: string | null; + id?: string | null; + Score?: string | null; + ScorePerTime?: string | null; + Time?: string | null; + timestamp?: string | null; + UserName?: string | null; + }; + Update: { + FanId?: string | null; + id?: string | null; + Score?: string | null; + ScorePerTime?: string | null; + Time?: string | null; + timestamp?: string | null; + UserName?: string | null; + }; + Relationships: []; + }; leaderboard_luv: { Row: { - f: string | null - id: string | null - } + f: string | null; + id: string | null; + }; Insert: { - f?: string | null - id?: string | null - } + f?: string | null; + id?: string | null; + }; Update: { - f?: string | null - id?: string | null - } - Relationships: [] - } + f?: string | null; + id?: string | null; + }; + Relationships: []; + }; memories: { Row: { - content: Json - id: string - room_id: string | null - updated_at: string - } - Insert: { - content: Json - id?: string - room_id?: string | null - updated_at?: string - } - Update: { - content?: Json - id?: string - room_id?: string | null - updated_at?: string - } + content: Json; + id: string; + room_id: string | null; + updated_at: string; + }; + Insert: { + content: Json; + id?: string; + room_id?: string | null; + updated_at?: string; + }; + Update: { + content?: Json; + id?: string; + room_id?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "memories_room_id_fkey" - columns: ["room_id"] - isOneToOne: false - referencedRelation: "rooms" - referencedColumns: ["id"] + foreignKeyName: "memories_room_id_fkey"; + columns: ["room_id"]; + isOneToOne: false; + referencedRelation: "rooms"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; memory_emails: { Row: { - created_at: string - email_id: string - id: string - memory: string - message_id: string - } - Insert: { - created_at?: string - email_id: string - id?: string - memory: string - message_id: string - } - Update: { - created_at?: string - email_id?: string - id?: string - memory?: string - message_id?: string - } + created_at: string; + email_id: string; + id: string; + memory: string; + message_id: string; + }; + Insert: { + created_at?: string; + email_id: string; + id?: string; + memory: string; + message_id: string; + }; + Update: { + created_at?: string; + email_id?: string; + id?: string; + memory?: string; + message_id?: string; + }; Relationships: [ { - foreignKeyName: "memory_emails_memory_fkey" - columns: ["memory"] - isOneToOne: false - referencedRelation: "memories" - referencedColumns: ["id"] + foreignKeyName: "memory_emails_memory_fkey"; + columns: ["memory"]; + isOneToOne: false; + referencedRelation: "memories"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; notifications: { Row: { - account_id: string - body: string - channel: Database["public"]["Enums"]["notification_channel"] - created_at: string - dismissed: boolean - expires_at: string | null - id: number - link: string | null - type: Database["public"]["Enums"]["notification_type"] - } - Insert: { - account_id: string - body: string - channel?: Database["public"]["Enums"]["notification_channel"] - created_at?: string - dismissed?: boolean - expires_at?: string | null - id?: never - link?: string | null - type?: Database["public"]["Enums"]["notification_type"] - } - Update: { - account_id?: string - body?: string - channel?: Database["public"]["Enums"]["notification_channel"] - created_at?: string - dismissed?: boolean - expires_at?: string | null - id?: never - link?: string | null - type?: Database["public"]["Enums"]["notification_type"] - } - Relationships: [] - } + account_id: string; + body: string; + channel: Database["public"]["Enums"]["notification_channel"]; + created_at: string; + dismissed: boolean; + expires_at: string | null; + id: number; + link: string | null; + type: Database["public"]["Enums"]["notification_type"]; + }; + Insert: { + account_id: string; + body: string; + channel?: Database["public"]["Enums"]["notification_channel"]; + created_at?: string; + dismissed?: boolean; + expires_at?: string | null; + id?: never; + link?: string | null; + type?: Database["public"]["Enums"]["notification_type"]; + }; + Update: { + account_id?: string; + body?: string; + channel?: Database["public"]["Enums"]["notification_channel"]; + created_at?: string; + dismissed?: boolean; + expires_at?: string | null; + id?: never; + link?: string | null; + type?: Database["public"]["Enums"]["notification_type"]; + }; + Relationships: []; + }; order_items: { Row: { - created_at: string - id: string - order_id: string - price_amount: number | null - product_id: string - quantity: number - updated_at: string - variant_id: string - } - Insert: { - created_at?: string - id: string - order_id: string - price_amount?: number | null - product_id: string - quantity?: number - updated_at?: string - variant_id: string - } - Update: { - created_at?: string - id?: string - order_id?: string - price_amount?: number | null - product_id?: string - quantity?: number - updated_at?: string - variant_id?: string - } + created_at: string; + id: string; + order_id: string; + price_amount: number | null; + product_id: string; + quantity: number; + updated_at: string; + variant_id: string; + }; + Insert: { + created_at?: string; + id: string; + order_id: string; + price_amount?: number | null; + product_id: string; + quantity?: number; + updated_at?: string; + variant_id: string; + }; + Update: { + created_at?: string; + id?: string; + order_id?: string; + price_amount?: number | null; + product_id?: string; + quantity?: number; + updated_at?: string; + variant_id?: string; + }; Relationships: [ { - foreignKeyName: "order_items_order_id_fkey" - columns: ["order_id"] - isOneToOne: false - referencedRelation: "orders" - referencedColumns: ["id"] + foreignKeyName: "order_items_order_id_fkey"; + columns: ["order_id"]; + isOneToOne: false; + referencedRelation: "orders"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; orders: { Row: { - account_id: string - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - created_at: string - currency: string - id: string - status: Database["public"]["Enums"]["payment_status"] - total_amount: number - updated_at: string - } - Insert: { - account_id: string - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - created_at?: string - currency: string - id: string - status: Database["public"]["Enums"]["payment_status"] - total_amount: number - updated_at?: string - } - Update: { - account_id?: string - billing_customer_id?: number - billing_provider?: Database["public"]["Enums"]["billing_provider"] - created_at?: string - currency?: string - id?: string - status?: Database["public"]["Enums"]["payment_status"] - total_amount?: number - updated_at?: string - } + account_id: string; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + created_at: string; + currency: string; + id: string; + status: Database["public"]["Enums"]["payment_status"]; + total_amount: number; + updated_at: string; + }; + Insert: { + account_id: string; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + created_at?: string; + currency: string; + id: string; + status: Database["public"]["Enums"]["payment_status"]; + total_amount: number; + updated_at?: string; + }; + Update: { + account_id?: string; + billing_customer_id?: number; + billing_provider?: Database["public"]["Enums"]["billing_provider"]; + created_at?: string; + currency?: string; + id?: string; + status?: Database["public"]["Enums"]["payment_status"]; + total_amount?: number; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "orders_billing_customer_id_fkey" - columns: ["billing_customer_id"] - isOneToOne: false - referencedRelation: "billing_customers" - referencedColumns: ["id"] + foreignKeyName: "orders_billing_customer_id_fkey"; + columns: ["billing_customer_id"]; + isOneToOne: false; + referencedRelation: "billing_customers"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; organization_domains: { Row: { - created_at: string | null - domain: string - id: string - organization_id: string - } - Insert: { - created_at?: string | null - domain: string - id?: string - organization_id: string - } - Update: { - created_at?: string | null - domain?: string - id?: string - organization_id?: string - } + created_at: string | null; + domain: string; + id: string; + organization_id: string; + }; + Insert: { + created_at?: string | null; + domain: string; + id?: string; + organization_id: string; + }; + Update: { + created_at?: string | null; + domain?: string; + id?: string; + organization_id?: string; + }; Relationships: [ { - foreignKeyName: "organization_domains_organization_id_fkey" - columns: ["organization_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "organization_domains_organization_id_fkey"; + columns: ["organization_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; plans: { Row: { - name: string - tokens_quota: number - variant_id: string - } - Insert: { - name: string - tokens_quota: number - variant_id: string - } - Update: { - name?: string - tokens_quota?: number - variant_id?: string - } - Relationships: [] - } + name: string; + tokens_quota: number; + variant_id: string; + }; + Insert: { + name: string; + tokens_quota: number; + variant_id: string; + }; + Update: { + name?: string; + tokens_quota?: number; + variant_id?: string; + }; + Relationships: []; + }; popup_open: { Row: { - campaignId: string | null - clientId: string | null - fanId: string | null - game: string | null - id: string | null - timestamp: string | null - } - Insert: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: string | null - } - Update: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: string | null - } - Relationships: [] - } + campaignId: string | null; + clientId: string | null; + fanId: string | null; + game: string | null; + id: string | null; + timestamp: string | null; + }; + Insert: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: string | null; + }; + Update: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: string | null; + }; + Relationships: []; + }; post_comments: { Row: { - comment: string | null - commented_at: string - id: string - post_id: string | null - social_id: string | null - } - Insert: { - comment?: string | null - commented_at: string - id?: string - post_id?: string | null - social_id?: string | null - } - Update: { - comment?: string | null - commented_at?: string - id?: string - post_id?: string | null - social_id?: string | null - } + comment: string | null; + commented_at: string; + id: string; + post_id: string | null; + social_id: string | null; + }; + Insert: { + comment?: string | null; + commented_at: string; + id?: string; + post_id?: string | null; + social_id?: string | null; + }; + Update: { + comment?: string | null; + commented_at?: string; + id?: string; + post_id?: string | null; + social_id?: string | null; + }; Relationships: [ { - foreignKeyName: "post_comments_post_id_fkey" - columns: ["post_id"] - isOneToOne: false - referencedRelation: "posts" - referencedColumns: ["id"] + foreignKeyName: "post_comments_post_id_fkey"; + columns: ["post_id"]; + isOneToOne: false; + referencedRelation: "posts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "post_comments_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "post_comments_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; posts: { Row: { - id: string - post_url: string - updated_at: string - } - Insert: { - id?: string - post_url: string - updated_at?: string - } - Update: { - id?: string - post_url?: string - updated_at?: string - } - Relationships: [] - } + id: string; + post_url: string; + updated_at: string; + }; + Insert: { + id?: string; + post_url: string; + updated_at?: string; + }; + Update: { + id?: string; + post_url?: string; + updated_at?: string; + }; + Relationships: []; + }; presave: { Row: { - accessToken: string | null - fanId: string | null - "fanId.error.code": string | null - "fanId.error.name": string | null - id: string | null - presaveId: string | null - presaveReleaseDate: string | null - refreshToken: string | null - timestamp: number | null - } - Insert: { - accessToken?: string | null - fanId?: string | null - "fanId.error.code"?: string | null - "fanId.error.name"?: string | null - id?: string | null - presaveId?: string | null - presaveReleaseDate?: string | null - refreshToken?: string | null - timestamp?: number | null - } - Update: { - accessToken?: string | null - fanId?: string | null - "fanId.error.code"?: string | null - "fanId.error.name"?: string | null - id?: string | null - presaveId?: string | null - presaveReleaseDate?: string | null - refreshToken?: string | null - timestamp?: number | null - } - Relationships: [] - } + accessToken: string | null; + fanId: string | null; + "fanId.error.code": string | null; + "fanId.error.name": string | null; + id: string | null; + presaveId: string | null; + presaveReleaseDate: string | null; + refreshToken: string | null; + timestamp: number | null; + }; + Insert: { + accessToken?: string | null; + fanId?: string | null; + "fanId.error.code"?: string | null; + "fanId.error.name"?: string | null; + id?: string | null; + presaveId?: string | null; + presaveReleaseDate?: string | null; + refreshToken?: string | null; + timestamp?: number | null; + }; + Update: { + accessToken?: string | null; + fanId?: string | null; + "fanId.error.code"?: string | null; + "fanId.error.name"?: string | null; + id?: string | null; + presaveId?: string | null; + presaveReleaseDate?: string | null; + refreshToken?: string | null; + timestamp?: number | null; + }; + Relationships: []; + }; pulse_accounts: { Row: { - account_id: string - active: boolean - id: string - } + account_id: string; + active: boolean; + id: string; + }; Insert: { - account_id: string - active?: boolean - id?: string - } + account_id: string; + active?: boolean; + id?: string; + }; Update: { - account_id?: string - active?: boolean - id?: string - } + account_id?: string; + active?: boolean; + id?: string; + }; Relationships: [ { - foreignKeyName: "pulse_accounts_account_id_fkey" - columns: ["account_id"] - isOneToOne: true - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "pulse_accounts_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: true; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; role_permissions: { Row: { - id: number - permission: Database["public"]["Enums"]["app_permissions"] - role: string - } + id: number; + permission: Database["public"]["Enums"]["app_permissions"]; + role: string; + }; Insert: { - id?: number - permission: Database["public"]["Enums"]["app_permissions"] - role: string - } + id?: number; + permission: Database["public"]["Enums"]["app_permissions"]; + role: string; + }; Update: { - id?: number - permission?: Database["public"]["Enums"]["app_permissions"] - role?: string - } + id?: number; + permission?: Database["public"]["Enums"]["app_permissions"]; + role?: string; + }; Relationships: [ { - foreignKeyName: "role_permissions_role_fkey" - columns: ["role"] - isOneToOne: false - referencedRelation: "roles" - referencedColumns: ["name"] + foreignKeyName: "role_permissions_role_fkey"; + columns: ["role"]; + isOneToOne: false; + referencedRelation: "roles"; + referencedColumns: ["name"]; }, - ] - } + ]; + }; roles: { Row: { - hierarchy_level: number - name: string - } + hierarchy_level: number; + name: string; + }; Insert: { - hierarchy_level: number - name: string - } + hierarchy_level: number; + name: string; + }; Update: { - hierarchy_level?: number - name?: string - } - Relationships: [] - } + hierarchy_level?: number; + name?: string; + }; + Relationships: []; + }; room_reports: { Row: { - id: string - report_id: string - room_id: string | null - } + id: string; + report_id: string; + room_id: string | null; + }; Insert: { - id?: string - report_id?: string - room_id?: string | null - } + id?: string; + report_id?: string; + room_id?: string | null; + }; Update: { - id?: string - report_id?: string - room_id?: string | null - } + id?: string; + report_id?: string; + room_id?: string | null; + }; Relationships: [ { - foreignKeyName: "room_reports_report_id_fkey" - columns: ["report_id"] - isOneToOne: false - referencedRelation: "segment_reports" - referencedColumns: ["id"] + foreignKeyName: "room_reports_report_id_fkey"; + columns: ["report_id"]; + isOneToOne: false; + referencedRelation: "segment_reports"; + referencedColumns: ["id"]; }, { - foreignKeyName: "room_reports_room_id_fkey" - columns: ["room_id"] - isOneToOne: false - referencedRelation: "rooms" - referencedColumns: ["id"] + foreignKeyName: "room_reports_room_id_fkey"; + columns: ["room_id"]; + isOneToOne: false; + referencedRelation: "rooms"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; rooms: { Row: { - account_id: string | null - artist_id: string | null - id: string - topic: string | null - updated_at: string - } - Insert: { - account_id?: string | null - artist_id?: string | null - id?: string - topic?: string | null - updated_at?: string - } - Update: { - account_id?: string | null - artist_id?: string | null - id?: string - topic?: string | null - updated_at?: string - } + account_id: string | null; + artist_id: string | null; + id: string; + topic: string | null; + updated_at: string; + }; + Insert: { + account_id?: string | null; + artist_id?: string | null; + id?: string; + topic?: string | null; + updated_at?: string; + }; + Update: { + account_id?: string | null; + artist_id?: string | null; + id?: string; + topic?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "rooms_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "rooms_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; sales_pipeline_customers: { Row: { - activity_count: number | null - assigned_to: string | null - company_size: string | null - competitors: string[] | null - contact_email: string | null - contact_name: string | null - contact_phone: string | null - contacts: Json | null - conversion_stage: string | null - conversion_target_date: string | null - created_at: string | null - current_artists: number - current_mrr: number - custom_fields: Json | null - days_in_stage: number | null - domain: string | null - email: string | null - engagement_health: string | null - expected_close_date: string | null - external_ids: Json | null - id: string - industry: string | null - internal_owner: string | null - last_activity_date: string | null - last_activity_type: string | null - last_contact_date: string - logo_url: string | null - lost_reason: string | null - name: string - next_action: string | null - next_activity_date: string | null - next_activity_type: string | null - notes: string | null - order_index: number | null - organization: string | null - potential_artists: number - potential_mrr: number - priority: string | null - probability: number | null - recoupable_user_id: string | null - source: string | null - stage: string - stage_entered_at: string | null - tags: string[] | null - todos: Json | null - trial_end_date: string | null - trial_start_date: string | null - type: string | null - updated_at: string | null - use_case_type: string | null - website: string | null - weighted_mrr: number | null - win_reason: string | null - } - Insert: { - activity_count?: number | null - assigned_to?: string | null - company_size?: string | null - competitors?: string[] | null - contact_email?: string | null - contact_name?: string | null - contact_phone?: string | null - contacts?: Json | null - conversion_stage?: string | null - conversion_target_date?: string | null - created_at?: string | null - current_artists?: number - current_mrr?: number - custom_fields?: Json | null - days_in_stage?: number | null - domain?: string | null - email?: string | null - engagement_health?: string | null - expected_close_date?: string | null - external_ids?: Json | null - id?: string - industry?: string | null - internal_owner?: string | null - last_activity_date?: string | null - last_activity_type?: string | null - last_contact_date?: string - logo_url?: string | null - lost_reason?: string | null - name: string - next_action?: string | null - next_activity_date?: string | null - next_activity_type?: string | null - notes?: string | null - order_index?: number | null - organization?: string | null - potential_artists?: number - potential_mrr?: number - priority?: string | null - probability?: number | null - recoupable_user_id?: string | null - source?: string | null - stage: string - stage_entered_at?: string | null - tags?: string[] | null - todos?: Json | null - trial_end_date?: string | null - trial_start_date?: string | null - type?: string | null - updated_at?: string | null - use_case_type?: string | null - website?: string | null - weighted_mrr?: number | null - win_reason?: string | null - } - Update: { - activity_count?: number | null - assigned_to?: string | null - company_size?: string | null - competitors?: string[] | null - contact_email?: string | null - contact_name?: string | null - contact_phone?: string | null - contacts?: Json | null - conversion_stage?: string | null - conversion_target_date?: string | null - created_at?: string | null - current_artists?: number - current_mrr?: number - custom_fields?: Json | null - days_in_stage?: number | null - domain?: string | null - email?: string | null - engagement_health?: string | null - expected_close_date?: string | null - external_ids?: Json | null - id?: string - industry?: string | null - internal_owner?: string | null - last_activity_date?: string | null - last_activity_type?: string | null - last_contact_date?: string - logo_url?: string | null - lost_reason?: string | null - name?: string - next_action?: string | null - next_activity_date?: string | null - next_activity_type?: string | null - notes?: string | null - order_index?: number | null - organization?: string | null - potential_artists?: number - potential_mrr?: number - priority?: string | null - probability?: number | null - recoupable_user_id?: string | null - source?: string | null - stage?: string - stage_entered_at?: string | null - tags?: string[] | null - todos?: Json | null - trial_end_date?: string | null - trial_start_date?: string | null - type?: string | null - updated_at?: string | null - use_case_type?: string | null - website?: string | null - weighted_mrr?: number | null - win_reason?: string | null - } - Relationships: [] - } + activity_count: number | null; + assigned_to: string | null; + company_size: string | null; + competitors: string[] | null; + contact_email: string | null; + contact_name: string | null; + contact_phone: string | null; + contacts: Json | null; + conversion_stage: string | null; + conversion_target_date: string | null; + created_at: string | null; + current_artists: number; + current_mrr: number; + custom_fields: Json | null; + days_in_stage: number | null; + domain: string | null; + email: string | null; + engagement_health: string | null; + expected_close_date: string | null; + external_ids: Json | null; + id: string; + industry: string | null; + internal_owner: string | null; + last_activity_date: string | null; + last_activity_type: string | null; + last_contact_date: string; + logo_url: string | null; + lost_reason: string | null; + name: string; + next_action: string | null; + next_activity_date: string | null; + next_activity_type: string | null; + notes: string | null; + order_index: number | null; + organization: string | null; + potential_artists: number; + potential_mrr: number; + priority: string | null; + probability: number | null; + recoupable_user_id: string | null; + source: string | null; + stage: string; + stage_entered_at: string | null; + tags: string[] | null; + todos: Json | null; + trial_end_date: string | null; + trial_start_date: string | null; + type: string | null; + updated_at: string | null; + use_case_type: string | null; + website: string | null; + weighted_mrr: number | null; + win_reason: string | null; + }; + Insert: { + activity_count?: number | null; + assigned_to?: string | null; + company_size?: string | null; + competitors?: string[] | null; + contact_email?: string | null; + contact_name?: string | null; + contact_phone?: string | null; + contacts?: Json | null; + conversion_stage?: string | null; + conversion_target_date?: string | null; + created_at?: string | null; + current_artists?: number; + current_mrr?: number; + custom_fields?: Json | null; + days_in_stage?: number | null; + domain?: string | null; + email?: string | null; + engagement_health?: string | null; + expected_close_date?: string | null; + external_ids?: Json | null; + id?: string; + industry?: string | null; + internal_owner?: string | null; + last_activity_date?: string | null; + last_activity_type?: string | null; + last_contact_date?: string; + logo_url?: string | null; + lost_reason?: string | null; + name: string; + next_action?: string | null; + next_activity_date?: string | null; + next_activity_type?: string | null; + notes?: string | null; + order_index?: number | null; + organization?: string | null; + potential_artists?: number; + potential_mrr?: number; + priority?: string | null; + probability?: number | null; + recoupable_user_id?: string | null; + source?: string | null; + stage: string; + stage_entered_at?: string | null; + tags?: string[] | null; + todos?: Json | null; + trial_end_date?: string | null; + trial_start_date?: string | null; + type?: string | null; + updated_at?: string | null; + use_case_type?: string | null; + website?: string | null; + weighted_mrr?: number | null; + win_reason?: string | null; + }; + Update: { + activity_count?: number | null; + assigned_to?: string | null; + company_size?: string | null; + competitors?: string[] | null; + contact_email?: string | null; + contact_name?: string | null; + contact_phone?: string | null; + contacts?: Json | null; + conversion_stage?: string | null; + conversion_target_date?: string | null; + created_at?: string | null; + current_artists?: number; + current_mrr?: number; + custom_fields?: Json | null; + days_in_stage?: number | null; + domain?: string | null; + email?: string | null; + engagement_health?: string | null; + expected_close_date?: string | null; + external_ids?: Json | null; + id?: string; + industry?: string | null; + internal_owner?: string | null; + last_activity_date?: string | null; + last_activity_type?: string | null; + last_contact_date?: string; + logo_url?: string | null; + lost_reason?: string | null; + name?: string; + next_action?: string | null; + next_activity_date?: string | null; + next_activity_type?: string | null; + notes?: string | null; + order_index?: number | null; + organization?: string | null; + potential_artists?: number; + potential_mrr?: number; + priority?: string | null; + probability?: number | null; + recoupable_user_id?: string | null; + source?: string | null; + stage?: string; + stage_entered_at?: string | null; + tags?: string[] | null; + todos?: Json | null; + trial_end_date?: string | null; + trial_start_date?: string | null; + type?: string | null; + updated_at?: string | null; + use_case_type?: string | null; + website?: string | null; + weighted_mrr?: number | null; + win_reason?: string | null; + }; + Relationships: []; + }; save_track: { Row: { - game: string | null - id: string | null - timestamp: string | null - } - Insert: { - game?: string | null - id?: string | null - timestamp?: string | null - } - Update: { - game?: string | null - id?: string | null - timestamp?: string | null - } - Relationships: [] - } + game: string | null; + id: string | null; + timestamp: string | null; + }; + Insert: { + game?: string | null; + id?: string | null; + timestamp?: string | null; + }; + Update: { + game?: string | null; + id?: string | null; + timestamp?: string | null; + }; + Relationships: []; + }; scheduled_actions: { Row: { - account_id: string - artist_account_id: string - created_at: string | null - enabled: boolean | null - id: string - last_run: string | null - model: string | null - next_run: string | null - prompt: string - schedule: string - title: string - trigger_schedule_id: string | null - updated_at: string | null - } - Insert: { - account_id: string - artist_account_id: string - created_at?: string | null - enabled?: boolean | null - id?: string - last_run?: string | null - model?: string | null - next_run?: string | null - prompt: string - schedule: string - title: string - trigger_schedule_id?: string | null - updated_at?: string | null - } - Update: { - account_id?: string - artist_account_id?: string - created_at?: string | null - enabled?: boolean | null - id?: string - last_run?: string | null - model?: string | null - next_run?: string | null - prompt?: string - schedule?: string - title?: string - trigger_schedule_id?: string | null - updated_at?: string | null - } + account_id: string; + artist_account_id: string; + created_at: string | null; + enabled: boolean | null; + id: string; + last_run: string | null; + model: string | null; + next_run: string | null; + prompt: string; + schedule: string; + title: string; + trigger_schedule_id: string | null; + updated_at: string | null; + }; + Insert: { + account_id: string; + artist_account_id: string; + created_at?: string | null; + enabled?: boolean | null; + id?: string; + last_run?: string | null; + model?: string | null; + next_run?: string | null; + prompt: string; + schedule: string; + title: string; + trigger_schedule_id?: string | null; + updated_at?: string | null; + }; + Update: { + account_id?: string; + artist_account_id?: string; + created_at?: string | null; + enabled?: boolean | null; + id?: string; + last_run?: string | null; + model?: string | null; + next_run?: string | null; + prompt?: string; + schedule?: string; + title?: string; + trigger_schedule_id?: string | null; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "scheduled_actions_account_id_fkey" - columns: ["account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "scheduled_actions_account_id_fkey"; + columns: ["account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "scheduled_actions_artist_account_id_fkey" - columns: ["artist_account_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "scheduled_actions_artist_account_id_fkey"; + columns: ["artist_account_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; segment_reports: { Row: { - artist_id: string | null - id: string - next_steps: string | null - report: string | null - updated_at: string | null - } - Insert: { - artist_id?: string | null - id?: string - next_steps?: string | null - report?: string | null - updated_at?: string | null - } - Update: { - artist_id?: string | null - id?: string - next_steps?: string | null - report?: string | null - updated_at?: string | null - } + artist_id: string | null; + id: string; + next_steps: string | null; + report: string | null; + updated_at: string | null; + }; + Insert: { + artist_id?: string | null; + id?: string; + next_steps?: string | null; + report?: string | null; + updated_at?: string | null; + }; + Update: { + artist_id?: string | null; + id?: string; + next_steps?: string | null; + report?: string | null; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "segment_reports_artist_id_fkey" - columns: ["artist_id"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "segment_reports_artist_id_fkey"; + columns: ["artist_id"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; segment_rooms: { Row: { - id: string - room_id: string - segment_id: string - updated_at: string - } - Insert: { - id?: string - room_id: string - segment_id: string - updated_at?: string - } - Update: { - id?: string - room_id?: string - segment_id?: string - updated_at?: string - } + id: string; + room_id: string; + segment_id: string; + updated_at: string; + }; + Insert: { + id?: string; + room_id: string; + segment_id: string; + updated_at?: string; + }; + Update: { + id?: string; + room_id?: string; + segment_id?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "segment_rooms_room_id_fkey" - columns: ["room_id"] - isOneToOne: false - referencedRelation: "rooms" - referencedColumns: ["id"] + foreignKeyName: "segment_rooms_room_id_fkey"; + columns: ["room_id"]; + isOneToOne: false; + referencedRelation: "rooms"; + referencedColumns: ["id"]; }, { - foreignKeyName: "segment_rooms_segment_id_fkey" - columns: ["segment_id"] - isOneToOne: false - referencedRelation: "segments" - referencedColumns: ["id"] + foreignKeyName: "segment_rooms_segment_id_fkey"; + columns: ["segment_id"]; + isOneToOne: false; + referencedRelation: "segments"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; segments: { Row: { - id: string - name: string - updated_at: string | null - } - Insert: { - id?: string - name: string - updated_at?: string | null - } - Update: { - id?: string - name?: string - updated_at?: string | null - } - Relationships: [] - } + id: string; + name: string; + updated_at: string | null; + }; + Insert: { + id?: string; + name: string; + updated_at?: string | null; + }; + Update: { + id?: string; + name?: string; + updated_at?: string | null; + }; + Relationships: []; + }; social_fans: { Row: { - artist_social_id: string - created_at: string - fan_social_id: string - id: string - latest_engagement: string | null - latest_engagement_id: string | null - updated_at: string - } - Insert: { - artist_social_id: string - created_at?: string - fan_social_id: string - id?: string - latest_engagement?: string | null - latest_engagement_id?: string | null - updated_at?: string - } - Update: { - artist_social_id?: string - created_at?: string - fan_social_id?: string - id?: string - latest_engagement?: string | null - latest_engagement_id?: string | null - updated_at?: string - } + artist_social_id: string; + created_at: string; + fan_social_id: string; + id: string; + latest_engagement: string | null; + latest_engagement_id: string | null; + updated_at: string; + }; + Insert: { + artist_social_id: string; + created_at?: string; + fan_social_id: string; + id?: string; + latest_engagement?: string | null; + latest_engagement_id?: string | null; + updated_at?: string; + }; + Update: { + artist_social_id?: string; + created_at?: string; + fan_social_id?: string; + id?: string; + latest_engagement?: string | null; + latest_engagement_id?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "social_fans_artist_social_id_fkey" - columns: ["artist_social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "social_fans_artist_social_id_fkey"; + columns: ["artist_social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, { - foreignKeyName: "social_fans_fan_social_id_fkey" - columns: ["fan_social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "social_fans_fan_social_id_fkey"; + columns: ["fan_social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, { - foreignKeyName: "social_fans_latest_engagement_id_fkey" - columns: ["latest_engagement_id"] - isOneToOne: false - referencedRelation: "post_comments" - referencedColumns: ["id"] + foreignKeyName: "social_fans_latest_engagement_id_fkey"; + columns: ["latest_engagement_id"]; + isOneToOne: false; + referencedRelation: "post_comments"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; social_posts: { Row: { - id: string - post_id: string | null - social_id: string | null - updated_at: string | null - } - Insert: { - id?: string - post_id?: string | null - social_id?: string | null - updated_at?: string | null - } - Update: { - id?: string - post_id?: string | null - social_id?: string | null - updated_at?: string | null - } + id: string; + post_id: string | null; + social_id: string | null; + updated_at: string | null; + }; + Insert: { + id?: string; + post_id?: string | null; + social_id?: string | null; + updated_at?: string | null; + }; + Update: { + id?: string; + post_id?: string | null; + social_id?: string | null; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "social_posts_post_id_fkey" - columns: ["post_id"] - isOneToOne: false - referencedRelation: "posts" - referencedColumns: ["id"] + foreignKeyName: "social_posts_post_id_fkey"; + columns: ["post_id"]; + isOneToOne: false; + referencedRelation: "posts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "social_posts_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "social_posts_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; social_spotify_albums: { Row: { - album_id: string | null - id: string - social_id: string | null - updated_at: string - } - Insert: { - album_id?: string | null - id?: string - social_id?: string | null - updated_at?: string - } - Update: { - album_id?: string | null - id?: string - social_id?: string | null - updated_at?: string - } + album_id: string | null; + id: string; + social_id: string | null; + updated_at: string; + }; + Insert: { + album_id?: string | null; + id?: string; + social_id?: string | null; + updated_at?: string; + }; + Update: { + album_id?: string | null; + id?: string; + social_id?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "social_spotify_albums_album_id_fkey" - columns: ["album_id"] - isOneToOne: false - referencedRelation: "spotify_albums" - referencedColumns: ["id"] + foreignKeyName: "social_spotify_albums_album_id_fkey"; + columns: ["album_id"]; + isOneToOne: false; + referencedRelation: "spotify_albums"; + referencedColumns: ["id"]; }, { - foreignKeyName: "social_spotify_albums_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "social_spotify_albums_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; social_spotify_tracks: { Row: { - id: string - social_id: string - track_id: string | null - updated_at: string | null - } - Insert: { - id?: string - social_id?: string - track_id?: string | null - updated_at?: string | null - } - Update: { - id?: string - social_id?: string - track_id?: string | null - updated_at?: string | null - } + id: string; + social_id: string; + track_id: string | null; + updated_at: string | null; + }; + Insert: { + id?: string; + social_id?: string; + track_id?: string | null; + updated_at?: string | null; + }; + Update: { + id?: string; + social_id?: string; + track_id?: string | null; + updated_at?: string | null; + }; Relationships: [ { - foreignKeyName: "social_spotify_tracks_social_id_fkey" - columns: ["social_id"] - isOneToOne: false - referencedRelation: "socials" - referencedColumns: ["id"] + foreignKeyName: "social_spotify_tracks_social_id_fkey"; + columns: ["social_id"]; + isOneToOne: false; + referencedRelation: "socials"; + referencedColumns: ["id"]; }, { - foreignKeyName: "social_spotify_tracks_track_id_fkey" - columns: ["track_id"] - isOneToOne: false - referencedRelation: "spotify_tracks" - referencedColumns: ["id"] + foreignKeyName: "social_spotify_tracks_track_id_fkey"; + columns: ["track_id"]; + isOneToOne: false; + referencedRelation: "spotify_tracks"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; socials: { Row: { - avatar: string | null - bio: string | null - followerCount: number | null - followingCount: number | null - id: string - profile_url: string - region: string | null - updated_at: string - username: string - } - Insert: { - avatar?: string | null - bio?: string | null - followerCount?: number | null - followingCount?: number | null - id?: string - profile_url: string - region?: string | null - updated_at?: string - username: string - } - Update: { - avatar?: string | null - bio?: string | null - followerCount?: number | null - followingCount?: number | null - id?: string - profile_url?: string - region?: string | null - updated_at?: string - username?: string - } - Relationships: [] - } + avatar: string | null; + bio: string | null; + followerCount: number | null; + followingCount: number | null; + id: string; + profile_url: string; + region: string | null; + updated_at: string; + username: string; + }; + Insert: { + avatar?: string | null; + bio?: string | null; + followerCount?: number | null; + followingCount?: number | null; + id?: string; + profile_url: string; + region?: string | null; + updated_at?: string; + username: string; + }; + Update: { + avatar?: string | null; + bio?: string | null; + followerCount?: number | null; + followingCount?: number | null; + id?: string; + profile_url?: string; + region?: string | null; + updated_at?: string; + username?: string; + }; + Relationships: []; + }; song_artists: { Row: { - artist: string - created_at: string - id: string - song: string - updated_at: string - } - Insert: { - artist: string - created_at?: string - id?: string - song: string - updated_at?: string - } - Update: { - artist?: string - created_at?: string - id?: string - song?: string - updated_at?: string - } + artist: string; + created_at: string; + id: string; + song: string; + updated_at: string; + }; + Insert: { + artist: string; + created_at?: string; + id?: string; + song: string; + updated_at?: string; + }; + Update: { + artist?: string; + created_at?: string; + id?: string; + song?: string; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "song_artists_artist_fkey" - columns: ["artist"] - isOneToOne: false - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "song_artists_artist_fkey"; + columns: ["artist"]; + isOneToOne: false; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, { - foreignKeyName: "song_artists_song_fkey" - columns: ["song"] - isOneToOne: false - referencedRelation: "songs" - referencedColumns: ["isrc"] + foreignKeyName: "song_artists_song_fkey"; + columns: ["song"]; + isOneToOne: false; + referencedRelation: "songs"; + referencedColumns: ["isrc"]; }, - ] - } + ]; + }; songs: { Row: { - album: string | null - isrc: string - name: string | null - notes: string | null - updated_at: string - } - Insert: { - album?: string | null - isrc: string - name?: string | null - notes?: string | null - updated_at?: string - } - Update: { - album?: string | null - isrc?: string - name?: string | null - notes?: string | null - updated_at?: string - } - Relationships: [] - } + album: string | null; + isrc: string; + name: string | null; + notes: string | null; + updated_at: string; + }; + Insert: { + album?: string | null; + isrc: string; + name?: string | null; + notes?: string | null; + updated_at?: string; + }; + Update: { + album?: string | null; + isrc?: string; + name?: string | null; + notes?: string | null; + updated_at?: string; + }; + Relationships: []; + }; spotify: { Row: { - clientId: string | null - country: string | null - display_name: string | null - email: string | null - "explicit_content.filter_enabled": string | null - "explicit_content.filter_locked": string | null - "external_urls.spotify": Json | null - fanId: string | null - "fanId.country": string | null - "fanId.display_name": string | null - "fanId.email": string | null - "fanId.explicit_content.filter_enabled": string | null - "fanId.explicit_content.filter_locked": string | null - "fanId.external_urls.spotify": string | null - "fanId.followers.total": string | null - "fanId.href": string | null - "fanId.id": string | null - "fanId.images": string | null - "fanId.isNewFan": string | null - "fanId.playlist": string | null - "fanId.presavedData.clientId": string | null - "fanId.presavedData.country": string | null - "fanId.presavedData.display_name": string | null - "fanId.presavedData.email": string | null - "fanId.presavedData.explicit_content.filter_enabled": string | null - "fanId.presavedData.explicit_content.filter_locked": string | null - "fanId.presavedData.external_urls.spotify": string | null - "fanId.presavedData.followers.total": string | null - "fanId.presavedData.href": string | null - "fanId.presavedData.id": string | null - "fanId.presavedData.images": string | null - "fanId.presavedData.playlist": string | null - "fanId.presavedData.product": string | null - "fanId.presavedData.recentlyPlayed": string | null - "fanId.presavedData.timestamp": string | null - "fanId.presavedData.type": string | null - "fanId.presavedData.uri": string | null - "fanId.product": string | null - "fanId.timestamp": string | null - "fanId.type": string | null - "fanId.uri": string | null - "followers.total": Json | null - game: string | null - href: string | null - id: string | null - images: Json | null - playlist: Json | null - product: string | null - syncId: string | null - timestamp: string | null - type: string | null - uri: string | null - } - Insert: { - clientId?: string | null - country?: string | null - display_name?: string | null - email?: string | null - "explicit_content.filter_enabled"?: string | null - "explicit_content.filter_locked"?: string | null - "external_urls.spotify"?: Json | null - fanId?: string | null - "fanId.country"?: string | null - "fanId.display_name"?: string | null - "fanId.email"?: string | null - "fanId.explicit_content.filter_enabled"?: string | null - "fanId.explicit_content.filter_locked"?: string | null - "fanId.external_urls.spotify"?: string | null - "fanId.followers.total"?: string | null - "fanId.href"?: string | null - "fanId.id"?: string | null - "fanId.images"?: string | null - "fanId.isNewFan"?: string | null - "fanId.playlist"?: string | null - "fanId.presavedData.clientId"?: string | null - "fanId.presavedData.country"?: string | null - "fanId.presavedData.display_name"?: string | null - "fanId.presavedData.email"?: string | null - "fanId.presavedData.explicit_content.filter_enabled"?: string | null - "fanId.presavedData.explicit_content.filter_locked"?: string | null - "fanId.presavedData.external_urls.spotify"?: string | null - "fanId.presavedData.followers.total"?: string | null - "fanId.presavedData.href"?: string | null - "fanId.presavedData.id"?: string | null - "fanId.presavedData.images"?: string | null - "fanId.presavedData.playlist"?: string | null - "fanId.presavedData.product"?: string | null - "fanId.presavedData.recentlyPlayed"?: string | null - "fanId.presavedData.timestamp"?: string | null - "fanId.presavedData.type"?: string | null - "fanId.presavedData.uri"?: string | null - "fanId.product"?: string | null - "fanId.timestamp"?: string | null - "fanId.type"?: string | null - "fanId.uri"?: string | null - "followers.total"?: Json | null - game?: string | null - href?: string | null - id?: string | null - images?: Json | null - playlist?: Json | null - product?: string | null - syncId?: string | null - timestamp?: string | null - type?: string | null - uri?: string | null - } - Update: { - clientId?: string | null - country?: string | null - display_name?: string | null - email?: string | null - "explicit_content.filter_enabled"?: string | null - "explicit_content.filter_locked"?: string | null - "external_urls.spotify"?: Json | null - fanId?: string | null - "fanId.country"?: string | null - "fanId.display_name"?: string | null - "fanId.email"?: string | null - "fanId.explicit_content.filter_enabled"?: string | null - "fanId.explicit_content.filter_locked"?: string | null - "fanId.external_urls.spotify"?: string | null - "fanId.followers.total"?: string | null - "fanId.href"?: string | null - "fanId.id"?: string | null - "fanId.images"?: string | null - "fanId.isNewFan"?: string | null - "fanId.playlist"?: string | null - "fanId.presavedData.clientId"?: string | null - "fanId.presavedData.country"?: string | null - "fanId.presavedData.display_name"?: string | null - "fanId.presavedData.email"?: string | null - "fanId.presavedData.explicit_content.filter_enabled"?: string | null - "fanId.presavedData.explicit_content.filter_locked"?: string | null - "fanId.presavedData.external_urls.spotify"?: string | null - "fanId.presavedData.followers.total"?: string | null - "fanId.presavedData.href"?: string | null - "fanId.presavedData.id"?: string | null - "fanId.presavedData.images"?: string | null - "fanId.presavedData.playlist"?: string | null - "fanId.presavedData.product"?: string | null - "fanId.presavedData.recentlyPlayed"?: string | null - "fanId.presavedData.timestamp"?: string | null - "fanId.presavedData.type"?: string | null - "fanId.presavedData.uri"?: string | null - "fanId.product"?: string | null - "fanId.timestamp"?: string | null - "fanId.type"?: string | null - "fanId.uri"?: string | null - "followers.total"?: Json | null - game?: string | null - href?: string | null - id?: string | null - images?: Json | null - playlist?: Json | null - product?: string | null - syncId?: string | null - timestamp?: string | null - type?: string | null - uri?: string | null - } - Relationships: [] - } + clientId: string | null; + country: string | null; + display_name: string | null; + email: string | null; + "explicit_content.filter_enabled": string | null; + "explicit_content.filter_locked": string | null; + "external_urls.spotify": Json | null; + fanId: string | null; + "fanId.country": string | null; + "fanId.display_name": string | null; + "fanId.email": string | null; + "fanId.explicit_content.filter_enabled": string | null; + "fanId.explicit_content.filter_locked": string | null; + "fanId.external_urls.spotify": string | null; + "fanId.followers.total": string | null; + "fanId.href": string | null; + "fanId.id": string | null; + "fanId.images": string | null; + "fanId.isNewFan": string | null; + "fanId.playlist": string | null; + "fanId.presavedData.clientId": string | null; + "fanId.presavedData.country": string | null; + "fanId.presavedData.display_name": string | null; + "fanId.presavedData.email": string | null; + "fanId.presavedData.explicit_content.filter_enabled": string | null; + "fanId.presavedData.explicit_content.filter_locked": string | null; + "fanId.presavedData.external_urls.spotify": string | null; + "fanId.presavedData.followers.total": string | null; + "fanId.presavedData.href": string | null; + "fanId.presavedData.id": string | null; + "fanId.presavedData.images": string | null; + "fanId.presavedData.playlist": string | null; + "fanId.presavedData.product": string | null; + "fanId.presavedData.recentlyPlayed": string | null; + "fanId.presavedData.timestamp": string | null; + "fanId.presavedData.type": string | null; + "fanId.presavedData.uri": string | null; + "fanId.product": string | null; + "fanId.timestamp": string | null; + "fanId.type": string | null; + "fanId.uri": string | null; + "followers.total": Json | null; + game: string | null; + href: string | null; + id: string | null; + images: Json | null; + playlist: Json | null; + product: string | null; + syncId: string | null; + timestamp: string | null; + type: string | null; + uri: string | null; + }; + Insert: { + clientId?: string | null; + country?: string | null; + display_name?: string | null; + email?: string | null; + "explicit_content.filter_enabled"?: string | null; + "explicit_content.filter_locked"?: string | null; + "external_urls.spotify"?: Json | null; + fanId?: string | null; + "fanId.country"?: string | null; + "fanId.display_name"?: string | null; + "fanId.email"?: string | null; + "fanId.explicit_content.filter_enabled"?: string | null; + "fanId.explicit_content.filter_locked"?: string | null; + "fanId.external_urls.spotify"?: string | null; + "fanId.followers.total"?: string | null; + "fanId.href"?: string | null; + "fanId.id"?: string | null; + "fanId.images"?: string | null; + "fanId.isNewFan"?: string | null; + "fanId.playlist"?: string | null; + "fanId.presavedData.clientId"?: string | null; + "fanId.presavedData.country"?: string | null; + "fanId.presavedData.display_name"?: string | null; + "fanId.presavedData.email"?: string | null; + "fanId.presavedData.explicit_content.filter_enabled"?: string | null; + "fanId.presavedData.explicit_content.filter_locked"?: string | null; + "fanId.presavedData.external_urls.spotify"?: string | null; + "fanId.presavedData.followers.total"?: string | null; + "fanId.presavedData.href"?: string | null; + "fanId.presavedData.id"?: string | null; + "fanId.presavedData.images"?: string | null; + "fanId.presavedData.playlist"?: string | null; + "fanId.presavedData.product"?: string | null; + "fanId.presavedData.recentlyPlayed"?: string | null; + "fanId.presavedData.timestamp"?: string | null; + "fanId.presavedData.type"?: string | null; + "fanId.presavedData.uri"?: string | null; + "fanId.product"?: string | null; + "fanId.timestamp"?: string | null; + "fanId.type"?: string | null; + "fanId.uri"?: string | null; + "followers.total"?: Json | null; + game?: string | null; + href?: string | null; + id?: string | null; + images?: Json | null; + playlist?: Json | null; + product?: string | null; + syncId?: string | null; + timestamp?: string | null; + type?: string | null; + uri?: string | null; + }; + Update: { + clientId?: string | null; + country?: string | null; + display_name?: string | null; + email?: string | null; + "explicit_content.filter_enabled"?: string | null; + "explicit_content.filter_locked"?: string | null; + "external_urls.spotify"?: Json | null; + fanId?: string | null; + "fanId.country"?: string | null; + "fanId.display_name"?: string | null; + "fanId.email"?: string | null; + "fanId.explicit_content.filter_enabled"?: string | null; + "fanId.explicit_content.filter_locked"?: string | null; + "fanId.external_urls.spotify"?: string | null; + "fanId.followers.total"?: string | null; + "fanId.href"?: string | null; + "fanId.id"?: string | null; + "fanId.images"?: string | null; + "fanId.isNewFan"?: string | null; + "fanId.playlist"?: string | null; + "fanId.presavedData.clientId"?: string | null; + "fanId.presavedData.country"?: string | null; + "fanId.presavedData.display_name"?: string | null; + "fanId.presavedData.email"?: string | null; + "fanId.presavedData.explicit_content.filter_enabled"?: string | null; + "fanId.presavedData.explicit_content.filter_locked"?: string | null; + "fanId.presavedData.external_urls.spotify"?: string | null; + "fanId.presavedData.followers.total"?: string | null; + "fanId.presavedData.href"?: string | null; + "fanId.presavedData.id"?: string | null; + "fanId.presavedData.images"?: string | null; + "fanId.presavedData.playlist"?: string | null; + "fanId.presavedData.product"?: string | null; + "fanId.presavedData.recentlyPlayed"?: string | null; + "fanId.presavedData.timestamp"?: string | null; + "fanId.presavedData.type"?: string | null; + "fanId.presavedData.uri"?: string | null; + "fanId.product"?: string | null; + "fanId.timestamp"?: string | null; + "fanId.type"?: string | null; + "fanId.uri"?: string | null; + "followers.total"?: Json | null; + game?: string | null; + href?: string | null; + id?: string | null; + images?: Json | null; + playlist?: Json | null; + product?: string | null; + syncId?: string | null; + timestamp?: string | null; + type?: string | null; + uri?: string | null; + }; + Relationships: []; + }; spotify_albums: { Row: { - id: string - name: string | null - release_date: string | null - updated_at: string - uri: string - } - Insert: { - id?: string - name?: string | null - release_date?: string | null - updated_at?: string - uri: string - } - Update: { - id?: string - name?: string | null - release_date?: string | null - updated_at?: string - uri?: string - } - Relationships: [] - } + id: string; + name: string | null; + release_date: string | null; + updated_at: string; + uri: string; + }; + Insert: { + id?: string; + name?: string | null; + release_date?: string | null; + updated_at?: string; + uri: string; + }; + Update: { + id?: string; + name?: string | null; + release_date?: string | null; + updated_at?: string; + uri?: string; + }; + Relationships: []; + }; spotify_analytics_albums: { Row: { - analysis_id: string | null - artist_name: string | null - created_at: string - id: string - name: string | null - release_date: number | null - uri: string | null - } - Insert: { - analysis_id?: string | null - artist_name?: string | null - created_at?: string - id?: string - name?: string | null - release_date?: number | null - uri?: string | null - } - Update: { - analysis_id?: string | null - artist_name?: string | null - created_at?: string - id?: string - name?: string | null - release_date?: number | null - uri?: string | null - } + analysis_id: string | null; + artist_name: string | null; + created_at: string; + id: string; + name: string | null; + release_date: number | null; + uri: string | null; + }; + Insert: { + analysis_id?: string | null; + artist_name?: string | null; + created_at?: string; + id?: string; + name?: string | null; + release_date?: number | null; + uri?: string | null; + }; + Update: { + analysis_id?: string | null; + artist_name?: string | null; + created_at?: string; + id?: string; + name?: string | null; + release_date?: number | null; + uri?: string | null; + }; Relationships: [ { - foreignKeyName: "spotify_analytics_albums_analysis_id_fkey" - columns: ["analysis_id"] - isOneToOne: false - referencedRelation: "funnel_analytics" - referencedColumns: ["id"] + foreignKeyName: "spotify_analytics_albums_analysis_id_fkey"; + columns: ["analysis_id"]; + isOneToOne: false; + referencedRelation: "funnel_analytics"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; spotify_analytics_tracks: { Row: { - analysis_id: string | null - artist_name: string | null - created_at: string - id: string - name: string | null - popularity: number | null - uri: string | null - } - Insert: { - analysis_id?: string | null - artist_name?: string | null - created_at?: string - id?: string - name?: string | null - popularity?: number | null - uri?: string | null - } - Update: { - analysis_id?: string | null - artist_name?: string | null - created_at?: string - id?: string - name?: string | null - popularity?: number | null - uri?: string | null - } + analysis_id: string | null; + artist_name: string | null; + created_at: string; + id: string; + name: string | null; + popularity: number | null; + uri: string | null; + }; + Insert: { + analysis_id?: string | null; + artist_name?: string | null; + created_at?: string; + id?: string; + name?: string | null; + popularity?: number | null; + uri?: string | null; + }; + Update: { + analysis_id?: string | null; + artist_name?: string | null; + created_at?: string; + id?: string; + name?: string | null; + popularity?: number | null; + uri?: string | null; + }; Relationships: [ { - foreignKeyName: "spotify_analytics_tracks_analysis_id_fkey" - columns: ["analysis_id"] - isOneToOne: false - referencedRelation: "funnel_analytics" - referencedColumns: ["id"] + foreignKeyName: "spotify_analytics_tracks_analysis_id_fkey"; + columns: ["analysis_id"]; + isOneToOne: false; + referencedRelation: "funnel_analytics"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; spotify_login_button_clicked: { Row: { - campaignId: string | null - clientId: string | null - fanId: string | null - game: string | null - id: string | null - timestamp: number | null - } - Insert: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: number | null - } - Update: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string | null - timestamp?: number | null - } + campaignId: string | null; + clientId: string | null; + fanId: string | null; + game: string | null; + id: string | null; + timestamp: number | null; + }; + Insert: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; + Update: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string | null; + timestamp?: number | null; + }; Relationships: [ { - foreignKeyName: "spotify_login_button_clicked_campaignId_fkey" - columns: ["campaignId"] - isOneToOne: false - referencedRelation: "campaigns" - referencedColumns: ["id"] + foreignKeyName: "spotify_login_button_clicked_campaignId_fkey"; + columns: ["campaignId"]; + isOneToOne: false; + referencedRelation: "campaigns"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; spotify_play_button_clicked: { Row: { - campaignId: string | null - clientId: string | null - fanId: string | null - game: string | null - id: string - isPremium: boolean | null - timestamp: number | null - } - Insert: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string - isPremium?: boolean | null - timestamp?: number | null - } - Update: { - campaignId?: string | null - clientId?: string | null - fanId?: string | null - game?: string | null - id?: string - isPremium?: boolean | null - timestamp?: number | null - } + campaignId: string | null; + clientId: string | null; + fanId: string | null; + game: string | null; + id: string; + isPremium: boolean | null; + timestamp: number | null; + }; + Insert: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string; + isPremium?: boolean | null; + timestamp?: number | null; + }; + Update: { + campaignId?: string | null; + clientId?: string | null; + fanId?: string | null; + game?: string | null; + id?: string; + isPremium?: boolean | null; + timestamp?: number | null; + }; Relationships: [ { - foreignKeyName: "spotify_play_button_clicked_campaignId_fkey" - columns: ["campaignId"] - isOneToOne: false - referencedRelation: "campaigns" - referencedColumns: ["id"] + foreignKeyName: "spotify_play_button_clicked_campaignId_fkey"; + columns: ["campaignId"]; + isOneToOne: false; + referencedRelation: "campaigns"; + referencedColumns: ["id"]; }, { - foreignKeyName: "spotify_play_button_clicked_fanId_fkey" - columns: ["fanId"] - isOneToOne: false - referencedRelation: "fans" - referencedColumns: ["id"] + foreignKeyName: "spotify_play_button_clicked_fanId_fkey"; + columns: ["fanId"]; + isOneToOne: false; + referencedRelation: "fans"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; spotify_tracks: { Row: { - id: string - name: string | null - popularity: number | null - updated_at: string - uri: string - } - Insert: { - id?: string - name?: string | null - popularity?: number | null - updated_at?: string - uri: string - } - Update: { - id?: string - name?: string | null - popularity?: number | null - updated_at?: string - uri?: string - } - Relationships: [] - } + id: string; + name: string | null; + popularity: number | null; + updated_at: string; + uri: string; + }; + Insert: { + id?: string; + name?: string | null; + popularity?: number | null; + updated_at?: string; + uri: string; + }; + Update: { + id?: string; + name?: string | null; + popularity?: number | null; + updated_at?: string; + uri?: string; + }; + Relationships: []; + }; subscription_items: { Row: { - created_at: string - id: string - interval: string - interval_count: number - price_amount: number | null - product_id: string - quantity: number - subscription_id: string - type: Database["public"]["Enums"]["subscription_item_type"] - updated_at: string - variant_id: string - } - Insert: { - created_at?: string - id: string - interval: string - interval_count: number - price_amount?: number | null - product_id: string - quantity?: number - subscription_id: string - type: Database["public"]["Enums"]["subscription_item_type"] - updated_at?: string - variant_id: string - } - Update: { - created_at?: string - id?: string - interval?: string - interval_count?: number - price_amount?: number | null - product_id?: string - quantity?: number - subscription_id?: string - type?: Database["public"]["Enums"]["subscription_item_type"] - updated_at?: string - variant_id?: string - } + created_at: string; + id: string; + interval: string; + interval_count: number; + price_amount: number | null; + product_id: string; + quantity: number; + subscription_id: string; + type: Database["public"]["Enums"]["subscription_item_type"]; + updated_at: string; + variant_id: string; + }; + Insert: { + created_at?: string; + id: string; + interval: string; + interval_count: number; + price_amount?: number | null; + product_id: string; + quantity?: number; + subscription_id: string; + type: Database["public"]["Enums"]["subscription_item_type"]; + updated_at?: string; + variant_id: string; + }; + Update: { + created_at?: string; + id?: string; + interval?: string; + interval_count?: number; + price_amount?: number | null; + product_id?: string; + quantity?: number; + subscription_id?: string; + type?: Database["public"]["Enums"]["subscription_item_type"]; + updated_at?: string; + variant_id?: string; + }; Relationships: [ { - foreignKeyName: "subscription_items_subscription_id_fkey" - columns: ["subscription_id"] - isOneToOne: false - referencedRelation: "subscriptions" - referencedColumns: ["id"] + foreignKeyName: "subscription_items_subscription_id_fkey"; + columns: ["subscription_id"]; + isOneToOne: false; + referencedRelation: "subscriptions"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; subscriptions: { Row: { - account_id: string - active: boolean - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - cancel_at_period_end: boolean - created_at: string - currency: string - id: string - period_ends_at: string - period_starts_at: string - status: Database["public"]["Enums"]["subscription_status"] - trial_ends_at: string | null - trial_starts_at: string | null - updated_at: string - } - Insert: { - account_id: string - active: boolean - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - cancel_at_period_end: boolean - created_at?: string - currency: string - id: string - period_ends_at: string - period_starts_at: string - status: Database["public"]["Enums"]["subscription_status"] - trial_ends_at?: string | null - trial_starts_at?: string | null - updated_at?: string - } - Update: { - account_id?: string - active?: boolean - billing_customer_id?: number - billing_provider?: Database["public"]["Enums"]["billing_provider"] - cancel_at_period_end?: boolean - created_at?: string - currency?: string - id?: string - period_ends_at?: string - period_starts_at?: string - status?: Database["public"]["Enums"]["subscription_status"] - trial_ends_at?: string | null - trial_starts_at?: string | null - updated_at?: string - } + account_id: string; + active: boolean; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + cancel_at_period_end: boolean; + created_at: string; + currency: string; + id: string; + period_ends_at: string; + period_starts_at: string; + status: Database["public"]["Enums"]["subscription_status"]; + trial_ends_at: string | null; + trial_starts_at: string | null; + updated_at: string; + }; + Insert: { + account_id: string; + active: boolean; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + cancel_at_period_end: boolean; + created_at?: string; + currency: string; + id: string; + period_ends_at: string; + period_starts_at: string; + status: Database["public"]["Enums"]["subscription_status"]; + trial_ends_at?: string | null; + trial_starts_at?: string | null; + updated_at?: string; + }; + Update: { + account_id?: string; + active?: boolean; + billing_customer_id?: number; + billing_provider?: Database["public"]["Enums"]["billing_provider"]; + cancel_at_period_end?: boolean; + created_at?: string; + currency?: string; + id?: string; + period_ends_at?: string; + period_starts_at?: string; + status?: Database["public"]["Enums"]["subscription_status"]; + trial_ends_at?: string | null; + trial_starts_at?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "subscriptions_billing_customer_id_fkey" - columns: ["billing_customer_id"] - isOneToOne: false - referencedRelation: "billing_customers" - referencedColumns: ["id"] + foreignKeyName: "subscriptions_billing_customer_id_fkey"; + columns: ["billing_customer_id"]; + isOneToOne: false; + referencedRelation: "billing_customers"; + referencedColumns: ["id"]; }, - ] - } + ]; + }; tasks: { Row: { - account_id: string - created_at: string - description: string | null - done: boolean - id: string - title: string - updated_at: string - } - Insert: { - account_id: string - created_at?: string - description?: string | null - done?: boolean - id?: string - title: string - updated_at?: string - } - Update: { - account_id?: string - created_at?: string - description?: string | null - done?: boolean - id?: string - title?: string - updated_at?: string - } - Relationships: [] - } + account_id: string; + created_at: string; + description: string | null; + done: boolean; + id: string; + title: string; + updated_at: string; + }; + Insert: { + account_id: string; + created_at?: string; + description?: string | null; + done?: boolean; + id?: string; + title: string; + updated_at?: string; + }; + Update: { + account_id?: string; + created_at?: string; + description?: string | null; + done?: boolean; + id?: string; + title?: string; + updated_at?: string; + }; + Relationships: []; + }; test_emails: { Row: { - created_at: string - email: string | null - id: number - } - Insert: { - created_at?: string - email?: string | null - id?: number - } - Update: { - created_at?: string - email?: string | null - id?: number - } - Relationships: [] - } + created_at: string; + email: string | null; + id: number; + }; + Insert: { + created_at?: string; + email?: string | null; + id?: number; + }; + Update: { + created_at?: string; + email?: string | null; + id?: number; + }; + Relationships: []; + }; youtube_tokens: { Row: { - access_token: string - artist_account_id: string - created_at: string - expires_at: string - id: string - refresh_token: string | null - updated_at: string - } - Insert: { - access_token: string - artist_account_id: string - created_at?: string - expires_at: string - id?: string - refresh_token?: string | null - updated_at?: string - } - Update: { - access_token?: string - artist_account_id?: string - created_at?: string - expires_at?: string - id?: string - refresh_token?: string | null - updated_at?: string - } + access_token: string; + artist_account_id: string; + created_at: string; + expires_at: string; + id: string; + refresh_token: string | null; + updated_at: string; + }; + Insert: { + access_token: string; + artist_account_id: string; + created_at?: string; + expires_at: string; + id?: string; + refresh_token?: string | null; + updated_at?: string; + }; + Update: { + access_token?: string; + artist_account_id?: string; + created_at?: string; + expires_at?: string; + id?: string; + refresh_token?: string | null; + updated_at?: string; + }; Relationships: [ { - foreignKeyName: "youtube_tokens_artist_account_id_fkey" - columns: ["artist_account_id"] - isOneToOne: true - referencedRelation: "accounts" - referencedColumns: ["id"] + foreignKeyName: "youtube_tokens_artist_account_id_fkey"; + columns: ["artist_account_id"]; + isOneToOne: true; + referencedRelation: "accounts"; + referencedColumns: ["id"]; }, - ] - } - } + ]; + }; + }; Views: { - [_ in never]: never - } + [_ in never]: never; + }; Functions: { accept_invitation: { - Args: { token: string; user_id: string } - Returns: string - } + Args: { token: string; user_id: string }; + Returns: string; + }; add_invitations_to_account: { Args: { - account_slug: string - invitations: Database["public"]["CompositeTypes"]["invitation"][] - } - Returns: Database["public"]["Tables"]["invitations"]["Row"][] - } + account_slug: string; + invitations: Database["public"]["CompositeTypes"]["invitation"][]; + }; + Returns: Database["public"]["Tables"]["invitations"]["Row"][]; + }; can_action_account_member: { - Args: { target_team_account_id: string; target_user_id: string } - Returns: boolean - } + Args: { target_team_account_id: string; target_user_id: string }; + Returns: boolean; + }; count_reports_by_day: { - Args: { end_date: string; start_date: string } + Args: { end_date: string; start_date: string }; Returns: { - count: number - date_key: string - }[] - } + count: number; + date_key: string; + }[]; + }; count_reports_by_month: { - Args: { end_date: string; start_date: string } + Args: { end_date: string; start_date: string }; Returns: { - count: number - date_key: string - }[] - } + count: number; + date_key: string; + }[]; + }; count_reports_by_week: { - Args: { end_date: string; start_date: string } + Args: { end_date: string; start_date: string }; Returns: { - count: number - date_key: string - }[] - } + count: number; + date_key: string; + }[]; + }; create_invitation: { - Args: { account_id: string; email: string; role: string } + Args: { account_id: string; email: string; role: string }; Returns: { - account_id: string - created_at: string - email: string - expires_at: string - id: number - invite_token: string - invited_by: string - role: string - updated_at: string - } + account_id: string; + created_at: string; + email: string; + expires_at: string; + id: number; + invite_token: string; + invited_by: string; + role: string; + updated_at: string; + }; SetofOptions: { - from: "*" - to: "invitations" - isOneToOne: true - isSetofReturn: false - } - } + from: "*"; + to: "invitations"; + isOneToOne: true; + isSetofReturn: false; + }; + }; deduct_credits: { - Args: { account_id: string; amount: number } - Returns: undefined - } - extract_domain: { Args: { email: string }; Returns: string } + Args: { account_id: string; amount: number }; + Returns: undefined; + }; + extract_domain: { Args: { email: string }; Returns: string }; get_account_invitations: { - Args: { account_slug: string } + Args: { account_slug: string }; Returns: { - account_id: string - created_at: string - email: string - expires_at: string - id: number - invited_by: string - inviter_email: string - inviter_name: string - role: string - updated_at: string - }[] - } + account_id: string; + created_at: string; + email: string; + expires_at: string; + id: number; + invited_by: string; + inviter_email: string; + inviter_name: string; + role: string; + updated_at: string; + }[]; + }; get_account_members: { - Args: { account_slug: string } + Args: { account_slug: string }; Returns: { - account_id: string - created_at: string - email: string - id: string - name: string - picture_url: string - primary_owner_user_id: string - role: string - role_hierarchy_level: number - updated_at: string - user_id: string - }[] - } + account_id: string; + created_at: string; + email: string; + id: string; + name: string; + picture_url: string; + primary_owner_user_id: string; + role: string; + role_hierarchy_level: number; + updated_at: string; + user_id: string; + }[]; + }; get_campaign: | { Args: { clientid: string }; Returns: Json } | { - Args: { artistid: string; campaignid: string; email: string } - Returns: Json - } + Args: { artistid: string; campaignid: string; email: string }; + Returns: Json; + }; get_campaign_fans: { - Args: { artistid: string; email: string } - Returns: Json - } - get_config: { Args: never; Returns: Json } + Args: { artistid: string; email: string }; + Returns: Json; + }; + get_config: { Args: never; Returns: Json }; get_fans_listening_top_songs: { - Args: { artistid: string; email: string } - Returns: Json - } + Args: { artistid: string; email: string }; + Returns: Json; + }; get_message_counts_by_user: | { - Args: { start_date: string } + Args: { start_date: string }; Returns: { - account_email: string - message_count: number - }[] + account_email: string; + message_count: number; + }[]; } | { - Args: { end_date: string; start_date: string } + Args: { end_date: string; start_date: string }; Returns: { - account_email: string - message_count: number - }[] - } + account_email: string; + message_count: number; + }[]; + }; get_rooms_created_by_user: { - Args: { start_date: string } + Args: { start_date: string }; Returns: { - account_email: string - rooms_created: number - }[] - } + account_email: string; + rooms_created: number; + }[]; + }; get_segment_reports_by_user: { - Args: { start_date: string } + Args: { start_date: string }; Returns: { - email: string - segment_report_count: number - }[] - } - get_upper_system_role: { Args: never; Returns: string } + email: string; + segment_report_count: number; + }[]; + }; + get_upper_system_role: { Args: never; Returns: string }; has_active_subscription: { - Args: { target_account_id: string } - Returns: boolean - } - has_credits: { Args: { account_id: string }; Returns: boolean } + Args: { target_account_id: string }; + Returns: boolean; + }; + has_credits: { Args: { account_id: string }; Returns: boolean }; has_more_elevated_role: { Args: { - role_name: string - target_account_id: string - target_user_id: string - } - Returns: boolean - } + role_name: string; + target_account_id: string; + target_user_id: string; + }; + Returns: boolean; + }; has_permission: { Args: { - account_id: string - permission_name: Database["public"]["Enums"]["app_permissions"] - user_id: string - } - Returns: boolean - } + account_id: string; + permission_name: Database["public"]["Enums"]["app_permissions"]; + user_id: string; + }; + Returns: boolean; + }; has_role_on_account: { - Args: { account_id: string; account_role?: string } - Returns: boolean - } + Args: { account_id: string; account_role?: string }; + Returns: boolean; + }; has_same_role_hierarchy_level: { Args: { - role_name: string - target_account_id: string - target_user_id: string - } - Returns: boolean - } - is_account_owner: { Args: { account_id: string }; Returns: boolean } + role_name: string; + target_account_id: string; + target_user_id: string; + }; + Returns: boolean; + }; + is_account_owner: { Args: { account_id: string }; Returns: boolean }; is_account_team_member: { - Args: { target_account_id: string } - Returns: boolean - } - is_set: { Args: { field_name: string }; Returns: boolean } + Args: { target_account_id: string }; + Returns: boolean; + }; + is_set: { Args: { field_name: string }; Returns: boolean }; is_team_member: { - Args: { account_id: string; user_id: string } - Returns: boolean - } + Args: { account_id: string; user_id: string }; + Returns: boolean; + }; team_account_workspace: { - Args: { account_slug: string } + Args: { account_slug: string }; Returns: { - id: string - name: string - permissions: Database["public"]["Enums"]["app_permissions"][] - picture_url: string - primary_owner_user_id: string - role: string - role_hierarchy_level: number - slug: string - subscription_status: Database["public"]["Enums"]["subscription_status"] - }[] - } + id: string; + name: string; + permissions: Database["public"]["Enums"]["app_permissions"][]; + picture_url: string; + primary_owner_user_id: string; + role: string; + role_hierarchy_level: number; + slug: string; + subscription_status: Database["public"]["Enums"]["subscription_status"]; + }[]; + }; transfer_team_account_ownership: { - Args: { new_owner_id: string; target_account_id: string } - Returns: undefined - } + Args: { new_owner_id: string; target_account_id: string }; + Returns: undefined; + }; upsert_order: { Args: { - billing_provider: Database["public"]["Enums"]["billing_provider"] - currency: string - line_items: Json - status: Database["public"]["Enums"]["payment_status"] - target_account_id: string - target_customer_id: string - target_order_id: string - total_amount: number - } + billing_provider: Database["public"]["Enums"]["billing_provider"]; + currency: string; + line_items: Json; + status: Database["public"]["Enums"]["payment_status"]; + target_account_id: string; + target_customer_id: string; + target_order_id: string; + total_amount: number; + }; Returns: { - account_id: string - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - created_at: string - currency: string - id: string - status: Database["public"]["Enums"]["payment_status"] - total_amount: number - updated_at: string - } + account_id: string; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + created_at: string; + currency: string; + id: string; + status: Database["public"]["Enums"]["payment_status"]; + total_amount: number; + updated_at: string; + }; SetofOptions: { - from: "*" - to: "orders" - isOneToOne: true - isSetofReturn: false - } - } + from: "*"; + to: "orders"; + isOneToOne: true; + isSetofReturn: false; + }; + }; upsert_subscription: { Args: { - active: boolean - billing_provider: Database["public"]["Enums"]["billing_provider"] - cancel_at_period_end: boolean - currency: string - line_items: Json - period_ends_at: string - period_starts_at: string - status: Database["public"]["Enums"]["subscription_status"] - target_account_id: string - target_customer_id: string - target_subscription_id: string - trial_ends_at?: string - trial_starts_at?: string - } + active: boolean; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + cancel_at_period_end: boolean; + currency: string; + line_items: Json; + period_ends_at: string; + period_starts_at: string; + status: Database["public"]["Enums"]["subscription_status"]; + target_account_id: string; + target_customer_id: string; + target_subscription_id: string; + trial_ends_at?: string; + trial_starts_at?: string; + }; Returns: { - account_id: string - active: boolean - billing_customer_id: number - billing_provider: Database["public"]["Enums"]["billing_provider"] - cancel_at_period_end: boolean - created_at: string - currency: string - id: string - period_ends_at: string - period_starts_at: string - status: Database["public"]["Enums"]["subscription_status"] - trial_ends_at: string | null - trial_starts_at: string | null - updated_at: string - } + account_id: string; + active: boolean; + billing_customer_id: number; + billing_provider: Database["public"]["Enums"]["billing_provider"]; + cancel_at_period_end: boolean; + created_at: string; + currency: string; + id: string; + period_ends_at: string; + period_starts_at: string; + status: Database["public"]["Enums"]["subscription_status"]; + trial_ends_at: string | null; + trial_starts_at: string | null; + updated_at: string; + }; SetofOptions: { - from: "*" - to: "subscriptions" - isOneToOne: true - isSetofReturn: false - } - } - } + from: "*"; + to: "subscriptions"; + isOneToOne: true; + isSetofReturn: false; + }; + }; + }; Enums: { app_permissions: | "roles.manage" @@ -3872,20 +3866,14 @@ export type Database = { | "members.manage" | "invites.manage" | "tasks.write" - | "tasks.delete" - billing_provider: "stripe" | "lemon-squeezy" | "paddle" - chat_role: "user" | "assistant" - notification_channel: "in_app" | "email" - notification_type: "info" | "warning" | "error" - payment_status: "pending" | "succeeded" | "failed" - social_type: - | "TIKTOK" - | "YOUTUBE" - | "INSTAGRAM" - | "TWITTER" - | "SPOTIFY" - | "APPLE" - subscription_item_type: "flat" | "per_seat" | "metered" + | "tasks.delete"; + billing_provider: "stripe" | "lemon-squeezy" | "paddle"; + chat_role: "user" | "assistant"; + notification_channel: "in_app" | "email"; + notification_type: "info" | "warning" | "error"; + payment_status: "pending" | "succeeded" | "failed"; + social_type: "TIKTOK" | "YOUTUBE" | "INSTAGRAM" | "TWITTER" | "SPOTIFY" | "APPLE"; + subscription_item_type: "flat" | "per_seat" | "metered"; subscription_status: | "active" | "trialing" @@ -3894,133 +3882,131 @@ export type Database = { | "unpaid" | "incomplete" | "incomplete_expired" - | "paused" - } + | "paused"; + }; CompositeTypes: { invitation: { - email: string | null - role: string | null - } - } - } -} + email: string | null; + role: string | null; + }; + }; + }; +}; -type DatabaseWithoutInternals = Omit +type DatabaseWithoutInternals = Omit; -type DefaultSchema = DatabaseWithoutInternals[Extract] +type DefaultSchema = DatabaseWithoutInternals[Extract]; export type Tables< DefaultSchemaTableNameOrOptions extends | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R + Row: infer R; } ? R : never - : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & - DefaultSchema["Views"]) - ? (DefaultSchema["Tables"] & - DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { - Row: infer R + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R; } ? R : never - : never + : never; export type TablesInsert< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I + Insert: infer I; } ? I : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Insert: infer I + Insert: infer I; } ? I : never - : never + : never; export type TablesUpdate< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U + Update: infer U; } ? U : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Update: infer U + Update: infer U; } ? U : never - : never + : never; export type Enums< DefaultSchemaEnumNameOrOptions extends | keyof DefaultSchema["Enums"] | { schema: keyof DatabaseWithoutInternals }, EnumName extends DefaultSchemaEnumNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] : never = never, > = DefaultSchemaEnumNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] - : never + : never; export type CompositeTypes< PublicCompositeTypeNameOrOptions extends | keyof DefaultSchema["CompositeTypes"] | { schema: keyof DatabaseWithoutInternals }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] : never = never, > = PublicCompositeTypeNameOrOptions extends { - schema: keyof DatabaseWithoutInternals + schema: keyof DatabaseWithoutInternals; } ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] - : never + : never; export const Constants = { public: { @@ -4039,14 +4025,7 @@ export const Constants = { notification_channel: ["in_app", "email"], notification_type: ["info", "warning", "error"], payment_status: ["pending", "succeeded", "failed"], - social_type: [ - "TIKTOK", - "YOUTUBE", - "INSTAGRAM", - "TWITTER", - "SPOTIFY", - "APPLE", - ], + social_type: ["TIKTOK", "YOUTUBE", "INSTAGRAM", "TWITTER", "SPOTIFY", "APPLE"], subscription_item_type: ["flat", "per_seat", "metered"], subscription_status: [ "active", @@ -4060,4 +4039,4 @@ export const Constants = { ], }, }, -} as const +} as const;