mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
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.
95 lines
2.9 KiB
TypeScript
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);
|
|
}
|
|
}
|