);
```
---
## Form Handling
### **Controlled Components**
```typescript
const [formData, setFormData] = useState({
title: '',
description: '',
isPublic: true
});
const handleChange = (field: keyof typeof formData) => (
e: React.ChangeEvent
) => {
setFormData(prev => ({ ...prev, [field]: e.target.value }));
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
await apiClient.createApp(formData);
};
return (
);
```
### **Form Validation**
```typescript
const [errors, setErrors] = useState>({});
const validate = () => {
const newErrors: Record = {};
if (!formData.title) {
newErrors.title = 'Title is required';
}
if (formData.title.length < 3) {
newErrors.title = 'Title must be at least 3 characters';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
if (!validate()) return;
await apiClient.createApp(formData);
};
```
---
## Modal Patterns
### **Simple Modal State**
```typescript
const [isOpen, setIsOpen] = useState(false);
return (
<>
>
);
```
### **Modal with Data**
```typescript
const [selectedApp, setSelectedApp] = useState(null);
return (
<>
{apps.map(app => (
))}
{selectedApp && (
setSelectedApp(null)}
/>
)}
>
);
```
---
## Error Handling
### **Error Boundary**
```typescript
// /components/ErrorBoundary.tsx
export class ErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
// Send to Sentry
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
```
### **API Error Handling**
```typescript
try {
const app = await apiClient.getApp(appId);
setApp(app);
} catch (error) {
if (error instanceof ApiError) {
if (error.status === 404) {
setError('App not found');
} else if (error.status === 403) {
setError('Access denied');
} else {
setError('Something went wrong');
}
}
}
```
---
# ๐๏ธ CORE AGENT SYSTEM (Durable Objects)
## Overview
**SimpleCodeGeneratorAgent** is the brain of vibesdk - a Durable Object that orchestrates entire app generation lifecycle.
**Key responsibilities:**
- Blueprint generation from user prompts
- Phase-by-phase code generation
- File management and versioning
- Sandbox deployment and monitoring
- Conversation handling
- Debug session orchestration
---
## Agent Operations (State Machine)
### **1. Blueprint Generation**
**Trigger:** User submits initial prompt
**Flow:**
1. LLM analyzes prompt โ generates complete PRD (Blueprint)
2. Blueprint includes: project structure, phases, tech stack, UI design, color palette
3. Saved to state, shown to user for confirmation
4. User can iterate or approve
### **2. Phase Generation**
**Trigger:** User starts generation or requests new feature
**Flow:**
1. Agent determines next phase from blueprint
2. Uses PhaseGeneration operation to plan files
3. Updates currentDevState = PHASE_GENERATING
4. Generates phase concept (files to create, purposes)
### **3. Phase Implementation**
**Trigger:** Phase concept ready
**Flow:**
1. PhaseImplementation operation generates all files for phase
2. Uses LLM with file generation tools
3. Tracks progress per-file
4. Updates generatedFilesMap with new files
5. Commits to git (isomorphic-git in SQLite)
6. Sets currentDevState = PHASE_IMPLEMENTING
### **4. Code Review & Fixing**
**Trigger:** Phase complete, auto-triggered or user-requested
**Flow:**
1. PostPhaseCodeFixer runs TypeScript static analysis
2. Identifies type errors, missing imports, etc.
3. Automatically fixes common issues (TS2304, TS2307, etc.)
4. Re-analyzes until clean or max iterations
5. Updates files in generatedFilesMap
### **5. Deployment to Sandbox**
**Trigger:** Files ready, user clicks preview
**Flow:**
1. DeploymentManager.deployToSandbox()
2. Syncs all files to remote sandbox container
3. Executes install commands (npm install, etc.)
4. Starts dev server
5. Returns preview URL
6. Monitors health with periodic checks
### **6. User Conversation**
**Trigger:** User sends message during generation
**Flow:**
1. UserConversationProcessor handles chat
2. Queues feature requests if generating
3. Processes immediately if idle
4. Has access to tools: queue_request, deep_debug, deploy, etc.
5. Streams responses via WebSocket
### **7. Deep Debugging**
**Trigger:** User reports bug or runtime error
**Flow:**
1. Agent checks not currently generating (conflict prevention)
2. DeepCodeDebugger assistant spawned
3. Has access to: read files, static analysis, runtime errors, logs, regenerate files
4. Iteratively diagnoses and fixes
5. Saves transcript for context in next session
6. Deploys fixes automatically
---
## Agent Services (Delegation Pattern)
Agent delegates specific responsibilities to service classes:
**Location:** `/worker/agents/services/implementations/`
1. **FileManager** - File CRUD, validation, deduplication
2. **DeploymentManager** - Sandbox lifecycle, deployment, health checks
3. **GitService** - Commit, history, clone service
4. **CodingAgent (Proxy)** - Exposes agent methods to tools (runs in DO context)
**Why services?**
- Separation of concerns
- Testability
- Code reuse
- Clean interfaces
---
# ๐งช SANDBOX SYSTEM
## Overview
Sandboxes are **ephemeral containers** that run user's generated apps in isolated environments.
**Technology:** Remote sandbox service (separate infrastructure)
**Communication:** HTTP API with bearer token auth
**Lifecycle:** Created on-demand, destroyed after inactivity
---
## Sandbox Architecture
```
/* Detailed source-code truncated for AI context efficiency. */
```
---
## Sandbox Operations
### **1. Instance Creation**
**Method:** `createInstance(templateName, projectName, webhookUrl?, envVars?)`
**Flow:**
1. Agent calls with template (react-vite, nextjs, etc.)
2. Sandbox service spins up container
3. Clones template from git
4. Installs base dependencies
5. Returns instanceId + preview URL
**Response:** `{ instanceId, url, status: 'ready' }`
### **2. File Synchronization**
**Method:** `writeFiles(instanceId, files, commitMessage?)`
**Flow:**
1. Agent sends array of files: `[{ path, content, encoding }]`
2. Sandbox writes to container filesystem
3. Triggers hot reload if dev server running
4. Optionally commits to git with message
**Used for:** Initial deployment, incremental updates, fixes
### **3. Command Execution**
**Method:** `executeCommands(instanceId, commands, timeout?)`
**Flow:**
1. Agent sends shell commands (npm install, npm run build, etc.)
2. Sandbox executes in container
3. Returns stdout, stderr, exit code
4. Timeout after 60s default
**Security:** Commands validated/filtered before execution to prevent dangerous operations
### **4. Static Analysis**
**Method:** `getStaticAnalysis(instanceId)`
**Flow:**
1. Sandbox runs TypeScript compiler (tsc --noEmit)
2. Collects all errors with file/line/column
3. Returns structured error list
**Used by:** PostPhaseCodeFixer, deep debugger
### **5. Runtime Error Monitoring**
**Method:** `getRuntimeErrors(instanceId)`
**Flow:**
1. Sandbox monitors browser console errors
2. Collects stack traces, error messages
3. Deduplicates and categorizes
4. Returns recent errors
**Triggers:** Websocket webhook to agent when errors occur
### **6. Log Retrieval**
**Method:** `getLogs(instanceId, lines?, filter?)`
**Flow:**
1. Returns recent console output from container
2. Includes dev server logs, build output, console.log statements
3. Filtered by pattern if provided
**Note:** Logs only appear when user interacts with app
### **7. Instance Shutdown**
**Method:** `shutdownInstance(instanceId)`
**Flow:**
1. Stops dev server
2. Destroys container
3. Frees resources
**Auto-triggered:** After 30 min inactivity or explicit user close
---
## Session Management
Each agent has a **sessionId** that maps to a sandbox instance:
- **Stored in:** `CodeGenState.sessionId`
- **Purpose:** Ensures deployment goes to correct container
- **Reset on:** Timeout errors, critical failures
- **Cached client:** DeploymentManager caches sandbox client per session
**Health Checks:**
- Periodic ping to sandbox every 30s
- If unhealthy, resets sessionId
- Forces redeployment on next attempt
---
# ๐ DEPLOYMENT FLOW
## Complete Deployment Process
### **Trigger:** User clicks "Preview" button
**Step-by-step:**
1. **Pre-deployment Validation**
- Check files exist in generatedFilesMap
- Verify no generation in progress
- Get or create sessionId
2. **Sandbox Instance Check**
- If no sandboxInstanceId: create new instance
- If exists: check health status
- If unhealthy: reset session, create new instance
3. **Create Instance (if needed)**
```
โ createInstance(templateName, projectName, webhookUrl)
โ { instanceId, url, status }
โ Save instanceId to state
```
4. **File Synchronization**
```
โ Collect all files from generatedFilesMap
โ Format as { path, content, encoding: 'utf-8' }[]
โ writeFiles(instanceId, files, "Deploy generated code")
โ { success: true, filesWritten: 42 }
```
5. **Package.json Sync**
```
โ Check if package.json changed
โ If changed: executeCommands(['npm install'])
โ Wait for completion (timeout: 60s)
โ Cache new package.json in state
```
6. **Bootstrap Commands (if needed)**
```
โ Execute commandsHistory (previously run user commands)
โ Validates/filters dangerous commands
โ Runs: npm install, setup scripts, etc.
```
7. **Start Dev Server**
```
โ Already running from instance creation
โ Or trigger via command if stopped
โ Monitor startup logs
```
8. **Health Check Loop**
```
โ setInterval(30s): ping sandbox
โ Check status endpoint
โ If unhealthy: log warning, may reset
```
9. **Return Preview URL**
```
โ Send URL to frontend via WebSocket
โ User can open in iframe or new tab
โ App is live and interactive
```
---
## Redeployment (Incremental Updates)
When files change after initial deploy:
1. **Diff Detection**
- Compare file hashes in generatedFilesMap
- Only sync changed files
2. **Partial Sync**
```
โ writeFiles(instanceId, [changedFiles])
โ Hot reload triggered automatically
```
3. **No Full Rebuild**
- Dev server hot reloads changes
- Fast iteration (< 1s typically)
---
## Deployment Errors & Recovery
**Common errors:**
1. **Timeout (60s)**
- Cause: npm install too slow, network issues
- Recovery: Reset sessionId, retry with fresh instance
2. **Instance Not Found**
- Cause: Container crashed or evicted
- Recovery: Create new instance, redeploy all files
3. **Command Execution Failed**
- Cause: Invalid package.json, dependency conflicts
- Recovery: Show error to user, allow editing
4. **Health Check Failed**
- Cause: Dev server crashed, port conflict
- Recovery: Reset session on next deploy attempt
---
# ๐ค LLM INFERENCE SYSTEM
## Overview
**Location:** `/worker/agents/inferutils/`
Centralized inference engine that all operations use to call LLMs.
**Key features:**
- Multi-provider support (OpenAI, Anthropic via Cloudflare AI Gateway)
- Streaming responses
- Tool calling with recursive execution
- Retry logic with exponential backoff
- Cancellation support (AbortController)
- Token tracking
---
## Inference Flow
```
Operation (PhaseImplementation, UserConversationProcessor, etc.)
โ
getOperationOptions() โ InferenceContext
โ
executeInference(args, context)
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Retry Loop (max 3 attempts) โ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ
infer(args)
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ OpenAI SDK (via AI Gateway) โ
โ - Model selection โ
โ - Token streaming โ
โ - Tool call parsing โ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ
Tool calls present?
โ
โโโโโโโโโดโโโโโโโโ
Yes No
โ โ
โ โ
Execute tools Return response
Recursive infer
```
---
## Model Selection
**Location:** `/worker/agents/inferutils/config.ts`
**Available models:**
1. **GPT-4o** - Fast, good for most tasks
2. **GPT-4o-mini** - Cheapest, simple operations
3. **Claude 3.5 Sonnet** - Best for complex reasoning
4. **Gemini 2.0 Flash** - Fast, experimental
5. **Gemini 2.5 Pro** - Highest quality, deep debugging
**Selection by operation:**
- Blueprint generation: GPT-4o
- Phase planning: GPT-4o
- File generation: GPT-4o
- Conversation: GPT-4o-mini
- Deep debugging: Gemini 2.5 Pro (reasoning_effort: high)
- Code review: GPT-4o
---
## Streaming
**When enabled:**
- User conversation responses
- Deep debugger output
- Real-time code generation feedback
**How it works:**
1. LLM sends Server-Sent Events (SSE)
2. `infer()` yields chunks via async generator
3. Operation accumulates + forwards to WebSocket
4. Frontend renders progressively
---
## Tool Calling
**Recursive execution:**
1. LLM response includes `tool_calls` array
2. `infer()` executes each tool in parallel
3. Results collected
4. Filtered (empty/null results skipped)
5. If results exist: call LLM again with tool outputs
6. Repeat until LLM provides final response
**Max depth:** Configurable per operation
---
## Retry Logic
**Triggers retry:**
- Rate limit errors (429)
- Network timeouts
- Temporary API failures (5xx)
**Does NOT retry:**
- Cancelled operations (AbortError)
- Invalid API key (401)
- Malformed requests (400)
**Backoff:** Exponential (1s, 2s, 4s)
---
## Cancellation
Each operation gets AbortSignal:
```
User clicks stop button
โ
WebSocket: STOP_GENERATION
โ
agent.cancelCurrentInference()
โ
AbortController.abort()
โ
OpenAI SDK cancels HTTP request
โ
infer() throws InferError('cancelled')
โ
No retry, immediate propagation
```
**Nested operations:** Share same AbortController
**Tool calls:** All cancelled together
---
# ๐ AUTHENTICATION & AUTHORIZATION SYSTEM
## Overview
The auth system implements a **comprehensive JWT-based authentication** with **OAuth 2.0 social login** (Google, GitHub), **session management**, **API keys**, and **security auditing**. All auth operations are centralized through services that interact with D1 database.
**Core Components:**
1. **AuthService** - Main authentication orchestrator
2. **SessionService** - JWT session management with D1 persistence
3. **JWTUtils** - Token creation, verification, signing
4. **OAuth Providers** - Google & GitHub implementations with PKCE
5. **Middleware** - Route protection and token extraction
6. **Security** - Password hashing, rate limiting, audit logs
---
## Auth Architecture Flow
```
/* Detailed source-code truncated for AI context efficiency. */
```
---
## Key Database Tables
### **users Table**
Stores user identity, OAuth provider info, preferences, and security settings.
**Key fields:**
- Identity: id, email, username, displayName, avatarUrl
- OAuth: provider (github/google/email), providerId, emailVerified
- Security: passwordHash (email provider only), failedLoginAttempts, lockedUntil
- Preferences: theme, timezone
- Timestamps: createdAt, updatedAt, deletedAt (soft delete)
**Indexed on:** email, provider+providerId (unique), username
### **sessions Table**
Manages JWT sessions with device tracking and revocation support.
**Key fields:**
- Session ID, userId (FK to users)
- Device tracking: deviceInfo, userAgent, ipAddress
- Token hashes: accessTokenHash, refreshTokenHash (SHA-256)
- Revocation: isRevoked, revokedAt, revokedReason
- Expiry: expiresAt (default 3 days), lastActivity
**Configuration:** Max 5 sessions per user, 3 concurrent devices
### **oauthStates Table**
Temporary storage for OAuth flow state tokens (CSRF protection).
**Key fields:**
- state (unique CSRF token), provider (google/github)
- codeVerifier (PKCE), redirectUri
- isUsed (one-time use), expiresAt (10 minutes)
**Security:** Prevents CSRF attacks, implements PKCE flow
### **apiKeys Table**
Stores hashed API keys for programmatic access.
**Key fields:**
- name, keyHash (SHA-256), keyPreview
- scopes (JSON array), isActive
- Usage: lastUsed, requestCount
- Optional: expiresAt
### **authAttempts Table**
Audit log for all authentication attempts.
**Purpose:** Track login/register attempts, detect suspicious activity
**Fields:** identifier (email), attemptType, success, ipAddress, timestamp
### **verificationOtps Table**
Email verification codes. The email-OTP verification flow has been removed (users are auto-verified on registration), so nothing reads or writes this table; the table is retained only to avoid a destructive migration.
**Fields:** email, otp (hashed), used, expiresAt (15 min)
### **auditLogs Table**
Detailed audit trail for security events.
**Fields:** userId, entityType/entityId, action, oldValues/newValues (JSON), ipAddress, userAgent
---
## AuthService - Core Operations
**Location:** `/worker/database/services/AuthService.ts`
Handles all authentication operations (login, register, OAuth) and delegates session management to SessionService.
### **register() Flow**
1. Validate email format and password strength (min 8 chars, mixed case, numbers)
2. Check email doesn't already exist
3. Hash password with bcrypt (12 rounds)
4. Create user with emailVerified=true (no OTP currently)
5. Auto-login: create session + generate JWT
6. Log attempt to authAttempts table
7. Return user + accessToken + sessionId
### **login() Flow**
1. Find user by email (case-insensitive), check not deleted
2. Verify passwordHash exists
3. Compare password with bcrypt.verify()
4. Create session + generate JWT
5. Log attempt (success/fail) with IP + user agent
6. Return user + accessToken + sessionId
**Security:** Failed attempts logged, passwords never logged
### **OAuth Flow**
**Step 1: getOAuthAuthorizationUrl()**
1. Cleanup expired OAuth states
2. Validate redirect URL (same-origin only)
3. Generate CSRF state token + PKCE code verifier
4. Store in oauthStates table (10 min expiry)
5. Build authorization URL with state + code_challenge
6. Return URL to redirect user to provider
**Step 2: handleOAuthCallback()**
1. Verify state token (not used, not expired)
2. Mark state as used
3. Exchange code for tokens using PKCE verifier
4. Fetch user info from provider
5. Find or create user (update OAuth info if exists)
6. Create session + JWT
7. Return user + token + intended redirectUrl
**Security:** CSRF protected, PKCE prevents code interception, one-time state tokens
### **Other Key Methods**
**getUserForAuth(userId):** Fetch user by ID (checks not deleted) - used by middleware
**validateTokenAndGetUser(token):** Complete pipeline: verify JWT signature โ check expiration โ fetch user โ return user + sessionId
---
## JWTUtils - Token Management
**Location:** `/worker/utils/jwtUtils.ts`
Singleton class for JWT operations using `jose` library.
**Token payload contains:** userId (sub), email, sessionId, type (access/refresh), iat/exp timestamps
**Key operations:**
- **createAccessToken()** - Sign JWT with HS256, 3-day expiry
- **verifyToken()** - Verify signature, check expiration, return payload
- **hashToken()** - SHA-256 hash for database storage (security: prevents token leakage from DB breaches)
---
## SessionService - Session Management
**Location:** `/worker/database/services/SessionService.ts`
**Config:** Max 5 sessions/user, 3-day TTL, max 3 concurrent devices
**Key operations:**
1. **createSession()** - Cleanup old sessions (keep 5 most recent) โ generate session ID โ create JWT โ hash token โ extract request metadata (IP, user agent, Cloudflare headers) โ store in D1
2. **revokeUserSession()** - Mark session as revoked with reason
3. **revokeAllUserSessions()** - Revoke all user sessions (for password change, security breach)
4. **getUserSessions()** - List active sessions (not revoked, not expired)
5. **getUserSecurityStatus()** - Analyze security: count active sessions + recent security events โ calculate risk level (high: >5 events/24h or hijacking; medium: >2 events or >3 devices; low: normal)
6. **forceLogoutAllOtherSessions()** - Delete all sessions except current (for suspected compromise)
7. **cleanupExpiredSessions()** - Delete expired sessions (run via cron)
---
## OAuth Providers
**Location:** `/worker/services/oauth/`
Abstract base class provides common OAuth 2.0 flow with PKCE.
**PKCE Flow:**
1. Generate code_verifier (random 32 bytes)
2. Hash to create code_challenge (SHA-256)
3. Send challenge in authorization URL
4. Provider stores challenge
5. Exchange code + verifier for tokens
6. Provider verifies: hash(verifier) === stored_challenge
**Purpose:** Prevents authorization code interception attacks
### **Google OAuth**
- Scopes: openid, email, profile
- Fetches user info from Google API
- Returns: id, email, name, picture, verified_email
- Env vars: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
### **GitHub OAuth**
- Scopes: read:user, user:email (minimal, no repo access)
- Special handling: Email not always in /user endpoint, fetches from /user/emails if needed
- Returns: id, email (primary verified), name, avatar_url
- Env vars: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
---
## Authentication Middleware
**Location:** `/worker/middleware/auth/routeAuth.ts`
**Three auth levels:**
1. **public** - No auth required
2. **authenticated** - Requires valid JWT
3. **owner-only** - Requires ownership of resource (e.g., user can only edit their own apps)
**Flow:**
1. Route declares auth level via `setAuthLevel()` middleware
2. `enforceAuthRequirement()` checks:
- Public: pass through
- Authenticated/Owner: extract token โ validate JWT โ fetch user โ check ownership if needed
3. User injected into request context: `c.set('user', user)`
4. Route handler executes with authenticated user
**Token extraction priority:** Authorization header (APIs) โ Cookie (browser) โ Query param (WebSocket)
---
## Security Features
### **Password Security**
- **Hashing:** bcrypt with 12 rounds (~250ms, intentionally slow to prevent brute force)
- **Validation:** Min 8 chars, mixed case, numbers, special chars, not common password, no sequential patterns (12345)
- **Strength scoring:** 0-4 scale
### **Rate Limiting**
- User-configurable limits (default: 100 requests/min)
- Separate limits for auth endpoints
- Tracked per user/IP in Durable Objects or KV
### **CSRF Protection**
- OAuth state tokens: cryptographically random, 10-min expiry, one-time use
- Verified on callback to prevent cross-site request forgery
### **Session Security**
- Tokens hashed (SHA-256) in database
- 3-day expiry by default
- Device + IP tracking
- Max 5 sessions per user, 3 concurrent devices
- Force logout feature for security incidents
### **Audit Logging**
- All auth attempts logged to `authAttempts` table
- Includes: IP, user agent, timestamp, success/failure
- Used for security analysis and anomaly detection
---
# ๐๏ธ DATABASE LAYER
## Overview
The database layer uses **Cloudflare D1** (SQLite) with **Drizzle ORM** for type-safe queries. All database operations are abstracted through service classes that extend `BaseService`.
**Key Technologies:**
- **D1 Database:** Serverless SQLite on Cloudflare's edge
- **Drizzle ORM:** Type-safe SQL query builder
- **D1 Sessions API:** Read replicas for lower latency
- **Migrations:** SQL-based schema migrations
---
## Database Architecture
```
/* Detailed source-code truncated for AI context efficiency. */
```
---
## BaseService Pattern
**Location:** `/worker/database/services/BaseService.ts`
### **Purpose**
Provides common database functionality to all domain services:
- Database connection management
- Read replica access (D1 Sessions API)
- Type-safe where condition building
- Error handling patterns
- Logging
### **Implementation**
```typescript
abstract class BaseService {
protected logger = createLogger(this.constructor.name);
protected db: DatabaseService;
protected env: Env;
constructor(env: Env) {
this.db = createDatabaseService(env);
this.env = env;
}
// Direct database access (primary)
protected get database() {
return this.db.db;
}
// Read replica access (optimized latency)
protected getReadDb(strategy: 'fast' | 'fresh' = 'fast') {
return this.db.getReadDb(strategy);
}
// Build type-safe WHERE conditions
protected buildWhereConditions(
conditions: (SQL | undefined)[]
): SQL | undefined {
const validConditions = conditions.filter(
(c): c is SQL => c !== undefined
);
if (validConditions.length === 0) return undefined;
if (validConditions.length === 1) return validConditions[0];
return and(...validConditions);
}
// Standard error handling
protected handleDatabaseError(
error: unknown,
operation: string,
context?: Record
): never {
this.logger.error(`Database error in ${operation}`, { error, context });
throw error;
}
}
```
---
## D1 Sessions API - Read Replicas
### **What is D1 Sessions?**
Cloudflare D1 Sessions API provides **read replicas** for D1 databases distributed globally. This dramatically reduces latency for read queries by serving them from the nearest replica.
### **Strategies**
**Location:** `/worker/database/database.ts`
```typescript
class DatabaseService {
getReadDb(strategy: 'fast' | 'fresh' = 'fast') {
if (strategy === 'fast') {
// Lowest latency - may be slightly stale
return drizzle(this.env.DB, { ... });
} else {
// Latest data - may have higher latency
return drizzle(this.env.DB.withSession({ strategy: 'fresh' }), { ... });
}
}
}
```
### **When to Use Each Strategy**
#### **'fast' Strategy (Default)**
**Use for:**
- Public app listings
- Public app details
- Analytics and stats
- Search results
- Any read-only public data
**Benefits:**
- **Lowest latency** (served from nearest replica)
- Suitable for data that can tolerate slight staleness (few seconds)
- Most queries should use this
**Example:**
```typescript
// Public apps - use fast replicas
async getPublicApps(options: PublicAppQueryOptions) {
const readDb = this.getReadDb('fast'); // โ Use fast strategy
const apps = await readDb
.select()
.from(schema.apps)
.where(eq(schema.apps.visibility, 'public'));
}
```
#### **'fresh' Strategy**
**Use for:**
- User's own data (own apps, favorites)
- Immediately after writes (read-after-write)
- Auth/session validation
- Account settings
- Any data where staleness is unacceptable
**Benefits:**
- **Latest data** from primary or recent replica
- Ensures user sees their own changes immediately
**Example:**
```typescript
// User's own apps - use fresh data
async getUserApps(userId: string) {
const readDb = this.getReadDb('fresh'); // โ Use fresh strategy
const apps = await readDb
.select()
.from(schema.apps)
.where(eq(schema.apps.userId, userId));
}
```
### **NEVER Use Read Replicas For:**
โ **Write operations** - Always use primary (`this.database`)
โ **Auth validation** - Use primary to avoid security issues
โ **Immediately after INSERT/UPDATE** - Read from primary
โ **Critical consistency** - Password changes, payments, etc.
---
## Drizzle ORM Patterns
### **Basic Queries**
#### **SELECT**
```typescript
// Simple select
const users = await db
.select()
.from(schema.users)
.where(eq(schema.users.email, email));
// Select specific columns
const users = await db
.select({
id: schema.users.id,
email: schema.users.email
})
.from(schema.users);
// With JOIN
const apps = await db
.select({
app: schema.apps,
userName: schema.users.displayName
})
.from(schema.apps)
.leftJoin(schema.users, eq(schema.apps.userId, schema.users.id));
```
#### **INSERT**
```typescript
// Insert one
const [user] = await db
.insert(schema.users)
.values({
id: generateId(),
email: 'user@example.com',
displayName: 'User',
createdAt: new Date()
})
.returning();
// Insert many
await db
.insert(schema.apps)
.values([
{ id: id1, title: 'App 1', ... },
{ id: id2, title: 'App 2', ... }
]);
```
#### **UPDATE**
```typescript
await db
.update(schema.users)
.set({
displayName: 'New Name',
updatedAt: new Date()
})
.where(eq(schema.users.id, userId));
```
#### **DELETE**
```typescript
// Hard delete
await db
.delete(schema.sessions)
.where(eq(schema.sessions.id, sessionId));
// Soft delete (preferred)
await db
.update(schema.users)
.set({ deletedAt: new Date() })
.where(eq(schema.users.id, userId));
```
### **Complex Queries**
#### **Aggregations**
```typescript
// COUNT
const result = await db
.select({ count: sql`COUNT(*)` })
.from(schema.apps)
.where(eq(schema.apps.visibility, 'public'));
const total = result[0].count;
// SUM, AVG
const stats = await db
.select({
totalViews: sql`SUM(${schema.appViews.id})`,
avgViews: sql`AVG(view_count)`
})
.from(schema.apps);
```
#### **Subqueries**
```typescript
// Subquery in WHERE
const apps = await db
.select()
.from(schema.apps)
.where(
inArray(
schema.apps.id,
db.select({ id: schema.favorites.appId })
.from(schema.favorites)
.where(eq(schema.favorites.userId, userId))
)
);
```
#### **Conditional WHERE Clauses**
```typescript
// Use BaseService.buildWhereConditions()
const conditions: WhereCondition[] = [];
if (framework) {
conditions.push(eq(schema.apps.framework, framework));
}
if (search) {
conditions.push(
or(
sql`LOWER(${schema.apps.title}) LIKE ${`%${search}%`}`,
sql`LOWER(${schema.apps.description}) LIKE ${`%${search}%`}`
)
);
}
const whereClause = this.buildWhereConditions(conditions);
const apps = await db
.select()
.from(schema.apps)
.where(whereClause);
```
---
## Domain Services
### **Available Services**
**Location:** `/worker/database/services/`
1. **AuthService** - Authentication, login, OAuth
2. **SessionService** - JWT sessions, token management
3. **UserService** - User CRUD, profiles
4. **AppService** - App CRUD, public listings, search, ranking
5. **AnalyticsService** - Views, stars, activity tracking
6. **SecretsService** - Encrypted secrets storage
7. **ModelConfigService** - User model overrides
8. **ApiKeyService** - API key generation, validation
Each extends BaseService, uses Drizzle ORM, follows standard CRUD patterns.
---
## AppService - Public App Ranking
**Key methods:** createApp, getPublicApps (paginated with filters), getUserAppsWithFavorites, toggleAppStar, updateDeploymentId, updateGitHubRepository, updateAppScreenshot
**Ranking algorithms:**
- **Popular:** (views ร 1 + stars ร 3) DESC
- **Trending:** (recent_activity ร 1000000 + recency_bonus) DESC
- **Recent:** updatedAt DESC
- **Starred:** COUNT(stars) DESC
**Read replica usage:** Public queries use 'fast', user's own data uses 'fresh'
---
## Database Migrations
**Location:** `/migrations/` (SQL files + meta snapshots)
**Commands:**
- `npm run db:generate` - Generate migration from schema changes
- `npm run db:migrate:local` - Apply to local D1
- `npm run db:migrate:remote` - Apply to production D1
- `npm run db:push:local` - Direct push (dev only)
**Tool:** Drizzle Kit with d1-http driver
---
## ๐ Key Files Reference
### **Frontend Core Files**
- `/src/api-types.ts` - ALL shared API types (single source of truth)
- `/src/lib/api-client.ts` - ALL API calls defined here
- `/src/routes/chat/chat.tsx` - Main chat interface (1208 lines)
- `/src/routes/chat/hooks/use-chat.ts` - Chat state management (BRAIN)
- `/src/routes/chat/utils/handle-websocket-message.ts` - WebSocket handler (831 lines)
- `/src/routes/chat/utils/deduplicate-messages.ts` - Message deduplication utilities
- `/src/routes/chat/components/phase-timeline.tsx` - Phase progress UI
- `/src/routes/chat/components/messages.tsx` - User/AI message rendering
- `/src/hooks/useAuthGuard.ts` - Authentication guards
- `/src/hooks/use-image-upload.ts` - Image upload handling
### **Backend Core Files**
- `/worker/agents/core/simpleGeneratorAgent.ts` - Base agent DO class
- `/worker/agents/core/state.ts` - CodeGenState interface
- `/worker/agents/core/websocket.ts` - WebSocket message handler (250 lines)
- `/worker/agents/constants.ts` - WebSocket message type constants
- `/worker/agents/inferutils/core.ts` - LLM inference engine
- `/worker/agents/inferutils/infer.ts` - Inference execution wrapper
- `/worker/agents/inferutils/config.ts` - Model configurations
- `/worker/agents/assistants/codeDebugger.ts` - Deep debugger assistant
- `/worker/agents/operations/UserConversationProcessor.ts` - Orange AI (818 lines)
- `/worker/agents/tools/customTools.ts` - Tool registration
- `/worker/api/routes/index.ts` - Main API router
- `/worker/database/schema.ts` - Database schema (618 lines)
### **Configuration Files**
- `/worker/agents/inferutils/config.ts` - LLM model configs
- `/wrangler.jsonc` - Cloudflare Workers config
- `/vite.config.ts` - Frontend build config
- `/tsconfig.json` - TypeScript config
- `/drizzle.config.local.ts` - Local database config
- `/drizzle.config.remote.ts` - Remote database config
---
## โ Checklist for Changes
Before submitting any change, verify:
- [ ] Types are properly defined (no `any`)
- [ ] Existing patterns are followed
- [ ] Code is DRY (no duplication)
- [ ] Comments are clear and concise
- [ ] File naming matches conventions
- [ ] API calls use `api-client.ts`
- [ ] Database operations use service classes
- [ ] Error handling is comprehensive
- [ ] AbortController lifecycle is correct (if applicable)
- [ ] WebSocket messages are handled (if applicable)
- [ ] This document is updated (if needed)
---
## ๐ง Troubleshooting Common Issues
### **Issue: "Cannot find module" errors**
**Cause:** Import path incorrect or module not installed
**Fix:**
1. Check import path matches file location
2. For workspace imports, use `worker/...` not `../../../...`
3. Run `npm install` if package missing
4. Check `tsconfig.json` path mappings
### **Issue: Durable Object not receiving WebSocket messages**
**Check:**
1. Message type in constants: `/worker/agents/constants.ts`
2. Handler in `/worker/agents/core/websocket.ts` โ `handleWebSocketMessage()`
3. Frontend sending correct type (check browser console)
4. WebSocket connection established (check `agent_connected` received)
**Debug:**
```typescript
// Add to websocket.ts handleWebSocketMessage()
logger.info('Received WebSocket message', { type: message.type, data: message });
```
### **Issue: LLM not calling tools**
**Common causes:**
1. Tool description unclear โ LLM doesn't know when to use it
2. Tool not registered in `buildTools()` or `buildDebugTools()`
3. Parameter schema too complex โ simplify
4. System prompt doesn't mention tool
**Fix:**
- Keep tool description to 2-3 clear lines
- Make parameters simple (prefer strings over complex objects)
- Add tool to relevant system prompt
### **Issue: Database query returning stale data**
**Cause:** Using read replica for data that needs to be fresh
**Fix:**
```typescript
// WRONG - uses fast replica
const readDb = this.getReadDb('fast');
// RIGHT - uses fresh data
const readDb = this.getReadDb('fresh');
// OR use primary for critical consistency
const result = await this.database.select()...
```
### **Issue: "Rate limit exceeded" during development**
**Quick fix:**
```typescript
// In UserConversationProcessor.ts or codeDebugger.ts
// Temporarily increase max_tokens or reduce frequency
```
**Better fix:** Use cheaper model for testing
```typescript
// In config.ts
conversationalResponse: {
name: GEMINI_2_5_FLASH, // Fast & cheap
max_tokens: 4000,
}
```
### **Issue: Type errors after schema change**
**Steps:**
1. Regenerate Drizzle types: `npm run db:generate`
2. Restart TypeScript server in IDE
3. Check migration applied: `npm run db:migrate:local`
### **Issue: Sandbox deployment failing**
**Check logs:**
```typescript
// In DeploymentManager.ts, enable verbose logging
this.logger.info('Deployment attempt', {
sessionId: this.getSessionId(),
filesCount: files.length
});
```
**Common causes:**
1. Sandbox service unreachable
2. Invalid template name
3. sessionId mismatch (check `agent.state.sessionId`)
4. npm install timeout โ increase timeout or split commands
### **Issue: Agent state not persisting**
**Verify:**
1. Check DO storage: Cloudflare dashboard โ Durable Objects
2. Ensure `setState()` called after changes
3. Check for exceptions in state serialization
**Test:**
```typescript
const currentState = this.getState();
this.logger().info('State before save', { currentState });
this.setState(newState);
this.logger().info('State after save', { newState });
```
### **Where to Look for Logs**
**Local development:**
- Frontend: Browser console
- Worker: Terminal where `npm run dev:worker` is running
- Durable Objects: Same terminal, prefixed with DO ID
**Production:**
- Cloudflare dashboard โ Workers & Pages โ Logs
- Real-time logs via `wrangler tail`
- Sentry (if configured)
### **Useful Debug Snippets**
**Log all WebSocket messages:**
```typescript
// In websocket.ts
logger.info('[WS_IN]', { type: message.type, keys: Object.keys(message) });
```
**Log all tool calls:**
```typescript
// In customTools.ts executeToolWithDefinition()
logger.info('[TOOL_CALL]', { name: toolDef.function.name, args });
```
**Log state transitions:**
```typescript
// In simpleGeneratorAgent.ts launchStateMachine()
logger.info('[STATE_TRANSITION]', {
from: currentDevState,
to: executionResults.currentDevState
});
```
---
# ๐ RATE LIMITING
## Overview
**Location:** `/worker/middleware/rate-limiter.ts`
Rate limiting protects API endpoints from abuse using token bucket algorithm with Durable Object storage.
---
## Implementation
**Middleware:** Applied to all API routes except health checks
**Strategy:**
- **Token bucket algorithm** - Tokens refill over time
- **Per-user basis** - Keyed by userId (authenticated) or IP (anonymous)
- **Durable Object storage** - Distributed rate limit state
- **Graceful degradation** - Falls back on DO errors
---
## Rate Limits
| User Type | Requests | Window | Burst |
|-----------|----------|--------|-------|
| **Authenticated** | 100 | 1 minute | 150 |
| **Anonymous** | 20 | 1 minute | 30 |
| **API Keys** | 300 | 1 minute | 400 |
**Burst:** Maximum requests in short burst before throttling
---
## Response Headers
```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1698765432
```
**On rate limit exceeded:**
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json
{
"error": "Rate limit exceeded",
"retryAfter": 42
}
```
---
## Frontend Handling
**Location:** `/src/routes/chat/utils/message-helpers.ts`
```typescript
export function handleRateLimitError(
error: RateLimitExceededError,
setMessages: (fn: (prev: ChatMessage[]) => ChatMessage[]) => void
) {
const retryAfter = error.retryAfter || 60;
const message = `Rate limit exceeded. Please wait ${retryAfter} seconds.`;
setMessages(prev => [
...prev,
createAIMessage('rate-limit', message)
]);
}
```
**Usage:**
```typescript
catch (error) {
if (error instanceof RateLimitExceededError) {
handleRateLimitError(error, setMessages);
return;
}
// ... other error handling
}
```
---
## Bypassing for Internal Tools
Some endpoints bypass rate limiting:
- Health checks (`/health`, `/api/health`)
- WebSocket connections (rate limited separately)
- Internal service-to-service calls (authenticated with service tokens)
**Configuration:**
```typescript
// In rate-limiter.ts
const EXEMPT_PATHS = ['/health', '/api/health'];
```
---
## Monitoring
**Cloudflare Analytics:**
- 429 response rate
- Peak request times
- Top rate-limited IPs
**Custom Logs:**
```typescript
logger.warn('Rate limit exceeded', {
userId: ctx.userId,
ip: ctx.ip,
path: ctx.path,
remaining: 0
});
```
---
**Last Updated:** 2024-10-31
**Maintainers:** All AI assistants working on this project
---
### POSTMAN COLLECTION README
# Legacy V1 Dev API Postman Collection
> This collection documents the legacy V1 Dev/phasic API surface and has not been migrated to the current Think behavior. Verify routes and payloads against `worker/api/routes/` before using it for current integrations.
The collection remains available for compatibility testing of supported legacy endpoints, OAuth setup, and CSRF behavior.
## ๐ Overview
This collection includes **100+ API endpoints** organized into logical groups:
- ๐ **Authentication** - OAuth, email auth, session management (16 endpoints)
- ๐ค **Agent & Code Generation** - AI-powered webapp creation (5 endpoints)
- ๐ฑ **Apps Management** - CRUD operations, public feed, favorites (10 endpoints)
- ๐ค **User Management** - Profile, apps with pagination (2 endpoints)
- ๐ **Analytics & Stats** - User stats, AI Gateway analytics (4 endpoints)
- ๐ค **Model Configuration** - AI model settings, BYOK providers (8 endpoints)
- ๐ข **Custom Model Providers** - OpenAI-compatible API management (6 endpoints)
- ๐ **Secrets Management** - API keys, credentials with templates (5 endpoints)
- ๐ **GitHub Integration** - Repository export, OAuth (2 endpoints)
## ๐ Quick Setup
### 1. Import Collection & Environment
1. **Import Collection**:
- Open Postman โ Import โ Upload `v1dev-api-collection.postman_collection.json`
2. **Import Environment**:
- Import โ Upload `v1dev-environment.postman_environment.json`
3. **Select Environment**:
- Choose "V1 Dev Environment" from the environment dropdown
### 2. Configure Base URL
Update the `baseUrl` environment variable:
- **Production**: `https://your-production-domain.com`
- **Local Development**: `http://localhost:8787` (Wrangler dev server)
### 3. OAuth Setup in Postman
โ ๏ธ **IMPORTANT**: OAuth endpoints redirect to external providers (Google/GitHub) and cannot be tested directly in Postman.
#### ๐ Recommended Approach: OAuth Helper Requests
1. **Use the OAuth Helper requests**:
- Run "๐ OAuth Helper - Get Google URL"
- Check the **Console tab** in Postman for the OAuth URL
- Copy the URL and open it in your browser
2. **Complete authentication in browser**:
- Follow the OAuth flow in your browser
- After successful auth, you'll be redirected back to your app
- Session cookies are now set for your domain
3. **Return to Postman**:
- Session cookies will work automatically for same-domain requests
- Test with "Get User Profile" to verify authentication
#### Alternative: Manual URL Construction
If helpers don't work, manually construct URLs:
- **Google OAuth**: `{{baseUrl}}/api/auth/oauth/google`
- **GitHub OAuth**: `{{baseUrl}}/api/auth/oauth/github`
- Open these URLs directly in your browser
#### Why Direct OAuth Requests Show HTML
- OAuth endpoints return HTTP redirects (302) to provider websites
- Postman shows the redirect HTML instead of following it
- This is normal behavior - OAuth requires browser-based flows
### 4. CSRF Token Automation
The collection automatically handles CSRF tokens:
- Pre-request scripts fetch CSRF tokens when needed
- Tokens are stored in the `csrf_token` environment variable
- All state-changing requests include the token automatically
## ๐ Authentication Methods
### 1. Email Authentication
```json
POST /api/auth/register
{
"email": "user@example.com",
"password": "SecurePassword123!",
"name": "Test User"
}
POST /api/auth/login
{
"email": "user@example.com",
"password": "SecurePassword123!"
}
```
### 2. OAuth Authentication
- **Google OAuth**: `GET /api/auth/oauth/google`
- **GitHub OAuth**: `GET /api/auth/oauth/github`
### 3. Session-Based Authentication
- Uses secure HTTP-only cookies
- Sessions are automatically maintained across requests
- CSRF protection via `X-CSRF-Token` header
## ๐ฑ Core API Workflows
### 1. Create a New App with AI
```bash
# 1. Login or use OAuth
POST /api/auth/login
# 2. Start code generation
POST /api/agent
{
"query": "Create a React todo app with TypeScript and Tailwind CSS",
"agentMode": "smart",
"language": "typescript",
"frameworks": ["react", "tailwindcss"],
"selectedTemplate": "react-typescript"
}
# 3. Connect to WebSocket for real-time updates
GET /api/agent/{agentId}/ws (WebSocket)
# 4. Deploy preview when ready
GET /api/agent/{agentId}/preview
```
### 2. Browse and Interact with Apps
```bash
# Get public apps (no auth required)
GET /api/apps/public?page=1&limit=20&sort=stars&order=desc
# Get app details (no auth required)
GET /api/apps/{appId}
# Star an app (requires auth)
POST /api/apps/{appId}/star
# Fork an app (requires auth)
POST /api/apps/{appId}/fork
```
### 3. Configure AI Models
```bash
# Get available models and providers
GET /api/model-configs/byok-providers
# Update model configuration for specific agent action
PUT /api/model-configs/planner
{
"modelName": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7,
"reasoningEffort": "medium"
}
# Test model configuration
POST /api/model-configs/test
{
"agentActionName": "planner",
"useUserKeys": true
}
```
### 4. Manage API Keys and Secrets
```bash
# Get secret templates
GET /api/secrets/templates
# Store an API key
POST /api/secrets
{
"templateId": "openai_api_key",
"name": "My OpenAI API Key",
"envVarName": "OPENAI_API_KEY",
"value": "sk-your-api-key-here"
}
# Create custom model provider
POST /api/user/providers
{
"name": "My Custom OpenAI Provider",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-your-key",
"models": [...]
}
```
## ๐ง Advanced Features
### Environment Variables
The collection uses these automatically managed variables:
| Variable | Description | Auto-populated |
|----------|-------------|----------------|
| `csrf_token` | CSRF protection token | โ |
| `user_id` | Current user ID | โ |
| `session_id` | Current session ID | โ |
| `agent_id` | Current agent/app ID | โ |
| `app_id` | Current app ID | โ |
| `provider_id` | Model provider ID | Manual |
| `secret_id` | Secret ID | Manual |
### Request Automation
- **CSRF Tokens**: Automatically fetched and included
- **Session Management**: Cookies handled transparently
- **Variable Population**: IDs extracted from responses
- **Error Handling**: Test scripts validate responses
### WebSocket Testing
For WebSocket endpoints like agent communication:
1. Use a WebSocket client (wscat, Postman WebSocket, etc.)
2. Connect to: `ws://localhost:8787/api/agent/{agentId}/ws`
3. Include authentication cookies
4. Send/receive real-time messages during code generation
## ๐ ๏ธ Development Setup
### Local Development
1. **Start Wrangler Dev Server**:
```bash
cd /path/to/vibesdk
bun run dev
```
2. **Update Environment**:
- Set `baseUrl` to `http://localhost:8787`
- Ensure `.dev.vars` contains required environment variables
3. **Test Authentication**:
- OAuth may require ngrok for localhost callback URLs
- Email auth works directly with localhost
### Production Testing
1. Update `baseUrl` to your production domain
2. Ensure OAuth apps are configured with correct callback URLs
3. Test with real OAuth credentials
## ๐ API Documentation
### Authentication Levels
- **Public**: No authentication required
- **Authenticated**: Requires valid session
- **Owner Only**: Requires ownership of the resource
### Common Parameters
| Parameter | Description | Example |
|-----------|-------------|---------|
| `page` | Page number for pagination | `1` |
| `limit` | Items per page | `20` |
| `sort` | Sort field | `createdAt`, `stars` |
| `order` | Sort order | `asc`, `desc` |
| `period` | Time period filter | `today`, `week`, `month`, `all` |
| `search` | Search query | `"todo app"` |
### Response Format
All API responses follow this structure:
```json
{
"success": true,
"data": { ... },
"message": "Optional message",
"pagination": { // For paginated responses
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}
```
### Error Responses
```json
{
"success": false,
"error": "Error message",
"code": "ERROR_CODE",
"details": { ... } // Optional additional details
}
```
## ๐จ Troubleshooting
### Common Issues
1. **CSRF Token Errors**:
- Ensure pre-request scripts are enabled
- Manually run "Get CSRF Token" request
- Check that `X-CSRF-Token` header is included in POST/PUT/DELETE requests
2. **Authentication Issues**:
- Verify cookies are enabled in Postman
- Check that OAuth callback URLs match your configuration
- Ensure session hasn't expired (check "Get User Profile")
3. **WebSocket Connection Issues**:
- WebSockets require active session authentication
- Use external WebSocket client if Postman WebSocket support is limited
- Verify agent ownership for WebSocket connections
4. **Local Development Issues**:
- Ensure Vite is running (`bun run dev`)
- Check that `.dev.vars` contains required environment variables
- Verify D1 migrations are applied (`bun run db:migrate:local`)
### Getting Help
1. **Check API Response**: Look at response body for detailed error messages
2. **Verify Environment**: Ensure correct `baseUrl` is set
3. **Test Authentication**: Run "Check Auth Status" to verify session
4. **Review Logs**: Check browser DevTools or Wrangler logs for additional context
## ๐ฏ Testing Workflows
### Complete User Journey
1. **Register/Login** โ Authentication working
2. **Create App** โ AI generation working
3. **Browse Public Apps** โ Public feed working
4. **Star/Fork App** โ Social features working
5. **Configure Models** โ AI customization working
6. **Manage Secrets** โ Security features working
7. **Export to GitHub** โ Integration working
### Quick Health Check
Run these requests to verify the system:
1. `GET /api/auth/providers` - System status
2. `GET /api/apps/public` - Public API working
3. `POST /api/auth/login` - Authentication working
4. `GET /api/model-configs` - AI system working
5. `GET /api/stats` - Analytics working
This collection provides comprehensive coverage of all V1 Dev APIs with proper authentication, error handling, and real-world usage examples. Perfect for development, testing, and integration work!
---
### Setup
# VibeSDK Setup Guide
Set up VibeSDK for local development and production deployment.
**Make sure to read through the entire guide for important notes, and have all the required information ready before starting.**
Current generated-app previews use SpaceDO, a Worker Loader binding, and Dynamic Workers. Cloudflare Artifacts is optional behind `ENABLE_ARTIFACTS`; it is not required for the default SQLite workspace filesystem. Previews do not require a sandbox container or persistent preview server.
## Prerequisites
Before getting started, make sure you have:
### Required
- **Node.js** (v22 or later)
- **Cloudflare account** with API access
- **Cloudflare API Token** with appropriate permissions
### Recommended
- **Bun**
- **Custom domain** configured in Cloudflare (for production deployment)
### For Production Features
- **Workers Paid Plan** (for remote Cloudflare resources)
- **Workers for Platforms** subscription (for app deployment features)
- **Advanced Certificate Manager** (if using first-level subdomains)
## Quick Start
The fastest way to get VibeSDK running is with our automated setup script:
```bash
# Bun is recommended. Install it first if needed.
curl -fsSL https://bun.sh/install | bash
# Then install dependencies and run setup
bun install
bun run setup
```
This interactive script will guide you through the entire setup process, including:
- **Package manager setup** (installs Bun automatically for better performance)
- **Cloudflare credentials** collection (Account ID and API Token)
- **Domain configuration** (custom domain or localhost for development)
- **Remote setup** (optional production deployment configuration)
- **AI Gateway configuration** (Cloudflare AI Gateway recommended)
- **API key collection** (OpenAI, Anthropic, Google AI Studio, etc.)
- **OAuth setup** (Google, GitHub login - optional)
- **Resource creation** (KV namespaces, D1 databases, R2 buckets, AI Gateway)
- **File generation** (`.dev.vars` and optionally `.prod.vars`)
- **Configuration updates** (`wrangler.jsonc` and `vite.config.ts`)
- **Database setup** (schema generation and migrations)
- **Template deployment** (example app templates to R2)
- **Readiness report** (comprehensive status and next steps)
## What You'll Need During Setup
The setup script will ask you for the following information:
### Cloudflare Account Information
1. **Account ID**: Found in your Cloudflare dashboard sidebar
2. **API Token**: In you Cloudflare dashboard under "My Profile" > "API Tokens", create a token (Using the "Edit Cloudflare Workers" template is recommended) with the following configurations:
- Your Account - Workers KV Storage:Edit, Workers Scripts:Edit, Account Settings:Read, Workers Tail:Read, Workers R2 Storage:Edit, Cloudflare Pages:Edit, Workers Builds Configuration:Edit, Workers Agents Configuration:Edit, Workers Observability:Edit, Containers:Edit, D1:Edit, AI Gateway:Read, AI Gateway:Edit, AI Gateway:Run, Cloudchamber:Edit, Browser Rendering:Edit
- All zones - Workers Routes:Edit
- All users - User Details:Read, Memberships:Read
**If using the `Edit Cloudflare Workers` template, make sure to add the missing permissions above manually.**
**Important**: Some features like D1 databases and R2 may require a paid Cloudflare plan.
### Domain Configuration
**With Custom Domain:**
```bash
Enter your custom domain (or press Enter to skip): myapp.com
โ Custom domain set: myapp.com
Use remote Cloudflare resources (KV, D1, R2, etc.)? (Y/n):
Configure for production deployment? (Y/n):
```
**Without Custom Domain:**
```bash
Enter your custom domain (or press Enter to skip): [press Enter]
โ ๏ธ No custom domain provided.
โข Remote Cloudflare resources: Not available
โข Production deployment: Not available
โข Only local development will be configured
Continue with local-only setup? (Y/n):
```
### AI Gateway Configuration
**Cloudflare AI Gateway (Recommended)**
- **Automatic token setup**: When selected, `CLOUDFLARE_AI_GATEWAY_TOKEN` is automatically set to your API token
- **No manual configuration**: The script handles all AI Gateway authentication
- **Better performance**: Caching, rate limiting, and monitoring included
**Custom OpenAI URL (Alternative)**
- For users with existing OpenAI-compatible endpoints
- Requires manual model configuration in `worker/agents/inferutils/config.ts`
### AI Provider Selection
The setup script offers multiple AI providers with intelligent multi-selection:
**Available Providers:**
1. **OpenAI** (for GPT models)
2. **Anthropic** (for Claude models)
3. **Google AI Studio** (for Gemini models) - **Default & Recommended**
4. **Cerebras** (for open source models)
5. **OpenRouter** (for various models)
6. **Custom provider** (for any other provider)
**Provider Selection:**
- Select multiple providers with comma-separated numbers (e.g., `1,2,3`)
- Each selected provider will prompt for its API key
- Custom providers automatically generate `PROVIDER_NAME_API_KEY` variables
- Custom providers are automatically added to `worker-configuration.d.ts`
### Important Model Configuration Notes
**Google AI Studio (Recommended):**
- Default model configurations use Gemini models
- No additional `worker/agents/inferutils/config.ts` editing required
- Best compatibility - This is the model used in the official deployment at https://build.cloudflare.dev
- You can get a free API key from https://aistudio.google.com/
**Other Providers:**
- **Strong warning**: You MUST edit `worker/agents/inferutils/config.ts`
- Change default model configurations from Gemini to your selected providers
- Model format: `/` (e.g., `openai/gpt-4`, `anthropic/claude-3.5-sonnet`)
- Review fallback model configurations
**Without AI Gateway:**
- **Manual config.ts editing required** for all model configurations
- Model names must follow `/` format
### OAuth Configuration
The script will also ask for OAuth credentials:
- **Google OAuth**: For user authentication and login (not AI Studio access)
- **GitHub OAuth**: For user authentication and login
- **GitHub Export OAuth**: For exporting generated apps to GitHub repositories (separate from login OAuth)
**If you don't provide OAuth credentials, by default at login, you will only be able to use email-based registration/login.**
### Login with Cloudflare
You can let users sign in with their Cloudflare account. The same consent also
connects their Cloudflare AI Gateway, so generations can run on their own credits
("Use my AI Gateway" toggle in settings).
**1. Create an OAuth client**
Create an OAuth client in the Cloudflare dashboard:
Configure these **redirect URLs** on the client (replace the origin with your
deployment's URL; for local development this is `http://localhost:5173`):
- `https://your-domain.com/api/auth/callback/cloudflare` โ "Login with Cloudflare"
- `https://your-domain.com/auth/callback` โ connect AI Gateway (from settings)
Grant the client these **scopes** (Cloudflare uses dotted identifiers, not OIDC
`email`/`profile`):
```
openid user-details.read ai.read ai.write aig.read aig.run aig.write offline_access
```
The scopes and the Cloudflare OAuth endpoint URLs are hardcoded in the worker
(`worker/services/oauth/cloudflare-connect.ts`) and are not configurable โ just make
sure the OAuth client is authorized for all of these scopes, or the authorization
request fails with `invalid_scope`.
**2. Set the environment variables**
Add the client credentials to `.dev.vars` (and `.prod.vars` for production):
```bash
CLOUDFLARE_OAUTH_CLIENT_ID="" # required for Login with Cloudflare
CLOUDFLARE_OAUTH_CLIENT_SECRET=""
CF_OAUTH_ENCRYPTION_KEY="<32-byte base64 key>" # required for AI Gateway; encrypts the token cookie
```
Set `ENABLE_CLOUDFLARE_LIMITS="true"` in the Cloudflare dashboard for production, or in `.dev.vars` for local development.
The **"Login with Cloudflare" button** appears as soon as `CLOUDFLARE_OAUTH_CLIENT_ID`
and `CLOUDFLARE_OAUTH_CLIENT_SECRET` are set โ identity login needs nothing else.
The **AI Gateway connect/auto-connect** (running generations on the user's own
credits) additionally requires the dashboard-managed `ENABLE_CLOUDFLARE_LIMITS="true"` and
`CF_OAUTH_ENCRYPTION_KEY` (generate with `openssl rand -base64 32`). If the key is
missing, the gateway feature is disabled (same as leaving `ENABLE_CLOUDFLARE_LIMITS`
unset) and login simply skips the gateway auto-connect โ users fall back to the free
tier and can connect later.
### Generated-app preview requirements
Generated-app previews use the `SPACE_DO` and `LOADER` bindings. Add the `ARTIFACTS` binding for Artifacts-backed spaces. Docker is not required for the current Think/SpaceDO preview path. `SandboxDockerfile` and container setup remain only for legacy tooling.
### Dashboard-managed feature toggles
Feature settings are intentionally omitted from the committed wrangler `vars`. For deployed environments, set them in the Cloudflare dashboard; `keep_vars: true` preserves their values when `wrangler deploy` runs. For local development, set them in `.dev.vars`. Do not add these settings back to `wrangler.jsonc` or `wrangler.staging.jsonc`.
| Variable | Effect | Unset default | Notes |
| --- | --- | --- | --- |
| `ENABLE_ARTIFACTS` | Uses Artifacts-backed spaces | Off | Requires the `ARTIFACTS` binding. |
| `ENABLE_READ_REPLICAS` | Enables D1 read replicas | Off | Set to `"true"` to enable. |
| `ENABLE_EMAIL_AUTH` | Enables email/password authentication | On | Set to `"false"` to make the deployment OAuth-only. |
| `ENABLE_CLOUDFLARE_LIMITS` | Enables AI Gateway connect | Off | Requires `CF_OAUTH_ENCRYPTION_KEY`; set to `"true"` to enable. |
| `ENABLE_USER_ACCOUNT_DEPLOY` | Deploys Think apps to the user's Cloudflare account | Off | Set to `"true"` to enable. |
| `ALLOWED_EMAIL` | Restricts sign-in to one email address | Off | Set the allowed address; empty or unset disables the allowlist. |
| `ALLOCATION_STRATEGY` | Selects the legacy sandbox allocation strategy | Default strategy | Managed in the dashboard rather than through production secrets. |
| `USE_CLOUDFLARE_IMAGES` | Enables Cloudflare Images uploads | Off | Set a non-empty value to enable. |
| `USE_TUNNEL_FOR_PREVIEW` | Uses a tunnel for local previews | Off | Dev-only; set in `.dev.vars`, not the production dashboard. |
Existing deployments retain previously configured dashboard values when this configuration is deployed. New deployments must explicitly set `ENABLE_READ_REPLICAS="true"` or `ENABLE_CLOUDFLARE_LIMITS="true"` in the dashboard to preserve the former committed defaults.
## Manual Setup (Alternative)
If you prefer to set up manually:
### 1. Create `.dev.vars` file
Copy `.dev.vars.example` to `.dev.vars` and fill in your values:
```bash
cp .dev.vars.example .dev.vars
```
### 2. Configure Required Variables
```bash
# Essential
CLOUDFLARE_API_TOKEN="your-api-token"
CLOUDFLARE_ACCOUNT_ID="your-account-id"
# Security
JWT_SECRET="generated-secret"
# Domain (optional)
CUSTOM_DOMAIN="your-domain.com"
```
### 3. Create Cloudflare Resources
Create required resources in your Cloudflare account:
- KV Namespace for `VibecoderStore`
- D1 Database named `vibesdk-db`
- R2 Bucket named `vibesdk-templates`
### 4. Update `wrangler.jsonc`
Update resource IDs in `wrangler.jsonc` with the IDs from step 3.
## Starting Development
After setup is complete:
```bash
# Set up database
bun run db:migrate:local
# Start development server
bun run dev
```
Visit your app at `http://localhost:5173`
**Important Note**: If you didn't specifiy any oauth credentials during setup, You would need to register an account for the first time.
## Troubleshooting
### Common Issues
**D1 Database "Unauthorized" Error**: This usually means:
- Your API token lacks "D1:Edit" permissions
- Your account doesn't have access to D1 (may require paid plan)
- You've exceeded your D1 database quota
- **Solution**: Update your API token permissions or upgrade your Cloudflare plan
**Permission Errors**: Ensure your API token has all required permissions listed above.
**Domain Not Found**: Make sure your domain is:
- Added to Cloudflare
- DNS is properly configured
- API token has zone permissions
**Resource Creation Failed**: Check that your account has:
- Available KV namespace quota (10 on free plan)
- D1 database quota (may require paid plan)
- R2 bucket quota (may require paid plan)
- Appropriate plan level for requested features
**R2 Bucket "Unauthorized" Error**: This usually means:
- Your API token lacks "R2:Edit" permissions
- Your account doesn't have access to R2 (may require paid plan)
- You've exceeded your R2 bucket quota
- **Solution**: Update your API token permissions or upgrade your Cloudflare plan
**AI Configuration Issues**:
- **"AI Gateway token already configured" but token not in .dev.vars**: Re-run setup, this was a bug that's now fixed
- **Models not working with custom providers**: Edit `worker/agents/inferutils/config.ts` to change default model configurations
- **Custom provider not recognized**: Check that the provider was added to `worker-configuration.d.ts`
- **AI Gateway creation failed**: Ensure your API token has AI Gateway permissions
**Dynamic Worker Preview Issues**:
- Confirm the `SPACE_DO` and `LOADER` bindings are configured; confirm `ARTIFACTS` only when `ENABLE_ARTIFACTS="true"`.
- Check the branch deployment and signed preview URL.
- Use `bun run dev:browser` when local browser-console inspection is needed.
**Deploy to Cloudflare Button Issues (Chat Interface)**:
- **"Deploy button not working locally"**: Chat interface deploy button requires custom domain, initial deployment, and remote dispatch bindings
- **"Dispatch namespace not found"**: Deploy your VibeSDK project to Cloudflare at least once first
- **"Deploy fails with authentication error"**: Ensure your custom domain is properly configured and deployed
- **Note**: This refers to deploying generated apps from the chat interface, not GitHub repository deployments
**Legacy Corporate Container Setup**:
The following certificate setup applies only when intentionally running legacy Docker-based tooling:
1. **Copy your corporate root CA certificate** to the project root (don't commit to git!)
2. **Edit SandboxDockerfile** to include your certificate:
```dockerfile
# Add your company's Root CA certificate for corporate network access
COPY your-root-ca.pem /usr/local/share/ca-certificates/your-root-ca.crt
RUN update-ca-certificates
# Set SSL environment variables for cloudflared and other tools
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/your-root-ca.crt
ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
```
**โ ๏ธ Security Warning**: Never commit corporate CA certificates to public repositories. Use `.gitignore` to exclude certificate files and only use this for local development.
### Getting Help
1. Check the setup report for specific issues and suggestions
2. Review the Cloudflare Workers documentation
3. Ensure all prerequisites are met
## Production Deployment
If you configured remote deployment during setup, you'll have a `.prod.vars` file ready for production. Deploy with:
```bash
bun run deploy
```
This will:
- Build the application
- Update Cloudflare resources
- Deploy to Cloudflare Workers
- Apply database migrations
- Configure custom domain routing (if specified)
### Production-Only Setup
If you only set up for local development initially, you can configure production later:
1. **Run setup again** and choose "yes" for remote deployment configuration
2. **Provide production domain** when prompted
3. **Deploy** using `bun run deploy`
### Manual Production Setup
Alternatively, create `.prod.vars` manually based on `.dev.vars` but with:
- Production domain in `CUSTOM_DOMAIN`
- Production API keys and secrets
- `ENVIRONMENT="prod"`
## Next Steps
Once setup is complete:
1. **Start developing** with `bun run dev`
2. **Visit** `http://localhost:5173` to access VibeSDK
3. **Try generating** your first AI-powered application
4. **Deploy to production** when ready with `bun run deploy`
## File Structure After Setup
The setup script creates and modifies these files:
```
vibesdk/
โโโ .dev.vars # Local development environment variables
โโโ .prod.vars # Production environment variables (if configured)
โโโ wrangler.jsonc # Updated with resource IDs and domain
โโโ vite.config.ts # Updated for remote/local bindings
โโโ migrations/ # Database migration files
โโโ templates/ # Template repository (downloaded)
```
## Summary
The VibeSDK setup script provides a comprehensive, intelligent configuration experience:
### **Key Features:**
- **Simplified domain setup** - One-time domain configuration with clear feature implications
- **Intelligent AI provider selection** - Multi-provider support with automatic configuration
- **AI Gateway automation** - Automatic token setup and configuration
- **Custom provider support** - Dynamic API key generation and worker configuration updates
- **Production-ready** - Both local development and production deployment configuration
- **User-friendly defaults** - Y/n prompts with clear default indicators
### **What Gets Configured:**
- Cloudflare resources (KV, D1, R2, AI Gateway, dispatch namespaces)
- Environment variables (.dev.vars and .prod.vars)
- Worker configuration (wrangler.jsonc, worker-configuration.d.ts)
- Database setup and migrations
- Template deployment
- ARM64 compatibility
The setup script handles everything from basic Cloudflare resource creation to advanced AI provider configuration, making it easy to get started regardless of your Cloudflare plan or AI provider preferences.
For any issues during setup, check the troubleshooting section above or refer to the comprehensive status report the script provides at the end.
## Important Caveats & Known Issues
### **Legacy tunnel and container configuration**
`USE_TUNNEL_FOR_PREVIEW`, `SandboxDockerfile`, and container instance settings belong to the retired sandbox preview path. Current generated-app previews run as Dynamic Workers loaded by SpaceDO. Do not troubleshoot the current preview path as a Docker or cloudflared tunnel unless you are intentionally running legacy tooling.
### **"Deploy to Cloudflare" Button Limitations (Chat Interface)**
The "Deploy to Cloudflare" button in the chat interface (for generated apps) has specific requirements for local development:
> **Note**: This refers to the deployment button within the VibeSDK platform's chat interface, not the GitHub repository deploy button.
**Requirements**:
1. **Custom domain** must be properly configured during setup
2. **Initial deployment** - Project must be deployed at least once to your Cloudflare account
3. **Remote dispatch bindings** - `wrangler.jsonc` must have remote dispatch namespace enabled
4. **Dispatch worker** - A dispatch worker must be running in your account
**Why These Requirements?**
- The deploy feature uses Cloudflare's dispatch namespace system
- Dispatch requires a running worker in your account to handle deployment requests
- Local-only development isn't yet supported for this in vibesdk
**Current Status**: Making "Deploy to Cloudflare" work completely in local-only mode is not yet implemented.
### **Dynamic Worker preview troubleshooting**
For current previews, verify the SpaceDO Durable Object binding, Worker Loader binding, branch deployment, and signed preview URL. Verify the Artifacts namespace only when `ENABLE_ARTIFACTS="true"`. Build failures originate in `@cloudflare/worker-bundler`; application runtime failures should be inspected through browser console logs. If an issue persists, open a GitHub issue with the setup report and deployment error.
---