Fix Vercel API breaking change (#1883)
Fixes https://github.com/dyad-sh/dyad/issues/1652 This is kind of a hack because the Vercel SDK has a bug since their API has subtly made a breaking change in the last month or so and the Vercel SDK still hasn't been updated https://github.com/vercel/sdk/issues/175#issuecomment-3608968116 Note: the Vercel SDK upgrade in this PR doesn't actually fix the issue, but is probably good to do anyways. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Works around a breaking change in Vercel’s API by bypassing the SDK for project queries. Restores listing, availability checks, and project linking. - **Bug Fixes** - Added a direct HTTP call to GET /v9/projects using the Vercel token. - Replaced SDK calls in list, name availability, and connect-to-project flows. - Added minimal types and clearer error handling for project responses. - **Dependencies** - Bumped @vercel/sdk to 1.18.0. The upgrade doesn’t fix the bug but is safe to adopt. <sup>Written for commit 306af5c3f235f0ab9d87c809bb8cf54016a5d59f. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces Vercel project retrieval with a direct HTTP helper used across handlers to handle API changes, and updates @vercel/sdk to ^1.18.0. > > - **IPC/Backend (Vercel)**: > - Add `getVercelProjects` helper to fetch projects via `GET /v9/projects`, mimicking `vercel.projects.getProjects`. > - Update handlers to use the new helper: > - `vercel:list-projects` (`handleListVercelProjects`) > - `vercel:is-project-available` (`handleIsProjectAvailable`) > - `vercel:connect-existing-project` (`handleConnectToExistingProject`) > - Add lightweight types: `VercelProjectResponse`, `GetVercelProjectsResponse`. > - **Dependencies**: > - Bump `@vercel/sdk` to `^1.18.0`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 306af5c3f235f0ab9d87c809bb8cf54016a5d59f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This commit is contained in:
@@ -42,6 +42,54 @@ function createVercelClient(token: string): Vercel {
|
||||
});
|
||||
}
|
||||
|
||||
interface VercelProjectResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
framework?: string | null;
|
||||
targets?: {
|
||||
production?: {
|
||||
url?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface GetVercelProjectsResponse {
|
||||
projects: VercelProjectResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch Vercel projects via HTTP request (bypasses the broken SDK).
|
||||
* Mimics the SDK's `vercel.projects.getProjects` API.
|
||||
*/
|
||||
async function getVercelProjects(
|
||||
token: string,
|
||||
options?: { search?: string },
|
||||
): Promise<GetVercelProjectsResponse> {
|
||||
const url = new URL(`${VERCEL_API_BASE}/v9/projects`);
|
||||
if (options?.search) {
|
||||
url.searchParams.set("search", options.search);
|
||||
}
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(
|
||||
`Failed to fetch Vercel projects: ${response.status} ${response.statusText} - ${errorText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
projects: data.projects || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function validateVercelToken(token: string): Promise<boolean> {
|
||||
try {
|
||||
const vercel = createVercelClient(token);
|
||||
@@ -184,8 +232,7 @@ async function handleListVercelProjects(): Promise<VercelProject[]> {
|
||||
throw new Error("Not authenticated with Vercel.");
|
||||
}
|
||||
|
||||
const vercel = createVercelClient(accessToken);
|
||||
const response = await vercel.projects.getProjects({});
|
||||
const response = await getVercelProjects(accessToken);
|
||||
|
||||
if (!response.projects) {
|
||||
throw new Error("Failed to retrieve projects from Vercel.");
|
||||
@@ -214,12 +261,8 @@ async function handleIsProjectAvailable(
|
||||
return { available: false, error: "Not authenticated with Vercel." };
|
||||
}
|
||||
|
||||
const vercel = createVercelClient(accessToken);
|
||||
|
||||
// Check if project name is available by searching for projects with that name
|
||||
const response = await vercel.projects.getProjects({
|
||||
search: name,
|
||||
});
|
||||
const response = await getVercelProjects(accessToken, { search: name });
|
||||
|
||||
if (!response.projects) {
|
||||
return {
|
||||
@@ -361,10 +404,8 @@ async function handleConnectToExistingProject(
|
||||
`Connecting to existing Vercel project: ${projectId} for app ${appId}`,
|
||||
);
|
||||
|
||||
const vercel = createVercelClient(accessToken);
|
||||
|
||||
// Verify the project exists and get its details
|
||||
const response = await vercel.projects.getProjects({});
|
||||
const response = await getVercelProjects(accessToken);
|
||||
const projectData = response.projects?.find(
|
||||
(p) => p.id === projectId || p.name === projectId,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user