valet-dev
v0.0.20
Published
[](https://www.npmjs.com/package/valet-dev) [](https://github.com/expo/valet/blob/main/LICENSE)
Readme
valet-dev
Local-first, real-time sync SDK for building reactive applications with automatic offline support and replay-based conflict resolution.
Valet is a TypeScript SDK that enables building modern local-first applications with real-time sync capabilities, similar to Convex. It provides React hooks, automatic sync, offline support, and deterministic replay for conflict resolution.
Features
- 🔄 Real-time Sync - Automatic synchronization between client and server
- 💾 Local-First - Client maintains a local SQLite replica for instant queries
- 🔌 Offline Support - Full functionality without network connection
- ⚛️ React Integration - First-class React hooks (
useQuery,useMutation) - 🔐 Authentication - Built-in auth with automatic token refresh
- 🛡️ Type Safety - End-to-end TypeScript types with code generation
- 🔀 Conflict Resolution - Deterministic replay for seamless multi-user collaboration
Installation
npm install valet-dev
# or
bun add valet-devQuick Start
1. Define Your Schema
Create a schema file (e.g., valet/schema.ts):
import { defineSchema, defineTable } from 'valet-dev/server'
import { v } from 'valet-dev/server'
export default defineSchema({
todos: defineTable({
title: v.string(),
completed: v.number(),
userId: v.string(),
}),
})2. Define Queries and Mutations
Create your API functions (e.g., valet/todos.ts):
import { defineQuery, defineMutation, v } from '../_generated/valet/api'
export const list = defineQuery({
args: {
completed: v.optional(v.number()),
},
execution: 'local',
handler: async (ctx, args) => {
let query = ctx.db.query('todos')
if (args.completed !== undefined) {
query = query.filter((q) => q.eq('completed', args.completed))
}
return query.collect()
},
})
export const create = defineMutation({
args: {
title: v.string(),
},
handler: async (ctx, args) => {
return ctx.db.insert('todos', {
title: args.title,
completed: 0,
userId: ctx.auth?.userId ?? 'anonymous',
})
},
})3. Use in Your React App
import { ValetProvider, useQuery, useMutation } from './_generated/valet/react'
import { api } from './_generated/valet/api'
function App() {
return (
<ValetProvider
url="wss://your-app.valet.host/ws"
authToken={() => getAuthToken()}
>
<TodoList />
</ValetProvider>
)
}
function TodoList() {
const { data: todos } = useQuery(api.todos.list, { completed: 0 })
const createTodo = useMutation(api.todos.create)
return (
<div>
{todos?.map(todo => (
<div key={todo._id}>{todo.title}</div>
))}
<button onClick={() => createTodo.mutate({ title: 'New task' })}>
Add Todo
</button>
</div>
)
}Package Exports
The package provides several entry points for different use cases:
valet-dev- Core client library (protocol types, message serialization)valet-dev/react- React hooks and components (useQuery,useMutation,ValetProvider)valet-dev/server- Server function definitions (validators, schema, query/mutation builders)valet-dev/local- Local database client for browser environmentsvalet-dev/qb- Query builder for constructing filtersvalet-dev/codegen- Code generation utilities (CLI:valet-dev codegen)
Code Generation
Valet includes a code generator that creates type-safe TypeScript definitions from your schema:
# Generate types once
npx valet-dev codegen
# Watch mode for development
npx valet-dev codegen --watchThis generates:
- Type definitions for your schema
- Fully-typed
apiobject with all your queries and mutations - Custom
ValetProviderand hooks with your schema types
API Overview
React Hooks
useQuery(api.namespace.query, args)- Subscribe to a query with automatic updatesuseMutation(api.namespace.mutation)- Get a mutation function to modify datauseConnectionState()- Monitor connection status (connected, connecting, disconnected)useValetAuth()- Access authentication state and user infouseValetClient()- Access the underlying client for advanced operations
Query Execution Modes
local- Executes in the browser against local SQLite replica (instant, offline-capable)server- Executes on the server with full database access
Context API
Inside query/mutation handlers, access:
ctx.db- Database query and mutation operationsctx.auth- Authentication info (userId, token claims)
Development
# Install dependencies
bun install
# Build the package
bun run build
# Run type checking
bun run typecheck
# Run tests
bun testDocumentation
For complete documentation, architecture details, and examples:
- See the main repository README
- Check out the demo app for a full working example
- Explore detailed docs for architecture and specifications
License
See LICENSE file.
