Getting Started
Migration Guide
Upgrading between Surf versions — breaking changes, new features, and code examples
Migration Guide#
This guide covers breaking changes and upgrade paths between major Surf versions.
0.3.x / 0.4.x → 0.5.0#
Released: 2026-03-27
The 0.5.0 release unifies all package versions and adds Vue and Svelte support. If you're already on 0.3.x or 0.4.x, this is a smooth upgrade.
Unified Versioning
All packages are now versioned together at 0.5.0. Previously, @surfjs/react was on 0.4.x while other packages were on 0.3.x. Update all packages at once:
pnpm add @surfjs/core@latest @surfjs/client@latest @surfjs/react@latestNew Packages
@surfjs/vue— Vue 3 composables@surfjs/svelte— Svelte stores and context
SurfBadge Redesign
The SurfBadge visual style changed from rainbow/holographic to a consistent Surf blue. No API changes — purely cosmetic.
Error Codes
All @surfjs/client errors are now typed SurfClientError with a code property:
import { SurfClient, SurfClientError } from '@surfjs/client' try { await client.execute('search', { query: 'test' })} catch (err) { if (err instanceof SurfClientError) { switch (err.code) { case 'TIMEOUT': // handle timeout case 'NETWORK_ERROR': // handle network failure case 'NOT_CONNECTED': // handle disconnection case 'RATE_LIMITED': // handle rate limiting (check err.retryAfter) } }}0.1.x → 0.2.x#
Released: 2026-03-21
The 0.2.x release introduced security hardening, basePath support, and the @surfjs/web browser runtime. This is the most significant upgrade path.
Breaking: createSurf() is Now Async
The most impactful change. createSurf() returns a Promise<SurfInstance> as of Phase 7 (framework adapters). All call sites must be awaited.
Before (0.1.x):
import { createSurf } from '@surfjs/core' const surf = createSurf({ name: 'My API', commands: { /* ... */ },}) app.use(surf.middleware())After (0.2.x+):
import { createSurf } from '@surfjs/core' const surf = await createSurf({ name: 'My API', commands: { /* ... */ },}) app.use(surf.middleware())If you're using Express at the top level, wrap in an async IIFE or use top-level await:
// Option 1: top-level await (ESM)const surf = await createSurf({ /* ... */ })const app = express()app.use(surf.middleware())app.listen(3000) // Option 2: async IIFE;(async () => { const surf = await createSurf({ /* ... */ }) const app = express() app.use(surf.middleware()) app.listen(3000)})()New: basePath Configuration
The client SDK now supports custom execute paths, useful for @surfjs/next or custom routing setups:
// Clientconst client = await SurfClient.discover('https://myapi.com', { basePath: '/api/surf/execute',})New: @surfjs/web Browser Runtime
The 0.2.x series introduced window.surf — a local command dispatcher for browser-based agents. This is now the foundation for all framework integrations:
import { initSurf, registerCommand } from '@surfjs/web' initSurf({ endpoint: 'https://myapp.com' }) registerCommand('theme.toggle', { mode: 'local', run: () => { document.body.classList.toggle('dark') return { ok: true } },})See @surfjs/web for the full API.
Security Hardening (0.2.x)
Several security fixes shipped across 0.2.1–0.2.3. No API changes, but worth noting:
- Session tokens are now cryptographically random
- Hidden commands are fully stripped from unauthenticated manifests
- Error responses no longer leak stack traces in production
- Auth comparison uses constant-time equality
- Rate limiter state is cleaned up for expired sessions
New Framework Adapters
0.2.0 (Phase 7) added first-class adapters for:
These complement the existing Express surf.middleware() and the later Next.js adapter.
Scoped Auth
Phase 8 introduced requiredScopes on commands:
const surf = await createSurf({ authVerifier: async (token, command) => { const user = await verifyToken(token) if (!user) return { valid: false, reason: 'Invalid token' } return { valid: true, claims: { userId: user.id }, scopes: user.scopes } }, commands: { 'admin.stats': { description: 'Server statistics', auth: 'required', requiredScopes: ['admin:read'], run: async (_params, ctx) => getStats(), }, },})See Scoped Auth for details.
Dependency Updates#
When upgrading, ensure your peer dependencies are compatible:
| Package | Minimum Node.js | TypeScript | Zod (if using @surfjs/zod) | |---------|-----------------|------------|---------------------------| | 0.5.x | 18+ | 5.0+ | 3.x | | 0.2.x–0.3.x | 18+ | 5.0+ | 3.x | | 0.1.x | 16+ | 4.9+ | 3.x |
TypeScript Configuration
For 0.2.x+ with top-level await, ensure your tsconfig.json targets ES2022+:
{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "strict": true }}