Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Format Check

on:
pull_request:
branches: [main, test]

jobs:
format:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Install dependencies
run: pnpm install

- name: Check formatting
run: pnpm format:check
6 changes: 1 addition & 5 deletions app/api/accounts/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ export async function OPTIONS() {
* @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);
}

13 changes: 3 additions & 10 deletions app/api/admins/sandboxes/__tests__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand Down
13 changes: 3 additions & 10 deletions app/api/admins/sandboxes/orgs/__tests__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { NextRequest, NextResponse } from "next/server";

const mockGetAdminSandboxOrgsHandler = vi.fn();
vi.mock("@/lib/admins/sandboxes/getAdminSandboxOrgsHandler", () => ({
getAdminSandboxOrgsHandler: (...args: unknown[]) =>
mockGetAdminSandboxOrgsHandler(...args),
getAdminSandboxOrgsHandler: (...args: unknown[]) => mockGetAdminSandboxOrgsHandler(...args),
}));

const { GET, OPTIONS } = await import("../route");
Expand All @@ -15,10 +14,7 @@ beforeEach(() => {

describe("GET /api/admins/sandboxes/orgs", () => {
it("delegates to getAdminSandboxOrgsHandler and returns its response", async () => {
const expected = NextResponse.json(
{ status: "success", repos: [] },
{ status: 200 },
);
const expected = NextResponse.json({ status: "success", repos: [] }, { status: 200 });
mockGetAdminSandboxOrgsHandler.mockResolvedValue(expected);

const request = new NextRequest("https://example.com/api/admins/sandboxes/orgs");
Expand Down Expand Up @@ -89,10 +85,7 @@ describe("GET /api/admins/sandboxes/orgs", () => {

it("returns 500 when handler returns internal error", async () => {
mockGetAdminSandboxOrgsHandler.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/orgs");
Expand Down
1 change: 0 additions & 1 deletion app/api/artists/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,3 @@ export async function GET(request: NextRequest) {
export async function POST(request: NextRequest) {
return createArtistPostHandler(request);
}

4 changes: 1 addition & 3 deletions app/api/coding-agent/callback/__tests__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
1 change: 0 additions & 1 deletion app/api/content/create/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";
export const revalidate = 0;

1 change: 0 additions & 1 deletion app/api/content/estimate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise<NextResponse> {
export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";
export const revalidate = 0;

1 change: 0 additions & 1 deletion app/api/content/templates/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise<NextResponse> {
export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";
export const revalidate = 0;

1 change: 0 additions & 1 deletion app/api/content/validate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ export async function GET(request: NextRequest): Promise<NextResponse> {
export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";
export const revalidate = 0;

1 change: 0 additions & 1 deletion app/api/organizations/artists/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ export async function OPTIONS() {
export async function POST(request: NextRequest) {
return addArtistToOrgHandler(request);
}

1 change: 0 additions & 1 deletion app/api/spotify/artist/albums/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ export async function OPTIONS() {
export async function GET(request: NextRequest) {
return getSpotifyArtistAlbumsHandler(request);
}

1 change: 0 additions & 1 deletion app/api/transcribe/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,3 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: message }, { status });
}
}

5 changes: 1 addition & 4 deletions evals/catalog-songs-count.eval.ts
Original file line number Diff line number Diff line change
@@ -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";

/**
Expand Down
12 changes: 4 additions & 8 deletions evals/first-week-album-sales.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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: {
Expand All @@ -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: {
Expand All @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion evals/memory-tools.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {},
})) || [];
Expand Down
2 changes: 1 addition & 1 deletion evals/monthly-listeners-tracking.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
9 changes: 3 additions & 6 deletions evals/search-web-tool.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
8 changes: 3 additions & 5 deletions evals/social-scraping.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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: {},
})) || [];
Expand Down
5 changes: 2 additions & 3 deletions evals/spotify-tools.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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: {},
})) || [];
Expand Down
6 changes: 2 additions & 4 deletions evals/tiktok-analytics-questions.eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
1 change: 0 additions & 1 deletion lib/accounts/getAccountHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ export async function getAccountHandler(
);
}
}

1 change: 0 additions & 1 deletion lib/accounts/validateAccountParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ export function validateAccountParams(id: string): NextResponse | AccountParams

return result.data;
}

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ describe("validateGetAdminEmailsQuery", () => {
});

it("prefers email_id when both provided", async () => {
const request = createMockRequest("http://localhost:3000/api/admins/emails?account_id=acc-123&email_id=email-abc");
const request = createMockRequest(
"http://localhost:3000/api/admins/emails?account_id=acc-123&email_id=email-abc",
);
const result = await validateGetAdminEmailsQuery(request);

expect(result).not.toBeInstanceOf(NextResponse);
Expand Down Expand Up @@ -74,7 +76,9 @@ describe("validateGetAdminEmailsQuery", () => {
});

it("trims whitespace from params", async () => {
const request = createMockRequest("http://localhost:3000/api/admins/emails?email_id=%20email-abc%20");
const request = createMockRequest(
"http://localhost:3000/api/admins/emails?email_id=%20email-abc%20",
);
const result = await validateGetAdminEmailsQuery(request);

expect(result).toEqual({ mode: "email", emailId: "email-abc" });
Expand Down
10 changes: 3 additions & 7 deletions lib/admins/emails/getAccountEmailIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ import { listResendEmails } from "@/lib/emails/listResendEmails";
* @param accountId - The account ID to look up emails for
* @returns Array of Resend email ID strings
*/
export async function getAccountEmailIds(
accountId: string,
): Promise<string[]> {
export async function getAccountEmailIds(accountId: string): Promise<string[]> {
const emailRows = await selectAccountEmails({ accountIds: accountId });
const accountEmail = emailRows.find((r) => r.email)?.email;
const accountEmail = emailRows.find(r => r.email)?.email;

if (!accountEmail) return [];

const emails = await listResendEmails();

return emails
.filter((email) => email.to.includes(accountEmail))
.map((email) => email.id);
return emails.filter(email => email.to.includes(accountEmail)).map(email => email.id);
}
8 changes: 2 additions & 6 deletions lib/admins/emails/getAdminEmailsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,9 @@ export async function getAdminEmailsHandler(request: NextRequest): Promise<NextR
);
}

const emails = await Promise.all(
emailIds.map((id) => fetchResendEmail(id)),
);
const emails = await Promise.all(emailIds.map(id => fetchResendEmail(id)));

const validEmails = emails.filter(
(e): e is GetEmailResponseSuccess => e !== null,
);
const validEmails = emails.filter((e): e is GetEmailResponseSuccess => e !== null);

return NextResponse.json(
{ status: "success", emails: validEmails },
Expand Down
Loading
Loading