bolt.diy/app/lib/stores/vercel.ts
KevIsDev 687b03ba74 feat: add Vercel integration for project deployment
This commit introduces Vercel integration, enabling users to deploy projects directly to Vercel. It includes:
- New Vercel types and store for managing connections and stats.
- A VercelConnection component for managing Vercel account connections.
- A VercelDeploymentLink component for displaying deployment links.
- API routes for handling Vercel deployments.
- Updates to the HeaderActionButtons component to support Vercel deployment.

The integration allows users to connect their Vercel accounts, view project stats, and deploy projects with ease.
2025-03-27 00:06:10 +00:00

95 lines
2.9 KiB
TypeScript

import { atom } from 'nanostores';
import type { VercelConnection } from '~/types/vercel';
import { logStore } from './logs';
import { toast } from 'react-toastify';
// Initialize with stored connection or defaults
const storedConnection = typeof window !== 'undefined' ? localStorage.getItem('vercel_connection') : null;
const initialConnection: VercelConnection = storedConnection
? JSON.parse(storedConnection)
: {
user: null,
token: '',
stats: undefined,
};
export const vercelConnection = atom<VercelConnection>(initialConnection);
export const isConnecting = atom<boolean>(false);
export const isFetchingStats = atom<boolean>(false);
export const updateVercelConnection = (updates: Partial<VercelConnection>) => {
const currentState = vercelConnection.get();
const newState = { ...currentState, ...updates };
vercelConnection.set(newState);
// Persist to localStorage
if (typeof window !== 'undefined') {
localStorage.setItem('vercel_connection', JSON.stringify(newState));
}
};
export async function fetchVercelStats(token: string) {
try {
isFetchingStats.set(true);
const projectsResponse = await fetch('https://api.vercel.com/v9/projects', {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
if (!projectsResponse.ok) {
throw new Error(`Failed to fetch projects: ${projectsResponse.status}`);
}
const projectsData = (await projectsResponse.json()) as any;
const projects = projectsData.projects || [];
// Fetch latest deployment for each project
const projectsWithDeployments = await Promise.all(
projects.map(async (project: any) => {
try {
const deploymentsResponse = await fetch(
`https://api.vercel.com/v6/deployments?projectId=${project.id}&limit=1`,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);
if (deploymentsResponse.ok) {
const deploymentsData = (await deploymentsResponse.json()) as any;
return {
...project,
latestDeployments: deploymentsData.deployments || [],
};
}
return project;
} catch (error) {
console.error(`Error fetching deployments for project ${project.id}:`, error);
return project;
}
}),
);
const currentState = vercelConnection.get();
updateVercelConnection({
...currentState,
stats: {
projects: projectsWithDeployments,
totalProjects: projectsWithDeployments.length,
},
});
} catch (error) {
console.error('Vercel API Error:', error);
logStore.logError('Failed to fetch Vercel stats', { error });
toast.error('Failed to fetch Vercel statistics');
} finally {
isFetchingStats.set(false);
}
}