Compare commits
12 Commits
437d110e37
...
9d8c4055ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d8c4055ca | ||
|
|
3f6050b227 | ||
|
|
5f925566c4 | ||
|
|
983b3025a5 | ||
|
|
49850d9253 | ||
|
|
1a55bd5866 | ||
|
|
f138b9c088 | ||
|
|
4e37f5a80c | ||
|
|
d34852c227 | ||
|
|
cb3c536c5d | ||
|
|
b32c4081ec | ||
|
|
583dfbda53 |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -74,7 +74,7 @@ jobs:
|
|||||||
- name: Validate Docker production build
|
- name: Validate Docker production build
|
||||||
run: |
|
run: |
|
||||||
echo "🐳 Testing Docker production target..."
|
echo "🐳 Testing Docker production target..."
|
||||||
docker build --target runtime . --no-cache --progress=plain
|
docker build --target bolt-ai-production . --no-cache --progress=plain
|
||||||
echo "✅ Production target builds successfully"
|
echo "✅ Production target builds successfully"
|
||||||
|
|
||||||
- name: Validate Docker development build
|
- name: Validate Docker development build
|
||||||
|
|||||||
2
.github/workflows/docker.yaml
vendored
2
.github/workflows/docker.yaml
vendored
@@ -57,7 +57,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
target: runtime
|
target: bolt-ai-production
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|||||||
83
Dockerfile
83
Dockerfile
@@ -9,6 +9,10 @@ ENV CI=true
|
|||||||
# Use pnpm
|
# Use pnpm
|
||||||
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate
|
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate
|
||||||
|
|
||||||
|
# Ensure git is available for build and runtime scripts
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Accept (optional) build-time public URL for Remix/Vite (Coolify can pass it)
|
# Accept (optional) build-time public URL for Remix/Vite (Coolify can pass it)
|
||||||
ARG VITE_PUBLIC_APP_URL
|
ARG VITE_PUBLIC_APP_URL
|
||||||
ENV VITE_PUBLIC_APP_URL=${VITE_PUBLIC_APP_URL}
|
ENV VITE_PUBLIC_APP_URL=${VITE_PUBLIC_APP_URL}
|
||||||
@@ -25,68 +29,75 @@ RUN pnpm install --offline --frozen-lockfile
|
|||||||
# Build the Remix app (SSR + client)
|
# Build the Remix app (SSR + client)
|
||||||
RUN NODE_OPTIONS=--max-old-space-size=4096 pnpm run build
|
RUN NODE_OPTIONS=--max-old-space-size=4096 pnpm run build
|
||||||
|
|
||||||
|
# ---- production dependencies stage ----
|
||||||
|
FROM build AS prod-deps
|
||||||
|
|
||||||
# Keep only production deps for runtime
|
# Keep only production deps for runtime
|
||||||
RUN pnpm prune --prod --ignore-scripts
|
RUN pnpm prune --prod --ignore-scripts
|
||||||
|
|
||||||
|
|
||||||
# ---- runtime stage ----
|
# ---- production stage ----
|
||||||
FROM node:22-bookworm-slim AS runtime
|
FROM prod-deps AS bolt-ai-production
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV PORT=3000
|
ENV PORT=5173
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
|
|
||||||
# Install curl so Coolify’s healthcheck works inside the image
|
# Non-sensitive build arguments
|
||||||
|
ARG VITE_LOG_LEVEL=debug
|
||||||
|
ARG DEFAULT_NUM_CTX
|
||||||
|
|
||||||
|
# Set non-sensitive environment variables
|
||||||
|
ENV WRANGLER_SEND_METRICS=false \
|
||||||
|
VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \
|
||||||
|
DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} \
|
||||||
|
RUNNING_IN_DOCKER=true
|
||||||
|
|
||||||
|
# Note: API keys should be provided at runtime via docker run -e or docker-compose
|
||||||
|
# Example: docker run -e OPENAI_API_KEY=your_key_here ...
|
||||||
|
|
||||||
|
# Install curl for healthchecks and copy bindings script
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends curl \
|
RUN apt-get update && apt-get install -y --no-install-recommends curl \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Copy only what we need to run
|
# Copy built files and scripts
|
||||||
COPY --from=build /app/build /app/build
|
COPY --from=prod-deps /app/build /app/build
|
||||||
COPY --from=build /app/node_modules /app/node_modules
|
COPY --from=prod-deps /app/node_modules /app/node_modules
|
||||||
COPY --from=build /app/package.json /app/package.json
|
COPY --from=prod-deps /app/package.json /app/package.json
|
||||||
|
COPY --from=prod-deps /app/bindings.sh /app/bindings.sh
|
||||||
|
|
||||||
EXPOSE 3000
|
# Pre-configure wrangler to disable metrics
|
||||||
|
RUN mkdir -p /root/.config/.wrangler && \
|
||||||
|
echo '{"enabled":false}' > /root/.config/.wrangler/metrics.json
|
||||||
|
|
||||||
# Healthcheck for Coolify
|
# Make bindings script executable
|
||||||
|
RUN chmod +x /app/bindings.sh
|
||||||
|
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
# Healthcheck for deployment platforms
|
||||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=5 \
|
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=5 \
|
||||||
CMD curl -fsS http://localhost:3000/ || exit 1
|
CMD curl -fsS http://localhost:5173/ || exit 1
|
||||||
|
|
||||||
# Start the Remix server
|
# Start using dockerstart script with Wrangler
|
||||||
CMD ["node", "build/server/index.js"]
|
CMD ["pnpm", "run", "dockerstart"]
|
||||||
|
|
||||||
|
|
||||||
# ---- development stage ----
|
# ---- development stage ----
|
||||||
FROM build AS development
|
FROM build AS development
|
||||||
|
|
||||||
# Define environment variables for development
|
# Non-sensitive development arguments
|
||||||
ARG GROQ_API_KEY
|
|
||||||
ARG HuggingFace_API_KEY
|
|
||||||
ARG OPENAI_API_KEY
|
|
||||||
ARG ANTHROPIC_API_KEY
|
|
||||||
ARG OPEN_ROUTER_API_KEY
|
|
||||||
ARG GOOGLE_GENERATIVE_AI_API_KEY
|
|
||||||
ARG OLLAMA_API_BASE_URL
|
|
||||||
ARG XAI_API_KEY
|
|
||||||
ARG TOGETHER_API_KEY
|
|
||||||
ARG TOGETHER_API_BASE_URL
|
|
||||||
ARG VITE_LOG_LEVEL=debug
|
ARG VITE_LOG_LEVEL=debug
|
||||||
ARG DEFAULT_NUM_CTX
|
ARG DEFAULT_NUM_CTX
|
||||||
|
|
||||||
ENV GROQ_API_KEY=${GROQ_API_KEY} \
|
# Set non-sensitive environment variables for development
|
||||||
HuggingFace_API_KEY=${HuggingFace_API_KEY} \
|
ENV VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \
|
||||||
OPENAI_API_KEY=${OPENAI_API_KEY} \
|
|
||||||
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
|
|
||||||
OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} \
|
|
||||||
GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} \
|
|
||||||
OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} \
|
|
||||||
XAI_API_KEY=${XAI_API_KEY} \
|
|
||||||
TOGETHER_API_KEY=${TOGETHER_API_KEY} \
|
|
||||||
TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \
|
|
||||||
AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \
|
|
||||||
VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \
|
|
||||||
DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} \
|
DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} \
|
||||||
RUNNING_IN_DOCKER=true
|
RUNNING_IN_DOCKER=true
|
||||||
|
|
||||||
|
# Note: API keys should be provided at runtime via docker run -e or docker-compose
|
||||||
|
# Example: docker run -e OPENAI_API_KEY=your_key_here ...
|
||||||
|
|
||||||
RUN mkdir -p /app/run
|
RUN mkdir -p /app/run
|
||||||
CMD ["pnpm", "run", "dev", "--host"]
|
CMD ["pnpm", "run", "dev", "--host"]
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -154,29 +154,52 @@ You have two options for running Bolt.DIY: directly on your machine or using Doc
|
|||||||
|
|
||||||
### Option 2: Using Docker
|
### Option 2: Using Docker
|
||||||
|
|
||||||
This option requires some familiarity with Docker but provides a more isolated environment.
|
This option requires Docker and is great when you want an isolated environment or to mirror the production image.
|
||||||
|
|
||||||
#### Additional Prerequisite
|
#### Additional Prerequisite
|
||||||
|
|
||||||
- Install Docker: [Download Docker](https://www.docker.com/)
|
- Install Docker: [Download Docker](https://www.docker.com/)
|
||||||
|
|
||||||
#### Steps:
|
#### Steps
|
||||||
|
|
||||||
1. **Build the Docker Image**:
|
1. **Prepare Environment Variables**
|
||||||
|
|
||||||
|
Copy the provided examples and add your provider keys:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using npm script:
|
cp .env.example .env
|
||||||
npm run dockerbuild
|
cp .env.example .env.local
|
||||||
|
|
||||||
# OR using direct Docker command:
|
|
||||||
docker build . --target bolt-ai-development
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Run the Container**:
|
The runtime scripts inside the container source `.env` and `.env.local`, so keep any API keys you need in one of those files.
|
||||||
|
|
||||||
|
2. **Build an Image**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Development image (bind-mounts your local source when run)
|
||||||
|
pnpm run dockerbuild
|
||||||
|
# ≈ docker build -t bolt-ai:development -t bolt-ai:latest --target development .
|
||||||
|
|
||||||
|
# Production image (self-contained build artifacts)
|
||||||
|
pnpm run dockerbuild:prod
|
||||||
|
# ≈ docker build -t bolt-ai:production -t bolt-ai:latest --target bolt-ai-production .
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Run the Container**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development workflow with hot reload
|
||||||
docker compose --profile development up
|
docker compose --profile development up
|
||||||
|
|
||||||
|
# Production-style container using composed services
|
||||||
|
docker compose --profile production up
|
||||||
|
|
||||||
|
# One-off production container (exposes the app on port 5173)
|
||||||
|
docker run --rm -p 5173:5173 --env-file .env.local bolt-ai:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When the container starts it runs `pnpm run dockerstart`, which in turn executes `bindings.sh` to pass Cloudflare bindings through Wrangler. You can override this command in `docker-compose.yaml` if you need a different startup routine.
|
||||||
|
|
||||||
### Option 3: Desktop Application (Electron)
|
### Option 3: Desktop Application (Electron)
|
||||||
|
|
||||||
For users who prefer a native desktop experience, bolt.diy is also available as an Electron desktop application:
|
For users who prefer a native desktop experience, bolt.diy is also available as an Electron desktop application:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Message } from 'ai';
|
|||||||
import { useChat } from '@ai-sdk/react';
|
import { useChat } from '@ai-sdk/react';
|
||||||
import { useAnimate } from 'framer-motion';
|
import { useAnimate } from 'framer-motion';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useMessageParser, usePromptEnhancer, useShortcuts } from '~/lib/hooks';
|
import { useMessageParser, usePromptEnhancer, useShortcuts } from '~/lib/hooks';
|
||||||
import { description, useChatHistory } from '~/lib/persistence';
|
import { description, useChatHistory } from '~/lib/persistence';
|
||||||
import { chatStore } from '~/lib/stores/chat';
|
import { chatStore } from '~/lib/stores/chat';
|
||||||
@@ -29,11 +29,6 @@ import type { TextUIPart, FileUIPart, Attachment } from '@ai-sdk/ui-utils';
|
|||||||
import { useMCPStore } from '~/lib/stores/mcp';
|
import { useMCPStore } from '~/lib/stores/mcp';
|
||||||
import type { LlmErrorAlertType } from '~/types/actions';
|
import type { LlmErrorAlertType } from '~/types/actions';
|
||||||
|
|
||||||
const toastAnimation = cssTransition({
|
|
||||||
enter: 'animated fadeInRight',
|
|
||||||
exit: 'animated fadeOutRight',
|
|
||||||
});
|
|
||||||
|
|
||||||
const logger = createScopedLogger('Chat');
|
const logger = createScopedLogger('Chat');
|
||||||
|
|
||||||
export function Chat() {
|
export function Chat() {
|
||||||
@@ -56,34 +51,6 @@ export function Chat() {
|
|||||||
importChat={importChat}
|
importChat={importChat}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ToastContainer
|
|
||||||
closeButton={({ closeToast }) => {
|
|
||||||
return (
|
|
||||||
<button className="Toastify__close-button" onClick={closeToast}>
|
|
||||||
<div className="i-ph:x text-lg" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
icon={({ type }) => {
|
|
||||||
/**
|
|
||||||
* @todo Handle more types if we need them. This may require extra color palettes.
|
|
||||||
*/
|
|
||||||
switch (type) {
|
|
||||||
case 'success': {
|
|
||||||
return <div className="i-ph:check-bold text-bolt-elements-icon-success text-2xl" />;
|
|
||||||
}
|
|
||||||
case 'error': {
|
|
||||||
return <div className="i-ph:warning-circle-bold text-bolt-elements-icon-error text-2xl" />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}}
|
|
||||||
position="bottom-right"
|
|
||||||
pauseOnFocusLoss
|
|
||||||
transition={toastAnimation}
|
|
||||||
autoClose={3000}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ export function useGitHubDeploy() {
|
|||||||
source: 'github',
|
source: 'github',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 GitHub deployment preparation completed successfully!`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
files: fileContents,
|
files: fileContents,
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ export function useGitLabDeploy() {
|
|||||||
source: 'gitlab',
|
source: 'gitlab',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 GitLab deployment preparation completed successfully!`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
files: fileContents,
|
files: fileContents,
|
||||||
|
|||||||
@@ -224,6 +224,9 @@ export function useNetlifyDeploy() {
|
|||||||
source: 'netlify',
|
source: 'netlify',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 Netlify deployment completed successfully!`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Deploy error:', error);
|
console.error('Deploy error:', error);
|
||||||
|
|||||||
@@ -213,6 +213,9 @@ export function useVercelDeploy() {
|
|||||||
source: 'vercel',
|
source: 'vercel',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show success toast notification
|
||||||
|
toast.success(`🚀 Vercel deployment completed successfully!`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Vercel deploy error:', err);
|
console.error('Vercel deploy error:', err);
|
||||||
|
|||||||
@@ -20,20 +20,21 @@ const PREVIEW_CHANNEL = 'preview-updates';
|
|||||||
export class PreviewsStore {
|
export class PreviewsStore {
|
||||||
#availablePreviews = new Map<number, PreviewInfo>();
|
#availablePreviews = new Map<number, PreviewInfo>();
|
||||||
#webcontainer: Promise<WebContainer>;
|
#webcontainer: Promise<WebContainer>;
|
||||||
#broadcastChannel: BroadcastChannel;
|
#broadcastChannel?: BroadcastChannel;
|
||||||
#lastUpdate = new Map<string, number>();
|
#lastUpdate = new Map<string, number>();
|
||||||
#watchedFiles = new Set<string>();
|
#watchedFiles = new Set<string>();
|
||||||
#refreshTimeouts = new Map<string, NodeJS.Timeout>();
|
#refreshTimeouts = new Map<string, NodeJS.Timeout>();
|
||||||
#REFRESH_DELAY = 300;
|
#REFRESH_DELAY = 300;
|
||||||
#storageChannel: BroadcastChannel;
|
#storageChannel?: BroadcastChannel;
|
||||||
|
|
||||||
previews = atom<PreviewInfo[]>([]);
|
previews = atom<PreviewInfo[]>([]);
|
||||||
|
|
||||||
constructor(webcontainerPromise: Promise<WebContainer>) {
|
constructor(webcontainerPromise: Promise<WebContainer>) {
|
||||||
this.#webcontainer = webcontainerPromise;
|
this.#webcontainer = webcontainerPromise;
|
||||||
this.#broadcastChannel = new BroadcastChannel(PREVIEW_CHANNEL);
|
this.#broadcastChannel = this.#maybeCreateChannel(PREVIEW_CHANNEL);
|
||||||
this.#storageChannel = new BroadcastChannel('storage-sync-channel');
|
this.#storageChannel = this.#maybeCreateChannel('storage-sync-channel');
|
||||||
|
|
||||||
|
if (this.#broadcastChannel) {
|
||||||
// Listen for preview updates from other tabs
|
// Listen for preview updates from other tabs
|
||||||
this.#broadcastChannel.onmessage = (event) => {
|
this.#broadcastChannel.onmessage = (event) => {
|
||||||
const { type, previewId } = event.data;
|
const { type, previewId } = event.data;
|
||||||
@@ -48,7 +49,9 @@ export class PreviewsStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.#storageChannel) {
|
||||||
// Listen for storage sync messages
|
// Listen for storage sync messages
|
||||||
this.#storageChannel.onmessage = (event) => {
|
this.#storageChannel.onmessage = (event) => {
|
||||||
const { storage, source } = event.data;
|
const { storage, source } = event.data;
|
||||||
@@ -57,6 +60,7 @@ export class PreviewsStore {
|
|||||||
this._syncStorage(storage);
|
this._syncStorage(storage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Override localStorage setItem to catch all changes
|
// Override localStorage setItem to catch all changes
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@@ -71,6 +75,29 @@ export class PreviewsStore {
|
|||||||
this.#init();
|
this.#init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#maybeCreateChannel(name: string): BroadcastChannel | undefined {
|
||||||
|
if (typeof globalThis === 'undefined') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalBroadcastChannel = (
|
||||||
|
globalThis as typeof globalThis & {
|
||||||
|
BroadcastChannel?: typeof BroadcastChannel;
|
||||||
|
}
|
||||||
|
).BroadcastChannel;
|
||||||
|
|
||||||
|
if (typeof globalBroadcastChannel !== 'function') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new globalBroadcastChannel(name);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[Preview] BroadcastChannel unavailable:', error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a unique ID for this tab
|
// Generate a unique ID for this tab
|
||||||
private _getTabId(): string {
|
private _getTabId(): string {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@@ -130,7 +157,7 @@ export class PreviewsStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#storageChannel.postMessage({
|
this.#storageChannel?.postMessage({
|
||||||
type: 'storage-sync',
|
type: 'storage-sync',
|
||||||
storage,
|
storage,
|
||||||
source: this._getTabId(),
|
source: this._getTabId(),
|
||||||
@@ -192,7 +219,7 @@ export class PreviewsStore {
|
|||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
this.#lastUpdate.set(previewId, timestamp);
|
this.#lastUpdate.set(previewId, timestamp);
|
||||||
|
|
||||||
this.#broadcastChannel.postMessage({
|
this.#broadcastChannel?.postMessage({
|
||||||
type: 'state-change',
|
type: 'state-change',
|
||||||
previewId,
|
previewId,
|
||||||
timestamp,
|
timestamp,
|
||||||
@@ -204,7 +231,7 @@ export class PreviewsStore {
|
|||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
this.#lastUpdate.set(previewId, timestamp);
|
this.#lastUpdate.set(previewId, timestamp);
|
||||||
|
|
||||||
this.#broadcastChannel.postMessage({
|
this.#broadcastChannel?.postMessage({
|
||||||
type: 'file-change',
|
type: 'file-change',
|
||||||
previewId,
|
previewId,
|
||||||
timestamp,
|
timestamp,
|
||||||
@@ -219,7 +246,7 @@ export class PreviewsStore {
|
|||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
this.#lastUpdate.set(previewId, timestamp);
|
this.#lastUpdate.set(previewId, timestamp);
|
||||||
|
|
||||||
this.#broadcastChannel.postMessage({
|
this.#broadcastChannel?.postMessage({
|
||||||
type: 'file-change',
|
type: 'file-change',
|
||||||
previewId,
|
previewId,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
|||||||
@@ -52,11 +52,37 @@ export const shortcutsStore = map<Shortcuts>({
|
|||||||
|
|
||||||
// Create a single key for provider settings
|
// Create a single key for provider settings
|
||||||
const PROVIDER_SETTINGS_KEY = 'provider_settings';
|
const PROVIDER_SETTINGS_KEY = 'provider_settings';
|
||||||
|
const AUTO_ENABLED_KEY = 'auto_enabled_providers';
|
||||||
|
|
||||||
// Add this helper function at the top of the file
|
// Add this helper function at the top of the file
|
||||||
const isBrowser = typeof window !== 'undefined';
|
const isBrowser = typeof window !== 'undefined';
|
||||||
|
|
||||||
// Initialize provider settings from both localStorage and defaults
|
// Interface for configured provider info from server
|
||||||
|
interface ConfiguredProvider {
|
||||||
|
name: string;
|
||||||
|
isConfigured: boolean;
|
||||||
|
configMethod: 'environment' | 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch configured providers from server
|
||||||
|
const fetchConfiguredProviders = async (): Promise<ConfiguredProvider[]> => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/configured-providers');
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = (await response.json()) as { providers?: ConfiguredProvider[] };
|
||||||
|
|
||||||
|
return data.providers || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching configured providers:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize provider settings from both localStorage and server-detected configuration
|
||||||
const getInitialProviderSettings = (): ProviderSetting => {
|
const getInitialProviderSettings = (): ProviderSetting => {
|
||||||
const initialSettings: ProviderSetting = {};
|
const initialSettings: ProviderSetting = {};
|
||||||
|
|
||||||
@@ -92,8 +118,84 @@ const getInitialProviderSettings = (): ProviderSetting => {
|
|||||||
return initialSettings;
|
return initialSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Auto-enable providers that are configured on the server
|
||||||
|
const autoEnableConfiguredProviders = async () => {
|
||||||
|
if (!isBrowser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const configuredProviders = await fetchConfiguredProviders();
|
||||||
|
const currentSettings = providersStore.get();
|
||||||
|
const savedSettings = localStorage.getItem(PROVIDER_SETTINGS_KEY);
|
||||||
|
const autoEnabledProviders = localStorage.getItem(AUTO_ENABLED_KEY);
|
||||||
|
|
||||||
|
// Track which providers were auto-enabled to avoid overriding user preferences
|
||||||
|
const previouslyAutoEnabled = autoEnabledProviders ? JSON.parse(autoEnabledProviders) : [];
|
||||||
|
const newlyAutoEnabled: string[] = [];
|
||||||
|
|
||||||
|
let hasChanges = false;
|
||||||
|
|
||||||
|
configuredProviders.forEach(({ name, isConfigured, configMethod }) => {
|
||||||
|
if (isConfigured && configMethod === 'environment' && LOCAL_PROVIDERS.includes(name)) {
|
||||||
|
const currentProvider = currentSettings[name];
|
||||||
|
|
||||||
|
if (currentProvider) {
|
||||||
|
/*
|
||||||
|
* Only auto-enable if:
|
||||||
|
* 1. Provider is not already enabled, AND
|
||||||
|
* 2. Either we haven't saved settings yet (first time) OR provider was previously auto-enabled
|
||||||
|
*/
|
||||||
|
const hasUserSettings = savedSettings !== null;
|
||||||
|
const wasAutoEnabled = previouslyAutoEnabled.includes(name);
|
||||||
|
const shouldAutoEnable = !currentProvider.settings.enabled && (!hasUserSettings || wasAutoEnabled);
|
||||||
|
|
||||||
|
if (shouldAutoEnable) {
|
||||||
|
currentSettings[name] = {
|
||||||
|
...currentProvider,
|
||||||
|
settings: {
|
||||||
|
...currentProvider.settings,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
newlyAutoEnabled.push(name);
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasChanges) {
|
||||||
|
// Update the store
|
||||||
|
providersStore.set(currentSettings);
|
||||||
|
|
||||||
|
// Save to localStorage
|
||||||
|
localStorage.setItem(PROVIDER_SETTINGS_KEY, JSON.stringify(currentSettings));
|
||||||
|
|
||||||
|
// Update the auto-enabled providers list
|
||||||
|
const allAutoEnabled = [...new Set([...previouslyAutoEnabled, ...newlyAutoEnabled])];
|
||||||
|
localStorage.setItem(AUTO_ENABLED_KEY, JSON.stringify(allAutoEnabled));
|
||||||
|
|
||||||
|
console.log(`Auto-enabled providers: ${newlyAutoEnabled.join(', ')}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error auto-enabling configured providers:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const providersStore = map<ProviderSetting>(getInitialProviderSettings());
|
export const providersStore = map<ProviderSetting>(getInitialProviderSettings());
|
||||||
|
|
||||||
|
// Export the auto-enable function for use in components
|
||||||
|
export const initializeProviders = autoEnableConfiguredProviders;
|
||||||
|
|
||||||
|
// Initialize providers when the module loads (in browser only)
|
||||||
|
if (isBrowser) {
|
||||||
|
// Use a small delay to ensure DOM and other resources are ready
|
||||||
|
setTimeout(() => {
|
||||||
|
autoEnableConfiguredProviders();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a function to update provider settings that handles both store and persistence
|
// Create a function to update provider settings that handles both store and persistence
|
||||||
export const updateProviderSettings = (provider: string, settings: ProviderSetting) => {
|
export const updateProviderSettings = (provider: string, settings: ProviderSetting) => {
|
||||||
const currentSettings = providersStore.get();
|
const currentSettings = providersStore.get();
|
||||||
@@ -113,6 +215,37 @@ export const updateProviderSettings = (provider: string, settings: ProviderSetti
|
|||||||
// Save to localStorage
|
// Save to localStorage
|
||||||
const allSettings = providersStore.get();
|
const allSettings = providersStore.get();
|
||||||
localStorage.setItem(PROVIDER_SETTINGS_KEY, JSON.stringify(allSettings));
|
localStorage.setItem(PROVIDER_SETTINGS_KEY, JSON.stringify(allSettings));
|
||||||
|
|
||||||
|
// If this is a local provider, update the auto-enabled tracking
|
||||||
|
if (LOCAL_PROVIDERS.includes(provider) && updatedProvider.settings.enabled !== undefined) {
|
||||||
|
updateAutoEnabledTracking(provider, updatedProvider.settings.enabled);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update auto-enabled tracking when user manually changes provider settings
|
||||||
|
const updateAutoEnabledTracking = (providerName: string, isEnabled: boolean) => {
|
||||||
|
if (!isBrowser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const autoEnabledProviders = localStorage.getItem(AUTO_ENABLED_KEY);
|
||||||
|
const currentAutoEnabled = autoEnabledProviders ? JSON.parse(autoEnabledProviders) : [];
|
||||||
|
|
||||||
|
if (isEnabled) {
|
||||||
|
// If user enables provider, add to auto-enabled list (for future detection)
|
||||||
|
if (!currentAutoEnabled.includes(providerName)) {
|
||||||
|
currentAutoEnabled.push(providerName);
|
||||||
|
localStorage.setItem(AUTO_ENABLED_KEY, JSON.stringify(currentAutoEnabled));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If user disables provider, remove from auto-enabled list (respect user choice)
|
||||||
|
const updatedAutoEnabled = currentAutoEnabled.filter((name: string) => name !== providerName);
|
||||||
|
localStorage.setItem(AUTO_ENABLED_KEY, JSON.stringify(updatedAutoEnabled));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating auto-enabled tracking:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isDebugMode = atom(false);
|
export const isDebugMode = atom(false);
|
||||||
|
|||||||
@@ -51,8 +51,15 @@ export interface SupabaseConnectionState {
|
|||||||
credentials?: SupabaseCredentials;
|
credentials?: SupabaseCredentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
const savedConnection = typeof localStorage !== 'undefined' ? localStorage.getItem('supabase_connection') : null;
|
const storage =
|
||||||
const savedCredentials = typeof localStorage !== 'undefined' ? localStorage.getItem('supabaseCredentials') : null;
|
typeof globalThis !== 'undefined' &&
|
||||||
|
typeof globalThis.localStorage !== 'undefined' &&
|
||||||
|
typeof globalThis.localStorage.getItem === 'function'
|
||||||
|
? globalThis.localStorage
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const savedConnection = storage ? storage.getItem('supabase_connection') : null;
|
||||||
|
const savedCredentials = storage ? storage.getItem('supabaseCredentials') : null;
|
||||||
|
|
||||||
const initialState: SupabaseConnectionState = savedConnection
|
const initialState: SupabaseConnectionState = savedConnection
|
||||||
? JSON.parse(savedConnection)
|
? JSON.parse(savedConnection)
|
||||||
@@ -75,14 +82,14 @@ if (savedCredentials && !initialState.credentials) {
|
|||||||
|
|
||||||
export const supabaseConnection = atom<SupabaseConnectionState>(initialState);
|
export const supabaseConnection = atom<SupabaseConnectionState>(initialState);
|
||||||
|
|
||||||
if (initialState.token && !initialState.stats) {
|
|
||||||
fetchSupabaseStats(initialState.token).catch(console.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isConnecting = atom(false);
|
export const isConnecting = atom(false);
|
||||||
export const isFetchingStats = atom(false);
|
export const isFetchingStats = atom(false);
|
||||||
export const isFetchingApiKeys = atom(false);
|
export const isFetchingApiKeys = atom(false);
|
||||||
|
|
||||||
|
if (initialState.token && !initialState.stats) {
|
||||||
|
fetchSupabaseStats(initialState.token).catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
export function updateSupabaseConnection(connection: Partial<SupabaseConnectionState>) {
|
export function updateSupabaseConnection(connection: Partial<SupabaseConnectionState>) {
|
||||||
const currentState = supabaseConnection.get();
|
const currentState = supabaseConnection.get();
|
||||||
|
|
||||||
@@ -123,16 +130,16 @@ export function updateSupabaseConnection(connection: Partial<SupabaseConnectionS
|
|||||||
* Always save the connection state to localStorage to persist across chats
|
* Always save the connection state to localStorage to persist across chats
|
||||||
*/
|
*/
|
||||||
if (connection.user || connection.token || connection.selectedProjectId !== undefined || connection.credentials) {
|
if (connection.user || connection.token || connection.selectedProjectId !== undefined || connection.credentials) {
|
||||||
localStorage.setItem('supabase_connection', JSON.stringify(newState));
|
storage?.setItem('supabase_connection', JSON.stringify(newState));
|
||||||
|
|
||||||
if (newState.credentials) {
|
if (newState.credentials) {
|
||||||
localStorage.setItem('supabaseCredentials', JSON.stringify(newState.credentials));
|
storage?.setItem('supabaseCredentials', JSON.stringify(newState.credentials));
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('supabaseCredentials');
|
storage?.removeItem('supabaseCredentials');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('supabase_connection');
|
storage?.removeItem('supabase_connection');
|
||||||
localStorage.removeItem('supabaseCredentials');
|
storage?.removeItem('supabaseCredentials');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
app/root.tsx
31
app/root.tsx
@@ -9,6 +9,7 @@ import { useEffect } from 'react';
|
|||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import { ClientOnly } from 'remix-utils/client-only';
|
import { ClientOnly } from 'remix-utils/client-only';
|
||||||
|
import { cssTransition, ToastContainer } from 'react-toastify';
|
||||||
|
|
||||||
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
||||||
import globalStyles from './styles/index.scss?url';
|
import globalStyles from './styles/index.scss?url';
|
||||||
@@ -16,6 +17,11 @@ import xtermStyles from '@xterm/xterm/css/xterm.css?url';
|
|||||||
|
|
||||||
import 'virtual:uno.css';
|
import 'virtual:uno.css';
|
||||||
|
|
||||||
|
const toastAnimation = cssTransition({
|
||||||
|
enter: 'animated fadeInRight',
|
||||||
|
exit: 'animated fadeOutRight',
|
||||||
|
});
|
||||||
|
|
||||||
export const links: LinksFunction = () => [
|
export const links: LinksFunction = () => [
|
||||||
{
|
{
|
||||||
rel: 'icon',
|
rel: 'icon',
|
||||||
@@ -75,6 +81,31 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ClientOnly>{() => <DndProvider backend={HTML5Backend}>{children}</DndProvider>}</ClientOnly>
|
<ClientOnly>{() => <DndProvider backend={HTML5Backend}>{children}</DndProvider>}</ClientOnly>
|
||||||
|
<ToastContainer
|
||||||
|
closeButton={({ closeToast }) => {
|
||||||
|
return (
|
||||||
|
<button className="Toastify__close-button" onClick={closeToast}>
|
||||||
|
<div className="i-ph:x text-lg" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
icon={({ type }) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'success': {
|
||||||
|
return <div className="i-ph:check-bold text-bolt-elements-icon-success text-2xl" />;
|
||||||
|
}
|
||||||
|
case 'error': {
|
||||||
|
return <div className="i-ph:warning-circle-bold text-bolt-elements-icon-error text-2xl" />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}}
|
||||||
|
position="bottom-right"
|
||||||
|
pauseOnFocusLoss
|
||||||
|
transition={toastAnimation}
|
||||||
|
autoClose={3000}
|
||||||
|
/>
|
||||||
<ScrollRestoration />
|
<ScrollRestoration />
|
||||||
<Scripts />
|
<Scripts />
|
||||||
</>
|
</>
|
||||||
|
|||||||
110
app/routes/api.configured-providers.ts
Normal file
110
app/routes/api.configured-providers.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import type { LoaderFunction } from '@remix-run/cloudflare';
|
||||||
|
import { json } from '@remix-run/cloudflare';
|
||||||
|
import { LLMManager } from '~/lib/modules/llm/manager';
|
||||||
|
import { LOCAL_PROVIDERS } from '~/lib/stores/settings';
|
||||||
|
|
||||||
|
interface ConfiguredProvider {
|
||||||
|
name: string;
|
||||||
|
isConfigured: boolean;
|
||||||
|
configMethod: 'environment' | 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConfiguredProvidersResponse {
|
||||||
|
providers: ConfiguredProvider[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API endpoint that detects which providers are configured via environment variables
|
||||||
|
* This helps auto-enable providers that have been set up by the user
|
||||||
|
*/
|
||||||
|
export const loader: LoaderFunction = async ({ context }) => {
|
||||||
|
try {
|
||||||
|
const llmManager = LLMManager.getInstance(context?.cloudflare?.env as any);
|
||||||
|
const configuredProviders: ConfiguredProvider[] = [];
|
||||||
|
|
||||||
|
// Check each local provider for environment configuration
|
||||||
|
for (const providerName of LOCAL_PROVIDERS) {
|
||||||
|
const providerInstance = llmManager.getProvider(providerName);
|
||||||
|
let isConfigured = false;
|
||||||
|
let configMethod: 'environment' | 'none' = 'none';
|
||||||
|
|
||||||
|
if (providerInstance) {
|
||||||
|
const config = providerInstance.config;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if required environment variables are set
|
||||||
|
* For providers with baseUrlKey (Ollama, LMStudio, OpenAILike)
|
||||||
|
*/
|
||||||
|
if (config.baseUrlKey) {
|
||||||
|
const baseUrlEnvVar = config.baseUrlKey;
|
||||||
|
const cloudflareEnv = (context?.cloudflare?.env as Record<string, any>)?.[baseUrlEnvVar];
|
||||||
|
const processEnv = process.env[baseUrlEnvVar];
|
||||||
|
const managerEnv = llmManager.env[baseUrlEnvVar];
|
||||||
|
|
||||||
|
const envBaseUrl = cloudflareEnv || processEnv || managerEnv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only consider configured if environment variable is explicitly set
|
||||||
|
* Don't count default config.baseUrl values or placeholder values
|
||||||
|
*/
|
||||||
|
const isValidEnvValue =
|
||||||
|
envBaseUrl &&
|
||||||
|
typeof envBaseUrl === 'string' &&
|
||||||
|
envBaseUrl.trim().length > 0 &&
|
||||||
|
!envBaseUrl.includes('your_') && // Filter out placeholder values like "your_openai_like_base_url_here"
|
||||||
|
!envBaseUrl.includes('_here') &&
|
||||||
|
envBaseUrl.startsWith('http'); // Must be a valid URL
|
||||||
|
|
||||||
|
if (isValidEnvValue) {
|
||||||
|
isConfigured = true;
|
||||||
|
configMethod = 'environment';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For providers that might need API keys as well (check this separately, not as fallback)
|
||||||
|
if (config.apiTokenKey && !isConfigured) {
|
||||||
|
const apiTokenEnvVar = config.apiTokenKey;
|
||||||
|
const envApiToken =
|
||||||
|
(context?.cloudflare?.env as Record<string, any>)?.[apiTokenEnvVar] ||
|
||||||
|
process.env[apiTokenEnvVar] ||
|
||||||
|
llmManager.env[apiTokenEnvVar];
|
||||||
|
|
||||||
|
// Only consider configured if API key is set and not a placeholder
|
||||||
|
const isValidApiToken =
|
||||||
|
envApiToken &&
|
||||||
|
typeof envApiToken === 'string' &&
|
||||||
|
envApiToken.trim().length > 0 &&
|
||||||
|
!envApiToken.includes('your_') && // Filter out placeholder values
|
||||||
|
!envApiToken.includes('_here') &&
|
||||||
|
envApiToken.length > 10; // API keys are typically longer than 10 chars
|
||||||
|
|
||||||
|
if (isValidApiToken) {
|
||||||
|
isConfigured = true;
|
||||||
|
configMethod = 'environment';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredProviders.push({
|
||||||
|
name: providerName,
|
||||||
|
isConfigured,
|
||||||
|
configMethod,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return json<ConfiguredProvidersResponse>({
|
||||||
|
providers: configuredProviders,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error detecting configured providers:', error);
|
||||||
|
|
||||||
|
// Return default state on error
|
||||||
|
return json<ConfiguredProvidersResponse>({
|
||||||
|
providers: LOCAL_PROVIDERS.map((name) => ({
|
||||||
|
name,
|
||||||
|
isConfigured: false,
|
||||||
|
configMethod: 'none' as const,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -46,8 +46,10 @@ export default function WebContainerPreview() {
|
|||||||
}, [previewId, previewUrl]);
|
}, [previewId, previewUrl]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Initialize broadcast channel
|
const supportsBroadcastChannel = typeof window !== 'undefined' && typeof window.BroadcastChannel === 'function';
|
||||||
broadcastChannelRef.current = new BroadcastChannel(PREVIEW_CHANNEL);
|
|
||||||
|
if (supportsBroadcastChannel) {
|
||||||
|
broadcastChannelRef.current = new window.BroadcastChannel(PREVIEW_CHANNEL);
|
||||||
|
|
||||||
// Listen for preview updates
|
// Listen for preview updates
|
||||||
broadcastChannelRef.current.onmessage = (event) => {
|
broadcastChannelRef.current.onmessage = (event) => {
|
||||||
@@ -57,6 +59,9 @@ export default function WebContainerPreview() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
broadcastChannelRef.current = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Construct the WebContainer preview URL
|
// Construct the WebContainer preview URL
|
||||||
const url = `https://${previewId}.local-credentialless.webcontainer-api.io`;
|
const url = `https://${previewId}.local-credentialless.webcontainer-api.io`;
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
@use '../z-index';
|
||||||
|
|
||||||
|
.Toastify__toast-container {
|
||||||
|
@extend .z-toast;
|
||||||
|
}
|
||||||
|
|
||||||
.Toastify__toast {
|
.Toastify__toast {
|
||||||
--at-apply: shadow-md;
|
--at-apply: shadow-md;
|
||||||
|
|
||||||
|
|||||||
@@ -31,3 +31,7 @@ $zIndexMax: 999;
|
|||||||
.z-max {
|
.z-max {
|
||||||
z-index: $zIndexMax;
|
z-index: $zIndexMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.z-toast {
|
||||||
|
z-index: $zIndexMax + 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ services:
|
|||||||
app-dev:
|
app-dev:
|
||||||
image: bolt-ai:development
|
image: bolt-ai:development
|
||||||
build:
|
build:
|
||||||
target: bolt-ai-development
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: development
|
||||||
env_file:
|
env_file:
|
||||||
- '.env'
|
- '.env'
|
||||||
- '.env.local'
|
- '.env.local'
|
||||||
|
|||||||
34848
package-lock.json
generated
Normal file
34848
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
|||||||
"dockerstart": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings --ip 0.0.0.0 --port 5173 --no-show-interactive-dev-session",
|
"dockerstart": "bindings=$(./bindings.sh) && wrangler pages dev ./build/client $bindings --ip 0.0.0.0 --port 5173 --no-show-interactive-dev-session",
|
||||||
"dockerrun": "docker run -it -d --name bolt-ai-live -p 5173:5173 --env-file .env.local bolt-ai",
|
"dockerrun": "docker run -it -d --name bolt-ai-live -p 5173:5173 --env-file .env.local bolt-ai",
|
||||||
"dockerbuild:prod": "docker build -t bolt-ai:production -t bolt-ai:latest --target bolt-ai-production .",
|
"dockerbuild:prod": "docker build -t bolt-ai:production -t bolt-ai:latest --target bolt-ai-production .",
|
||||||
"dockerbuild": "docker build -t bolt-ai:development -t bolt-ai:latest --target bolt-ai-development .",
|
"dockerbuild": "docker build -t bolt-ai:development -t bolt-ai:latest --target development .",
|
||||||
"typecheck": "tsc",
|
"typecheck": "tsc",
|
||||||
"typegen": "wrangler types",
|
"typegen": "wrangler types",
|
||||||
"preview": "pnpm run build && pnpm run start",
|
"preview": "pnpm run build && pnpm run start",
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitz/eslint-plugin": "0.1.0",
|
"@blitz/eslint-plugin": "0.1.0",
|
||||||
"@cloudflare/workers-types": "^4.20241127.0",
|
"@cloudflare/workers-types": "^4.20251011.0",
|
||||||
"@electron/notarize": "^2.5.0",
|
"@electron/notarize": "^2.5.0",
|
||||||
"@iconify-json/ph": "^1.2.1",
|
"@iconify-json/ph": "^1.2.1",
|
||||||
"@iconify/types": "^2.0.0",
|
"@iconify/types": "^2.0.0",
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"vite-plugin-optimize-css-modules": "^1.1.0",
|
"vite-plugin-optimize-css-modules": "^1.1.0",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^2.1.7",
|
"vitest": "^2.1.7",
|
||||||
"wrangler": "^4.5.1"
|
"wrangler": "^4.44.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@typescript-eslint/utils": "^8.0.0-alpha.30"
|
"@typescript-eslint/utils": "^8.0.0-alpha.30"
|
||||||
|
|||||||
152
pnpm-lock.yaml
generated
152
pnpm-lock.yaml
generated
@@ -157,10 +157,10 @@ importers:
|
|||||||
version: 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.2.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@remix-run/cloudflare':
|
'@remix-run/cloudflare':
|
||||||
specifier: ^2.15.2
|
specifier: ^2.15.2
|
||||||
version: 2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)
|
version: 2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)
|
||||||
'@remix-run/cloudflare-pages':
|
'@remix-run/cloudflare-pages':
|
||||||
specifier: ^2.15.2
|
specifier: ^2.15.2
|
||||||
version: 2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)
|
version: 2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)
|
||||||
'@remix-run/node':
|
'@remix-run/node':
|
||||||
specifier: ^2.15.2
|
specifier: ^2.15.2
|
||||||
version: 2.16.8(typescript@5.8.3)
|
version: 2.16.8(typescript@5.8.3)
|
||||||
@@ -322,7 +322,7 @@ importers:
|
|||||||
version: 0.2.0(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/server-runtime@2.16.8(typescript@5.8.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 0.2.0(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/server-runtime@2.16.8(typescript@5.8.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
remix-utils:
|
remix-utils:
|
||||||
specifier: ^7.7.0
|
specifier: ^7.7.0
|
||||||
version: 7.7.0(@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3))(@remix-run/node@2.16.8(typescript@5.8.3))(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.25.76)
|
version: 7.7.0(@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3))(@remix-run/node@2.16.8(typescript@5.8.3))(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.25.76)
|
||||||
rollup-plugin-node-polyfills:
|
rollup-plugin-node-polyfills:
|
||||||
specifier: ^0.2.1
|
specifier: ^0.2.1
|
||||||
version: 0.2.1
|
version: 0.2.1
|
||||||
@@ -352,8 +352,8 @@ importers:
|
|||||||
specifier: 0.1.0
|
specifier: 0.1.0
|
||||||
version: 0.1.0(jiti@1.21.7)(prettier@3.6.2)(typescript@5.8.3)
|
version: 0.1.0(jiti@1.21.7)(prettier@3.6.2)(typescript@5.8.3)
|
||||||
'@cloudflare/workers-types':
|
'@cloudflare/workers-types':
|
||||||
specifier: ^4.20241127.0
|
specifier: ^4.20251011.0
|
||||||
version: 4.20250722.0
|
version: 4.20251014.0
|
||||||
'@electron/notarize':
|
'@electron/notarize':
|
||||||
specifier: ^2.5.0
|
specifier: ^2.5.0
|
||||||
version: 2.5.0
|
version: 2.5.0
|
||||||
@@ -365,7 +365,7 @@ importers:
|
|||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
'@remix-run/dev':
|
'@remix-run/dev':
|
||||||
specifier: ^2.15.2
|
specifier: ^2.15.2
|
||||||
version: 2.16.8(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.8(typescript@5.8.3))(@types/node@24.1.0)(sass-embedded@1.89.2)(typescript@5.8.3)(vite@5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2))(wrangler@4.25.1(@cloudflare/workers-types@4.20250722.0))
|
version: 2.16.8(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.8(typescript@5.8.3))(@types/node@24.1.0)(sass-embedded@1.89.2)(typescript@5.8.3)(vite@5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2))(wrangler@4.44.0(@cloudflare/workers-types@4.20251014.0))
|
||||||
'@remix-run/serve':
|
'@remix-run/serve':
|
||||||
specifier: ^2.15.2
|
specifier: ^2.15.2
|
||||||
version: 2.16.8(typescript@5.8.3)
|
version: 2.16.8(typescript@5.8.3)
|
||||||
@@ -419,7 +419,7 @@ importers:
|
|||||||
version: 33.4.11
|
version: 33.4.11
|
||||||
electron-builder:
|
electron-builder:
|
||||||
specifier: ^26.0.12
|
specifier: ^26.0.12
|
||||||
version: 26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12))
|
version: 26.0.12(electron-builder-squirrel-windows@26.0.12)
|
||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
specifier: ^10.1.1
|
specifier: ^10.1.1
|
||||||
version: 10.1.8(eslint@9.31.0(jiti@1.21.7))
|
version: 10.1.8(eslint@9.31.0(jiti@1.21.7))
|
||||||
@@ -481,8 +481,8 @@ importers:
|
|||||||
specifier: ^2.1.7
|
specifier: ^2.1.7
|
||||||
version: 2.1.9(@types/node@24.1.0)(jsdom@26.1.0)(sass-embedded@1.89.2)
|
version: 2.1.9(@types/node@24.1.0)(jsdom@26.1.0)(sass-embedded@1.89.2)
|
||||||
wrangler:
|
wrangler:
|
||||||
specifier: ^4.5.1
|
specifier: ^4.44.0
|
||||||
version: 4.25.1(@cloudflare/workers-types@4.20250722.0)
|
version: 4.44.0(@cloudflare/workers-types@4.20251014.0)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -954,47 +954,47 @@ packages:
|
|||||||
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.3.3':
|
'@cloudflare/unenv-preset@2.7.8':
|
||||||
resolution: {integrity: sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A==}
|
resolution: {integrity: sha512-Ky929MfHh+qPhwCapYrRPwPVHtA2Ioex/DbGZyskGyNRDe9Ru3WThYZivyNVaPy5ergQSgMs9OKrM9Ajtz9F6w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
unenv: 2.0.0-rc.17
|
unenv: 2.0.0-rc.21
|
||||||
workerd: ^1.20250508.0
|
workerd: ^1.20250927.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
workerd:
|
workerd:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-64@1.20250712.0':
|
'@cloudflare/workerd-darwin-64@1.20251011.0':
|
||||||
resolution: {integrity: sha512-M6S6a/LQ0Jb0R+g0XhlYi1adGifvYmxA5mD/i9TuZZgjs2bIm5ELuka/n3SCnI98ltvlx3HahRaHagAtOilsFg==}
|
resolution: {integrity: sha512-0DirVP+Z82RtZLlK2B+VhLOkk+ShBqDYO/jhcRw4oVlp0TOvk3cOVZChrt3+y3NV8Y/PYgTEywzLKFSziK4wCg==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-arm64@1.20250712.0':
|
'@cloudflare/workerd-darwin-arm64@1.20251011.0':
|
||||||
resolution: {integrity: sha512-7sFzn6rvAcnLy7MktFL42dYtzL0Idw/kiUmNf2P3TvsBRoShhLK5ZKhbw+NAhvU8e4pXWm5lkE0XmpieA0zNjw==}
|
resolution: {integrity: sha512-1WuFBGwZd15p4xssGN/48OE2oqokIuc51YvHvyNivyV8IYnAs3G9bJNGWth1X7iMDPe4g44pZrKhRnISS2+5dA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-64@1.20250712.0':
|
'@cloudflare/workerd-linux-64@1.20251011.0':
|
||||||
resolution: {integrity: sha512-EFRrGe/bqK7NHtht7vNlbrDpfvH3eRvtJOgsTpEQEysDjVmlK6pVJxSnLy9Hg1zlLY15IfhfGC+K2qisseHGJQ==}
|
resolution: {integrity: sha512-BccMiBzFlWZyFghIw2szanmYJrJGBGHomw2y/GV6pYXChFzMGZkeCEMfmCyJj29xczZXxcZmUVJxNy4eJxO8QA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-arm64@1.20250712.0':
|
'@cloudflare/workerd-linux-arm64@1.20251011.0':
|
||||||
resolution: {integrity: sha512-rG8JUleddhUHQVwpXOYv0VbL0S9kOtR9PNKecgVhFpxEhC8aTeg2HNBBjo8st7IfcUvY8WaW3pD3qdAMZ05UwQ==}
|
resolution: {integrity: sha512-79o/216lsbAbKEVDZYXR24ivEIE2ysDL9jvo0rDTkViLWju9dAp3CpyetglpJatbSi3uWBPKZBEOqN68zIjVsQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@cloudflare/workerd-windows-64@1.20250712.0':
|
'@cloudflare/workerd-windows-64@1.20251011.0':
|
||||||
resolution: {integrity: sha512-qS8H5RCYwE21Om9wo5/F807ClBJIfknhuLBj16eYxvJcj9JqgAKWi12BGgjyGxHuJJjeoQ63lr4wHAdbFntDDg==}
|
resolution: {integrity: sha512-RIXUQRchFdqEvaUqn1cXZXSKjpqMaSaVAkI5jNZ8XzAw/bw2bcdOVUtakrflgxDprltjFb0PTNtuss1FKtH9Jg==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@cloudflare/workers-types@4.20250722.0':
|
'@cloudflare/workers-types@4.20251014.0':
|
||||||
resolution: {integrity: sha512-pTY+A07DTSacgUBYcVEEb78/KG7THdcRpPqXLeH/A/LHHobAddgN4zyXBldsoZuzy7bD9tZYJW+wkcyR4k7fDA==}
|
resolution: {integrity: sha512-tEW98J/kOa0TdylIUOrLKRdwkUw0rvvYVlo+Ce0mqRH3c8kSoxLzUH9gfCvwLe0M89z1RkzFovSKAW2Nwtyn3w==}
|
||||||
|
|
||||||
'@codemirror/autocomplete@6.18.6':
|
'@codemirror/autocomplete@6.18.6':
|
||||||
resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==}
|
resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==}
|
||||||
@@ -6068,8 +6068,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
miniflare@4.20250712.1:
|
miniflare@4.20251011.0:
|
||||||
resolution: {integrity: sha512-46gB3FGPOsy+EpFGufjhr8agYycO/55d6l0y7hNJ13NcTVwrObMg/0HmI3pC5yQj0974IVXzBgUfDBMAX6thow==}
|
resolution: {integrity: sha512-DlZ7vR5q/RE9eLsxsrXzfSZIF2f6O5k0YsFrSKhWUtdefyGtJt4sSpR6V+Af/waaZ6+zIFy9lsknHBCm49sEYA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -7765,12 +7765,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
|
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
|
||||||
engines: {node: '>=18.17'}
|
engines: {node: '>=18.17'}
|
||||||
|
|
||||||
undici@7.12.0:
|
undici@7.14.0:
|
||||||
resolution: {integrity: sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==}
|
resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==}
|
||||||
engines: {node: '>=20.18.1'}
|
engines: {node: '>=20.18.1'}
|
||||||
|
|
||||||
unenv@2.0.0-rc.17:
|
unenv@2.0.0-rc.21:
|
||||||
resolution: {integrity: sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg==}
|
resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==}
|
||||||
|
|
||||||
unified@10.1.2:
|
unified@10.1.2:
|
||||||
resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
|
resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
|
||||||
@@ -8137,17 +8137,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
workerd@1.20250712.0:
|
workerd@1.20251011.0:
|
||||||
resolution: {integrity: sha512-7h+k1OxREpiZW0849g0uQNexRWMcs5i5gUGhJzCY8nIx6Tv4D/ndlXJ47lEFj7/LQdp165IL9dM2D5uDiedZrg==}
|
resolution: {integrity: sha512-Dq35TLPEJAw7BuYQMkN3p9rge34zWMU2Gnd4DSJFeVqld4+DAO2aPG7+We2dNIAyM97S8Y9BmHulbQ00E0HC7Q==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
wrangler@4.25.1:
|
wrangler@4.44.0:
|
||||||
resolution: {integrity: sha512-4Tlg+jmqxCX3xFm+Nz1b4jHHY9iOu1EyJ17SSCCJ6MGp+FCGtXgr+CynT94+MP0v/qKQUkMKjoeJ5FNDunZ9cA==}
|
resolution: {integrity: sha512-BLOUigckcWZ0r4rm7b5PuaTpb9KP9as0XeCRSJ8kqcNgXcKoUD3Ij8FlPvN25KybLnFnetaO0ZdfRYUPWle4qw==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@cloudflare/workers-types': ^4.20250712.0
|
'@cloudflare/workers-types': ^4.20251011.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@cloudflare/workers-types':
|
'@cloudflare/workers-types':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -9104,28 +9104,28 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250712.0)':
|
'@cloudflare/unenv-preset@2.7.8(unenv@2.0.0-rc.21)(workerd@1.20251011.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
unenv: 2.0.0-rc.17
|
unenv: 2.0.0-rc.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
workerd: 1.20250712.0
|
workerd: 1.20251011.0
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-64@1.20250712.0':
|
'@cloudflare/workerd-darwin-64@1.20251011.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-arm64@1.20250712.0':
|
'@cloudflare/workerd-darwin-arm64@1.20251011.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-64@1.20250712.0':
|
'@cloudflare/workerd-linux-64@1.20251011.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-arm64@1.20250712.0':
|
'@cloudflare/workerd-linux-arm64@1.20251011.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-windows-64@1.20250712.0':
|
'@cloudflare/workerd-windows-64@1.20251011.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workers-types@4.20250722.0': {}
|
'@cloudflare/workers-types@4.20251014.0': {}
|
||||||
|
|
||||||
'@codemirror/autocomplete@6.18.6':
|
'@codemirror/autocomplete@6.18.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -10765,22 +10765,22 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
'@remix-run/cloudflare-pages@2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)':
|
'@remix-run/cloudflare-pages@2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/workers-types': 4.20250722.0
|
'@cloudflare/workers-types': 4.20251014.0
|
||||||
'@remix-run/cloudflare': 2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)
|
'@remix-run/cloudflare': 2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
|
|
||||||
'@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)':
|
'@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/kv-asset-handler': 0.1.3
|
'@cloudflare/kv-asset-handler': 0.1.3
|
||||||
'@cloudflare/workers-types': 4.20250722.0
|
'@cloudflare/workers-types': 4.20251014.0
|
||||||
'@remix-run/server-runtime': 2.16.8(typescript@5.8.3)
|
'@remix-run/server-runtime': 2.16.8(typescript@5.8.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
|
|
||||||
'@remix-run/dev@2.16.8(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.8(typescript@5.8.3))(@types/node@24.1.0)(sass-embedded@1.89.2)(typescript@5.8.3)(vite@5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2))(wrangler@4.25.1(@cloudflare/workers-types@4.20250722.0))':
|
'@remix-run/dev@2.16.8(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.8(typescript@5.8.3))(@types/node@24.1.0)(sass-embedded@1.89.2)(typescript@5.8.3)(vite@5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2))(wrangler@4.44.0(@cloudflare/workers-types@4.20251014.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.0
|
'@babel/core': 7.28.0
|
||||||
'@babel/generator': 7.28.0
|
'@babel/generator': 7.28.0
|
||||||
@@ -10843,7 +10843,7 @@ snapshots:
|
|||||||
'@remix-run/serve': 2.16.8(typescript@5.8.3)
|
'@remix-run/serve': 2.16.8(typescript@5.8.3)
|
||||||
typescript: 5.8.3
|
typescript: 5.8.3
|
||||||
vite: 5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2)
|
vite: 5.4.19(@types/node@24.1.0)(sass-embedded@1.89.2)
|
||||||
wrangler: 4.25.1(@cloudflare/workers-types@4.20250722.0)
|
wrangler: 4.44.0(@cloudflare/workers-types@4.20251014.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
@@ -12074,7 +12074,7 @@ snapshots:
|
|||||||
|
|
||||||
app-builder-bin@5.0.0-alpha.12: {}
|
app-builder-bin@5.0.0-alpha.12: {}
|
||||||
|
|
||||||
app-builder-lib@26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)):
|
app-builder-lib@26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@develar/schema-utils': 2.6.5
|
'@develar/schema-utils': 2.6.5
|
||||||
'@electron/asar': 3.2.18
|
'@electron/asar': 3.2.18
|
||||||
@@ -12887,7 +12887,7 @@ snapshots:
|
|||||||
|
|
||||||
dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12):
|
dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12))
|
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
|
||||||
builder-util: 26.0.11
|
builder-util: 26.0.11
|
||||||
builder-util-runtime: 9.3.1
|
builder-util-runtime: 9.3.1
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
@@ -12966,7 +12966,7 @@ snapshots:
|
|||||||
|
|
||||||
electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12):
|
electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12))
|
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
|
||||||
builder-util: 26.0.11
|
builder-util: 26.0.11
|
||||||
electron-winstaller: 5.4.0
|
electron-winstaller: 5.4.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -12974,9 +12974,9 @@ snapshots:
|
|||||||
- dmg-builder
|
- dmg-builder
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)):
|
electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12))
|
app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12)
|
||||||
builder-util: 26.0.11
|
builder-util: 26.0.11
|
||||||
builder-util-runtime: 9.3.1
|
builder-util-runtime: 9.3.1
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
@@ -15269,7 +15269,7 @@ snapshots:
|
|||||||
|
|
||||||
min-indent@1.0.1: {}
|
min-indent@1.0.1: {}
|
||||||
|
|
||||||
miniflare@4.20250712.1:
|
miniflare@4.20251011.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cspotcode/source-map-support': 0.8.1
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
acorn: 8.14.0
|
acorn: 8.14.0
|
||||||
@@ -15278,8 +15278,8 @@ snapshots:
|
|||||||
glob-to-regexp: 0.4.1
|
glob-to-regexp: 0.4.1
|
||||||
sharp: 0.33.5
|
sharp: 0.33.5
|
||||||
stoppable: 1.1.0
|
stoppable: 1.1.0
|
||||||
undici: 7.12.0
|
undici: 7.14.0
|
||||||
workerd: 1.20250712.0
|
workerd: 1.20251011.0
|
||||||
ws: 8.18.0
|
ws: 8.18.0
|
||||||
youch: 4.1.0-beta.10
|
youch: 4.1.0-beta.10
|
||||||
zod: 3.22.3
|
zod: 3.22.3
|
||||||
@@ -16229,11 +16229,11 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
remix-utils@7.7.0(@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3))(@remix-run/node@2.16.8(typescript@5.8.3))(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.25.76):
|
remix-utils@7.7.0(@remix-run/cloudflare@2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3))(@remix-run/node@2.16.8(typescript@5.8.3))(@remix-run/react@2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/router@1.23.0)(react@18.3.1)(zod@3.25.76):
|
||||||
dependencies:
|
dependencies:
|
||||||
type-fest: 4.41.0
|
type-fest: 4.41.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@remix-run/cloudflare': 2.16.8(@cloudflare/workers-types@4.20250722.0)(typescript@5.8.3)
|
'@remix-run/cloudflare': 2.16.8(@cloudflare/workers-types@4.20251014.0)(typescript@5.8.3)
|
||||||
'@remix-run/node': 2.16.8(typescript@5.8.3)
|
'@remix-run/node': 2.16.8(typescript@5.8.3)
|
||||||
'@remix-run/react': 2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)
|
'@remix-run/react': 2.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3)
|
||||||
'@remix-run/router': 1.23.0
|
'@remix-run/router': 1.23.0
|
||||||
@@ -17072,9 +17072,9 @@ snapshots:
|
|||||||
|
|
||||||
undici@6.21.3: {}
|
undici@6.21.3: {}
|
||||||
|
|
||||||
undici@7.12.0: {}
|
undici@7.14.0: {}
|
||||||
|
|
||||||
unenv@2.0.0-rc.17:
|
unenv@2.0.0-rc.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
exsolve: 1.0.7
|
exsolve: 1.0.7
|
||||||
@@ -17522,26 +17522,26 @@ snapshots:
|
|||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
workerd@1.20250712.0:
|
workerd@1.20251011.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@cloudflare/workerd-darwin-64': 1.20250712.0
|
'@cloudflare/workerd-darwin-64': 1.20251011.0
|
||||||
'@cloudflare/workerd-darwin-arm64': 1.20250712.0
|
'@cloudflare/workerd-darwin-arm64': 1.20251011.0
|
||||||
'@cloudflare/workerd-linux-64': 1.20250712.0
|
'@cloudflare/workerd-linux-64': 1.20251011.0
|
||||||
'@cloudflare/workerd-linux-arm64': 1.20250712.0
|
'@cloudflare/workerd-linux-arm64': 1.20251011.0
|
||||||
'@cloudflare/workerd-windows-64': 1.20250712.0
|
'@cloudflare/workerd-windows-64': 1.20251011.0
|
||||||
|
|
||||||
wrangler@4.25.1(@cloudflare/workers-types@4.20250722.0):
|
wrangler@4.44.0(@cloudflare/workers-types@4.20251014.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/kv-asset-handler': 0.4.0
|
'@cloudflare/kv-asset-handler': 0.4.0
|
||||||
'@cloudflare/unenv-preset': 2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250712.0)
|
'@cloudflare/unenv-preset': 2.7.8(unenv@2.0.0-rc.21)(workerd@1.20251011.0)
|
||||||
blake3-wasm: 2.1.5
|
blake3-wasm: 2.1.5
|
||||||
esbuild: 0.25.4
|
esbuild: 0.25.4
|
||||||
miniflare: 4.20250712.1
|
miniflare: 4.20251011.0
|
||||||
path-to-regexp: 6.3.0
|
path-to-regexp: 6.3.0
|
||||||
unenv: 2.0.0-rc.17
|
unenv: 2.0.0-rc.21
|
||||||
workerd: 1.20250712.0
|
workerd: 1.20251011.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@cloudflare/workers-types': 4.20250722.0
|
'@cloudflare/workers-types': 4.20251014.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
|
|||||||
Reference in New Issue
Block a user