Skip to content
Open
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
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,16 @@ You have two options for running Bolt.DIY: directly on your machine or using Doc
```bash
pnpm run dev
```



To run the application with a custom base path (for example, `/bolt`), use:

```bash
VITE_BASE_PATH=/bolt pnpm run dev
```

Replace `/bolt` with your desired base path if needed. This sets the frontend route base path.

### Option 2: Using Docker

This option requires some familiarity with Docker but provides a more isolated environment.
Expand Down Expand Up @@ -378,7 +387,7 @@ This method is recommended for developers who want to:
Hint: Be aware that this can have beta-features and more likely got bugs than the stable release

>**Open the WebUI to test (Default: http://localhost:5173)**
> - Beginners:
> - Beginners:
> - Try to use a sophisticated Provider/Model like Anthropic with Claude Sonnet 3.x Models to get best results
> - Explanation: The System Prompt currently implemented in bolt.diy cant cover the best performance for all providers and models out there. So it works better with some models, then other, even if the models itself are perfect for >programming
> - Future: Planned is a Plugin/Extentions-Library so there can be different System Prompts for different Models, which will help to get better results
Expand All @@ -396,7 +405,7 @@ To get the latest changes from the repository:
2. **Pull Latest Updates**:

```bash
git pull
git pull
```

3. **Update Dependencies**:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ export function GitLabRepositorySelector({ onClone, className }: GitLabRepositor
setError(null);

try {
const response = await fetch('/api/gitlab-projects', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/gitlab-projects`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
5 changes: 4 additions & 1 deletion app/components/@settings/tabs/supabase/SupabaseTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ export default function SupabaseTab() {
});

try {
const response = await fetch('/api/supabase-user', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/supabase-user`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Expand Down
7 changes: 4 additions & 3 deletions app/components/chat/APIKeyManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ export const APIKeyManager: React.FC<APIKeyManagerProps> = ({ provider, apiKey,
}

try {
const response = await fetch(`/api/check-env-key?provider=${encodeURIComponent(provider.name)}`);
const basePath = import.meta.env.VITE_BASE_PATH || '/';
const response = await fetch(`${basePath}/api/check-env-key?provider=${encodeURIComponent(provider.name)}`);
const data = await response.json();
const isSet = (data as { isSet: boolean }).isSet;

Expand Down Expand Up @@ -121,8 +122,8 @@ export const APIKeyManager: React.FC<APIKeyManagerProps> = ({ provider, apiKey,
value={tempKey}
placeholder="Enter API Key"
onChange={(e) => setTempKey(e.target.value)}
className="w-[300px] px-3 py-1.5 text-sm rounded border border-bolt-elements-borderColor
bg-bolt-elements-prompt-background text-bolt-elements-textPrimary
className="w-[300px] px-3 py-1.5 text-sm rounded border border-bolt-elements-borderColor
bg-bolt-elements-prompt-background text-bolt-elements-textPrimary
focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus"
/>
<IconButton
Expand Down
10 changes: 8 additions & 2 deletions app/components/chat/BaseChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,11 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
}

setIsModelLoading('all');
fetch('/api/models')

const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/models`.replace(/\/+/g, '/');
fetch(apiUrl)
.then((response) => response.json())
.then((data) => {
const typedData = data as { modelList: ModelInfo[] };
Expand All @@ -237,7 +241,9 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
let providerModels: ModelInfo[] = [];

try {
const response = await fetch(`/api/models/${encodeURIComponent(providerName)}`);
const response = await fetch(
`${import.meta.env.VITE_BASE_PATH || ''}/api/models/${encodeURIComponent(providerName)}`,
);
const data = await response.json();
providerModels = (data as { modelList: ModelInfo[] }).modelList;
} catch (error) {
Expand Down
4 changes: 3 additions & 1 deletion app/components/chat/Chat.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ export const ChatImpl = memo(
const [selectedElement, setSelectedElement] = useState<ElementInfo | null>(null);
const mcpSettings = useMCPStore((state) => state.settings);

const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const {
messages,
isLoading,
Expand All @@ -165,7 +167,7 @@ export const ChatImpl = memo(
setData,
addToolResult,
} = useChat({
api: '/api/chat',
api: `${basePath}/api/chat`.replace(/\/+/g, '/'),
body: {
apiKeys,
files,
Expand Down
5 changes: 4 additions & 1 deletion app/components/chat/SupabaseAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ export function SupabaseChatAlert({ alert, clearAlert, postMessage }: Props) {
setIsExecuting(true);

try {
const response = await fetch('/api/supabase/query', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/supabase/query`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
5 changes: 4 additions & 1 deletion app/components/deploy/NetlifyDeploy.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ export function useNetlifyDeploy() {
// Use chatId instead of artifact.id
const existingSiteId = localStorage.getItem(`netlify-site-${currentChatId}`);

const response = await fetch('/api/netlify-deploy', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/netlify-deploy`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
5 changes: 4 additions & 1 deletion app/components/deploy/VercelDeploy.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ export function useVercelDeploy() {
// Use chatId instead of artifact.id
const existingProjectId = localStorage.getItem(`vercel-project-${currentChatId}`);

const response = await fetch('/api/vercel-deploy', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/vercel-deploy`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
11 changes: 8 additions & 3 deletions app/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import { ChatDescription } from '~/lib/persistence/ChatDescription.client';
export function Header() {
const chat = useStore(chatStore);

// Ensure asset URLs always start with a leading slash
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const assetUrl = (file: string) => `${basePath}/${file}`.replace(/\/+/g, '/');

return (
<header
className={classNames('flex items-center px-4 border-b h-[var(--header-height)]', {
Expand All @@ -17,10 +22,10 @@ export function Header() {
>
<div className="flex items-center gap-2 z-logo text-bolt-elements-textPrimary cursor-pointer">
<div className="i-ph:sidebar-simple-duotone text-xl" />
<a href="/" className="text-2xl font-semibold text-accent flex items-center">
<a href={basePath || '/'} className="text-2xl font-semibold text-accent flex items-center">
{/* <span className="i-bolt:logo-text?mask w-[46px] inline-block" /> */}
<img src="/logo-light-styled.png" alt="logo" className="w-[90px] inline-block dark:hidden" />
<img src="/logo-dark-styled.png" alt="logo" className="w-[90px] inline-block hidden dark:block" />
<img src={assetUrl('logo-light-styled.png')} alt="logo" className="w-[90px] inline-block dark:hidden" />
<img src={assetUrl('logo-dark-styled.png')} alt="logo" className="w-[90px] inline-block hidden dark:block" />
</a>
</div>
{chat.started && ( // Display ChatDescription and HeaderActionButtons only when the chat has started.
Expand Down
7 changes: 5 additions & 2 deletions app/components/ui/BranchSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export function BranchSelector({
let response: Response;

if (provider === 'github') {
response = await fetch('/api/github-branches', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/github-branches`.replace(/\/+/g, '/');
response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Expand All @@ -70,7 +73,7 @@ export function BranchSelector({
throw new Error('Project ID is required for GitLab repositories');
}

response = await fetch('/api/gitlab-branches', {
response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/gitlab-branches`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Expand Down
7 changes: 4 additions & 3 deletions app/lib/api/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ export const checkConnection = async (): Promise<ConnectionStatus> => {
}

// Try multiple endpoints in case one fails
const BASE_PATH = (import.meta.env.VITE_BASE_PATH || '').replace(/\/$/, '');
const endpoints = [
'/api/health',
'/', // Fallback to root route
'/favicon.ico', // Another common fallback
`${BASE_PATH}/api/health`.replace(/\/+/g, '/'),
`${BASE_PATH}/`, // Fallback to root route
`${BASE_PATH}/favicon.ico`, // Another common fallback
];

let latency = 0;
Expand Down
2 changes: 1 addition & 1 deletion app/lib/hooks/useGitHubConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export function useGitHubConnection(): UseGitHubConnectionReturn {
const isServerSide = !connection.token;

if (isServerSide) {
const response = await fetch('/api/github-user');
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/github-user`);
return response.ok;
}

Expand Down
5 changes: 4 additions & 1 deletion app/lib/hooks/usePromptEnhancer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ export function usePromptEnhancer() {
requestBody.apiKeys = apiKeys;
}

const response = await fetch('/api/enhancer', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/enhancer`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestBody),
});
Expand Down
5 changes: 4 additions & 1 deletion app/lib/hooks/useSupabaseConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ export function useSupabaseConnection() {
try {
const cleanToken = connection.token.trim();

const response = await fetch('/api/supabase', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/supabase`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
2 changes: 1 addition & 1 deletion app/lib/stores/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export async function fetchGitHubStatsViaAPI() {
try {
isFetchingStats.set(true);

const response = await fetch('/api/github-user', {
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/github-user`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
7 changes: 5 additions & 2 deletions app/lib/stores/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const useMCPStore = create<Store & Actions>((set, get) => ({
}
},
checkServersAvailabilities: async () => {
const response = await fetch('/api/mcp-check', {
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/mcp-check`, {
method: 'GET',
});

Expand All @@ -99,7 +99,10 @@ export const useMCPStore = create<Store & Actions>((set, get) => ({
}));

async function updateServerConfig(config: MCPConfig) {
const response = await fetch('/api/mcp-update-config', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/mcp-update-config`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(config),
Expand Down
4 changes: 2 additions & 2 deletions app/lib/stores/supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export async function fetchSupabaseStats(token: string) {

try {
// Use the internal API route instead of direct Supabase API call
const response = await fetch('/api/supabase', {
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/supabase`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down Expand Up @@ -183,7 +183,7 @@ export async function fetchProjectApiKeys(projectId: string, token: string) {
isFetchingApiKeys.set(true);

try {
const response = await fetch('/api/supabase/variables', {
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/supabase/variables`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
6 changes: 5 additions & 1 deletion app/lib/webcontainer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ if (!import.meta.env.SSR) {

const { workbenchStore } = await import('~/lib/stores/workbench');

const response = await fetch('/inspector-script.js');
// Ensure asset URLs always start with a leading slash
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const assetUrl = (file: string) => `${basePath}/${file}`.replace(/\/+/g, '/');
const response = await fetch(assetUrl('inspector-script.js'));
const inspectorScript = await response.text();
await webcontainer.setPreviewScript(inspectorScript);

Expand Down
7 changes: 6 additions & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ import 'virtual:uno.css';
export const links: LinksFunction = () => [
{
rel: 'icon',
href: '/favicon.svg',
href: (() => {
const envBasePath = typeof window !== 'undefined' ? import.meta.env.VITE_BASE_PATH : process.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.endsWith('/') ? envBasePath : envBasePath + '/') : '/';

return `${basePath}favicon.svg`;
})(),
type: 'image/svg+xml',
},
{ rel: 'stylesheet', href: reactToastifyStyles },
Expand Down
2 changes: 1 addition & 1 deletion app/utils/debugLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ class DebugLogger {
private async _getGitInfo(): Promise<AppInfo['gitInfo']> {
try {
// Try to fetch git info from existing API endpoint
const response = await fetch('/api/system/git-info');
const response = await fetch(`${import.meta.env.VITE_BASE_PATH || ''}/api/system/git-info`);

if (response.ok) {
const gitInfo = await response.json();
Expand Down
11 changes: 8 additions & 3 deletions app/utils/selectStarterTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Instructions:
5. If no perfect match exists, recommend the closest option

Important: Provide only the selection tags in your response, no additional text.
MOST IMPORTANT: YOU DONT HAVE TIME TO THINK JUST START RESPONDING BASED ON HUNCH
MOST IMPORTANT: YOU DONT HAVE TIME TO THINK JUST START RESPONDING BASED ON HUNCH
`;

const templates: Template[] = STARTER_TEMPLATES.filter((t) => !t.name.includes('shadcn'));
Expand Down Expand Up @@ -90,7 +90,10 @@ export const selectStarterTemplate = async (options: { message: string; model: s
provider,
system: starterTemplateSelectionPrompt(templates),
};
const response = await fetch('/api/llmcall', {
const envBasePath = import.meta.env.VITE_BASE_PATH;
const basePath = envBasePath ? (envBasePath.startsWith('/') ? envBasePath : '/' + envBasePath) : '';
const apiUrl = `${basePath}/api/llmcall`.replace(/\/+/g, '/');
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestBody),
});
Expand All @@ -115,7 +118,9 @@ export const selectStarterTemplate = async (options: { message: string; model: s
const getGitHubRepoContent = async (repoName: string): Promise<{ name: string; path: string; content: string }[]> => {
try {
// Instead of directly fetching from GitHub, use our own API endpoint as a proxy
const response = await fetch(`/api/github-template?repo=${encodeURIComponent(repoName)}`);
const response = await fetch(
`${import.meta.env.VITE_BASE_PATH || ''}/api/github-template?repo=${encodeURIComponent(repoName)}`,
);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
Expand Down
4 changes: 3 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dotenv.config();

export default defineConfig((config) => {
return {
base: process.env.VITE_BASE_PATH || '/',
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
},
Expand Down Expand Up @@ -45,6 +46,7 @@ export default defineConfig((config) => {
},
config.mode !== 'test' && remixCloudflareDevProxy(),
remixVitePlugin({
basename: process.env.VITE_BASE_PATH || '/',
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
Expand Down Expand Up @@ -109,4 +111,4 @@ function chrome129IssuePlugin() {
});
},
};
}
}
Loading