### Install Dependencies and Build Source: https://github.com/evoluhq/evolu/blob/main/examples/angular-vite-pwa/README.md Installs project dependencies, builds common and web packages, and starts the development server for the Angular Vite PWA example. ```bash # From the repository root... pnpm install pnpm --filter @evolu/common --filter @evolu/web build # Start development server pnpm --filter @example/angular-vite-pwa dev # Build to test the PWA pnpm --filter @example/angular-vite-pwa build # Then serve, for example... python3 -m http.server --directory examples/angular-vite-pwa/dist ``` -------------------------------- ### Run iOS Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Runs the iOS example application. Ensure the relay server is started first. ```bash pnpm ios ``` -------------------------------- ### Dev Server for React Next.js Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts the development server for the React Next.js example application. ```bash pnpm examples:react-nextjs:dev ``` -------------------------------- ### Run Android Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Runs the Android example application. Ensure the relay server is started first. ```bash pnpm android ``` -------------------------------- ### Build All Examples Source: https://github.com/evoluhq/evolu/blob/main/README.md Builds all example applications within the project. ```bash pnpm examples:build ``` -------------------------------- ### Dev Server for Svelte Vite PWA Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts the development server for the Svelte Vite PWA example application. ```bash pnpm examples:svelte-vite-pwa:dev ``` -------------------------------- ### Dev Server for Vue Vite PWA Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts the development server for the Vue Vite PWA example application. ```bash pnpm examples:vue-vite-pwa:dev ``` -------------------------------- ### Dev Server for React Vite PWA Example Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts the development server for the React Vite PWA example application. ```bash pnpm examples:react-vite-pwa:dev ``` -------------------------------- ### Toggle Dependencies for Examples Source: https://github.com/evoluhq/evolu/blob/main/README.md Toggles dependencies for working on examples with local packages. This command must be run before working on examples. ```bash pnpm examples:toggle-deps ``` -------------------------------- ### Run Evolu Relay with Docker Source: https://github.com/evoluhq/evolu/blob/main/apps/relay/README.md Pull the latest Evolu Relay Docker image and run it on port 4000. This is the fastest way to get started. ```bash docker pull docker.io/evoluhq/relay:latest docker run --rm -p 4000:4000 docker.io/evoluhq/relay:latest ``` -------------------------------- ### Install React SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common, react, and react-web SDKs for React applications. ```bash npm install @evolu/common @evolu/react @evolu/react-web ``` -------------------------------- ### Install Vanilla JS SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common and web SDKs for Vanilla JavaScript applications. ```bash npm install @evolu/common @evolu/web ``` -------------------------------- ### Install Vue SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common, web, and vue SDKs for Vue applications. ```bash npm install @evolu/common @evolu/web @evolu/vue ``` -------------------------------- ### Start Relay and Web Servers Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts both the relay and web development servers for local development. ```bash pnpm dev ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/evoluhq/evolu/blob/main/README.md Installs all necessary dependencies for the Evolu monorepo using pnpm. ```bash pnpm install ``` -------------------------------- ### Install Svelte SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common, web, and svelte SDKs for Svelte applications. ```bash npm install @evolu/common @evolu/web @evolu/svelte ``` -------------------------------- ### Create Evolu for Vanilla JS Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx This snippet shows the basic setup for creating an Evolu instance in a Vanilla JavaScript environment using web dependencies. ```js import { createEvolu, Name } from "@evolu/common"; import { evoluWebDeps } from "@evolu/web"; const evolu = createEvolu(evoluWebDeps)(Schema, { appName: Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); ``` -------------------------------- ### Start Relay Server Only Source: https://github.com/evoluhq/evolu/blob/main/README.md Starts only the relay server. This is useful for mobile development. ```bash pnpm relay ``` -------------------------------- ### Install React Native SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common, react, react-native SDKs along with necessary native dependencies for React Native. ```bash npm install @evolu/common @evolu/react @evolu/react-native \n @op-engineering/op-sqlite react-native-quick-crypto ``` -------------------------------- ### Install Evolu Common Package Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/library/page.mdx Install the core Evolu library package using npm. This is the first step to begin using Evolu in your project. ```bash npm install @evolu/common ``` -------------------------------- ### Create Evolu for React Native (Expo) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Initialize Evolu for React Native applications built with Expo, utilizing the Expo SQLite dependency. The setup mirrors other React examples but uses the Expo-specific module. ```tsx import { createEvolu, Name } from "@evolu/common"; import { createUseEvolu, EvoluProvider } from "@evolu/react"; import { evoluReactNativeDeps } from "@evolu/react-native/expo-sqlite"; const evolu = createEvolu(evoluReactNativeDeps)(Schema, { appName: Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); // Wrap your app with {/* ... */} // Create a typed React Hook returning an instance of Evolu const useEvolu = createUseEvolu(evolu); // Use the Hook in your app const { insert, update } = useEvolu(); ``` -------------------------------- ### Run Next.js Development Server Source: https://github.com/evoluhq/evolu/blob/main/examples/react-nextjs/README.md Commands to start the Next.js development server using npm, yarn, or pnpm. Open http://localhost:3000 in your browser to view the application. ```bash npm run dev # or yarn dev # or pnpm dev ``` -------------------------------- ### Install Expo SDK Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Install the common, react, react-native SDKs with Expo-specific SQLite and crypto modules for Expo applications. ```bash npm install @evolu/common @evolu/react @evolu/react-native \n expo-sqlite react-native-quick-crypto ``` -------------------------------- ### Create Evolu for Vue Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Initialize Evolu for a Vue.js application. This example uses `provideEvolu` to make the Evolu instance available throughout the component tree and exposes insert/update methods. ```ts import { defineComponent } from "vue"; import { createEvolu, Name } from "@evolu/common"; import { evoluWebDeps } from "@evolu/web"; import { provideEvolu } from "@evolu/vue"; const evolu = createEvolu(evoluWebDeps)(Schema, { appName: Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); export default defineComponent({ setup() { provideEvolu(evolu); const { insert, update } = evolu; return { insert, update }; }, }); ``` -------------------------------- ### Install Playwright Browsers Source: https://github.com/evoluhq/evolu/blob/main/README.md Installs the browsers required by Playwright for local testing and verification runs. This should be run again after Playwright updates or if the browser cache is cleared. ```bash pnpm playwright:install ``` -------------------------------- ### Create Evolu for React Native (Bare Op) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx This snippet shows how to initialize Evolu for React Native using the bare-op SQLite dependency. It's similar to the React setup but uses platform-specific dependencies. ```tsx import { createEvolu, Name } from "@evolu/common"; import { createUseEvolu, EvoluProvider } from "@evolu/react"; import { evoluReactNativeDeps } from "@evolu/react-native/bare-op-sqlite"; const evolu = createEvolu(evoluReactNativeDeps)(Schema, { appName: Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); // Wrap your app with {/* ... */} // Create a typed React Hook returning an instance of Evolu const useEvolu = createUseEvolu(evolu); // Use the Hook in your app const { insert, update } = useEvolu(); ``` -------------------------------- ### Install JavaScript Explicit Resource Management Polyfills Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/library/page.mdx Import and call `installPolyfills` during application startup to ensure compatibility with JavaScript explicit resource management features, which are not yet supported in all browsers like Safari. This is crucial before using Evolu. ```typescript import { installPolyfills } from "@evolu/common/polyfills"; installPolyfills(); ``` -------------------------------- ### Passing Multiple Dependencies (Verbose Attempt) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx This example shows a verbose way of passing multiple dependencies (`Time` and `Logger`) to a function using currying. It highlights potential issues with managing many dependencies. ```typescript const timeUntilEvent = (time: Time, logger: Logger) => (eventTimestamp: number): number => { logger.log("..."); const currentTime = time.now(); return eventTimestamp - currentTime; }; ``` -------------------------------- ### Query Data in Vanilla JS Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Demonstrates querying data once using `loadQuery` and subscribing to query changes using `subscribeQuery` in plain JavaScript. Includes how to get rows from a query. ```typescript // Query once const todos = await evolu.loadQuery(allTodos); const unsubscribe = evolu.subscribeQuery(allTodos)(() => { const rows = evolu.getQueryRows(allTodos); // do something with rows }); ``` -------------------------------- ### Sync Phase Metadata Example Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/scaling-local-first-software/page.mdx This snippet illustrates the sync phase metadata within a protocol message. It indicates the current state of data synchronization and the type of range information that follows. ```typescript [0, 1, 2, 31] ``` -------------------------------- ### Create Identicon Function Call Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/building-identicons-with-ai-lessons-learned/page.mdx This is an example of how to call the `createIdenticon` function with an owner ID and a specific style. Ensure the owner ID is provided and the desired style is selected. ```typescript const svg = createIdenticon(ownerId, "sutnar"); ``` -------------------------------- ### Access App Owner Mnemonic in Vue Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx This example demonstrates how to retrieve the app owner's mnemonic in a Vue.js application using the `useEvolu` composable. The mnemonic is available asynchronously. ```ts import { useEvolu } from "@evolu/vue"; const evolu = useEvolu(); const owner = await evolu.appOwner; console.log(owner.mnemonic); ``` -------------------------------- ### Example Evolu Schema Definition Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/migrations/page.mdx Defines a simple schema for 'Todo' items, including an ID, title, and an optional completion status. Note the use of `nullOr` for optional fields. ```typescript const TodoId = id("Todo"); const Schema = { todo: { id: TodoId, title: NonEmptyString100, isCompleted: nullOr(SqliteBoolean), }, }; ``` -------------------------------- ### Dependency Injection Interfaces and Example Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/effect-like-code-without-effect/page.mdx Defines interfaces for dependencies like Time and Logger, and demonstrates a convention-based dependency injection pattern in TypeScript. Optional dependencies are handled using `Partial`. ```typescript export interface Time { readonly now: () => number; } export interface TimeDep { readonly time: Time; } export interface Logger { readonly log: (message?: any, ...optionalParams: Array) => void; } export interface LoggerDep { readonly logger: Logger; } const timeUntilEvent = // Partial makes LoggerDep optional (deps: TimeDep & Partial) => (eventTimestamp: number): number => { deps.logger?.log("Calculating time until event..."); const currentTime = deps.time.now(); return eventTimestamp - currentTime; }; /** Creates a {@link Time} using Date.now(). */ export const createTime = (): Time => ({ now: () => Date.now(), }); /** Creates a {@link Logger} using console.log. */ export const createLogger = (): Logger => ({ log: (...args) => { console.log(...args); }, }); const enableLogging = true; const deps: TimeDep & Partial = { time: createTime(), // Inject a dependency conditionally ...(enableLogging && { logger: createLogger() }), }; timeUntilEvent(deps)(1742329310767); ``` -------------------------------- ### Example Binary Protocol Message (Fingerprints) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/scaling-local-first-software/page.mdx This snippet shows a sample byte array representing a protocol message used for larger syncs, containing fingerprints instead of full timestamp data. It demonstrates the compact representation for extensive data reconciliation. ```typescript [ 0, 185, 172, 128, 111, 7, 182, 206, 234, 32, 23, 112, 226, 170, 156, 211, 88, 0, 16, 247, 138, 215, 250, 238, 50, 203, 2, 187, 2, 200, 2, 201, 2, 205, 2, 217, 2, 201, 2, 131, 28, 230, 2, 217, 2, 175, 2, 205, 2, 238, 25, 135, 20, 0, 15, 183, 244, 1, 145, 23, 166, 60, 55, 15, 1, ] ``` -------------------------------- ### Check Database File Size Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Use the `exportDatabase` method to get the database content as a Blob and determine its size in bytes. This is useful for monitoring storage usage. ```typescript const database = await evolu.exportDatabase(); const sizeInBytes = database.length; console.log(`Database size: ${sizeInBytes} bytes`); ``` -------------------------------- ### Example Binary Protocol Message (Timestamps) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/scaling-local-first-software/page.mdx This snippet shows a sample byte array representing a protocol message containing timestamp data. It's used to illustrate the initial structure and size of messages with a moderate number of timestamps. ```typescript [ 0, 59, 193, 30, 13, 197, 129, 241, 80, 15, 255, 45, 234, 249, 223, 59, 136, 0, 1, 2, 31, 153, 253, 156, 250, 238, 50, 128, 220, 15, 246, 3, 165, 3, 194, 1, 183, 1, 183, 1, 157, 1, 168, 1, 180, 1, 165, 1, 247, 2, 219, 64, 252, 1, 179, 1, 203, 2, 193, 1, 227, 1, 200, 1, 222, 150, 18, 226, 55, 217, 28, 212, 64, 171, 66, 134, 3, 198, 1, 159, 1, 151, 1, 196, 1, 173, 62, 135, 33, 0, 31, 77, 160, 38, 240, 26, 164, 100, 89, 31, ] ``` -------------------------------- ### Build Docs and Web Source: https://github.com/evoluhq/evolu/blob/main/README.md Builds both the project documentation and the web interface. ```bash pnpm build:web ``` -------------------------------- ### Build Documentation Source: https://github.com/evoluhq/evolu/blob/main/README.md Builds the project documentation. This is required once after cloning or pulling. ```bash pnpm build:docs ``` -------------------------------- ### Build and Test Evolu Relay Locally with Docker Source: https://github.com/evoluhq/evolu/blob/main/apps/relay/README.md Build a local Docker image for the Evolu Relay and run it with a persistent data volume. Useful for development and testing changes. ```bash # From the repo root: build the image docker build -f apps/relay/Dockerfile -t evolu/relay:dev . # Run in background with persistent data volume docker run -d --name evolu-relay \ -p 4000:4000 \ -v evolu-relay-data:/app/data \ evolu/relay:dev # Follow logs (Ctrl+C to stop tailing) docker logs -f evolu-relay # Stop & remove when done docker rm -f evolu-relay ``` -------------------------------- ### Fast Web Build Source: https://github.com/evoluhq/evolu/blob/main/README.md Deletes the 'api-reference' directory and builds only the web interface. This is a faster build option. ```bash pnpm build:web:fast ``` -------------------------------- ### Demonstrate Dependency Over-providing and Lean Dependencies Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Illustrate how to structure application dependencies, showing that over-providing dependencies is acceptable, but over-depending is not. This ensures functions receive only what they need. ```typescript export interface TimeDep { readonly time: Time; } export interface LoggerDep { readonly logger: Logger; } const runApp = (deps: LoggerDep & TimeDep) => { // Over-providing is OK—doSomethingWithTime needs only TimeDep, // but passing the whole `deps` object is fine doSomethingWithTime(deps); doSomethingWithLogger(deps); }; const doSomethingWithTime = (deps: TimeDep) => { deps.time.now(); }; // Over-depending is not OK—this function requires TimeDep but doesn't use it const doSomethingWithLogger = (deps: LoggerDep & TimeDep) => { deps.logger.log("foo"); }; type AppDeps = LoggerDep & TimeDep; const appDeps: AppDeps = { logger: createLogger(), time: createTime(), }; runApp(appDeps); ``` -------------------------------- ### Create Local-Only Instance for Device Settings Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Set up a separate Evolu instance with `transports: []` to store device-specific settings that should not be synced across devices. This ensures data like UI preferences remains local. ```typescript const PreferencesId = id("Preferences"); type PreferencesId = typeof PreferencesId.Type; const DeviceSchema = { preferences: { id: PreferencesId, //whatever }, }; // Local-only instance for device settings (no sync) const deviceEvolu = createEvolu(evoluReactWebDeps)(DeviceSchema, { appName: Name.orThrow("MyApp-Device"), transports: [], // No sync - stays local to device }); ``` -------------------------------- ### Run Tests Source: https://github.com/evoluhq/evolu/blob/main/README.md Executes all defined tests for the project. ```bash pnpm test ``` -------------------------------- ### Create Evolu for Svelte Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx This snippet demonstrates how to create an Evolu instance for Svelte applications. It imports necessary modules from '@evolu/common' and '@evolu/svelte'. ```ts import * as Evolu from "@evolu/common"; import { evoluSvelteDeps } from "@evolu/svelte"; const evolu = Evolu.createEvolu(evoluSvelteDeps)(Schema, { appName: Evolu.Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); ``` -------------------------------- ### External Store for State Management in Svelte Source: https://github.com/evoluhq/evolu/blob/main/examples/svelte-vite-pwa/README.md Use an external store to manage component state that needs to be preserved across Hot Module Replacement (HMR) updates. This example demonstrates a basic writable store. ```typescript import { writable } from "svelte/store"; export default writable(0); ``` -------------------------------- ### Project Structure for Copy-Pasted Code Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/the-copy-paste-typescript-standard-library/page.mdx Illustrates a recommended project structure for organizing copy-pasted code snippets. ```text src/ _copypaste/ Evolu/ Result.ts app/ ... ``` -------------------------------- ### Build All Packages Source: https://github.com/evoluhq/evolu/blob/main/README.md Builds all packages within the monorepo. This is required once after cloning or pulling to generate IDE types. ```bash pnpm build ``` -------------------------------- ### Creating a Reusable Branded Type Factory for Trimmed Strings Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/scaling-local-first-software/page.mdx Demonstrates creating a reusable factory for branded types, specifically for trimmed strings. This pattern allows for consistent application of constraints like trimming. ```typescript const trimmed: BrandFactory<"Trimmed", string, TrimmedError> = (parent) => brand("Trimmed", parent, (value) => value.trim().length === value.length ? ok(value) : err({ type: "Trimmed", value }), ); interface TrimmedError extends TypeError<"Trimmed"> {} const formatTrimmedError = createTypeErrorFormatter( (error) => `A value ${error.value} is not trimmed`, ); const TrimmedString = trimmed(String); // string & Brand<"Trimmed"> type TrimmedString = typeof TrimmedString.Type; const TrimmedNote = trimmed(Note); ``` -------------------------------- ### Use Factory Function as a Dependency Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Show how to use a factory function (e.g., `createLogger`) as a dependency. This allows for delayed instantiation of dependencies, useful when prerequisites are not yet available. ```typescript export interface LoggerConfig { readonly level: "info" | "debug"; } export interface Logger { readonly log: ( message?: unknown, ...optionalParams: ReadonlyArray ) => void; } export type CreateLogger = (config: LoggerConfig) => Logger; export interface CreateLoggerDep { readonly createLogger: CreateLogger; } export const createLogger: CreateLogger = (config) => ({ log: (...args) => { console.log(`[${config.level}]`, ...args); }, }); type AppDeps = CreateLoggerDep & TimeDep; // Note we pass `createLogger` as a factory, not calling it yet. // It will be called later when LoggerConfig becomes available. const appDeps: AppDeps = { createLogger, time: createTime(), }; runApp(appDeps); ``` -------------------------------- ### Initialize Evolu Without Transports for Seeding Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Initialize Evolu with an empty `transports` array to prevent immediate syncing. After backend verification for a first-time user, seed data explicitly before enabling sync by recreating the Evolu instance with transports. ```typescript // Start without sync const evolu = createEvolu(evoluReactWebDeps)(Schema, { appName: Name.orThrow("MyApp"), transports: [], }); // After backend verification for first-time user if (isFirstLogin) { seedDefaultData(); } // Then enable sync by recreating with transports ``` -------------------------------- ### Managing Multiple Resources with `DisposableStack` Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/resource-management/page.mdx Shows how to use `DisposableStack` to manage the cleanup of multiple resources. Resources are disposed in the reverse order of acquisition when an early return occurs. ```typescript const processResources = (): Result => { using disposer = new DisposableStack(); const db = createResource("db"); if (!db.ok) return db; // disposer disposes nothing yet disposer.use(db.value); const file = createResource("file"); if (!file.ok) return file; // disposer disposes db disposer.use(file.value); return ok("processed"); }; // disposer disposes file, then db (reverse order) ``` -------------------------------- ### Run All Pre-Commit Checks Source: https://github.com/evoluhq/evolu/blob/main/README.md Runs all checks, including build, lint, and test, before a commit to ensure code quality. ```bash pnpm verify ``` -------------------------------- ### Describe Changes for Release Log Source: https://github.com/evoluhq/evolu/blob/main/README.md Generates a description of changes for the release log using the changeset tool. ```bash pnpm changeset ``` -------------------------------- ### Evolu Type: Custom Factories and Complex Objects Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/effect-like-code-without-effect/page.mdx Shows how to create custom factories using regular expressions and define complex object structures with nested types using Evolu's Type library. ```typescript // Many factories export const Name = regex("Name", /^[a-z0-9-]{1,42}$/i)(NonEmptyString); // string & Brand<"MinLength1"> & Brand<"Name"> export type Name = typeof Name.Type; // Complex objects const User = object({ id: Id, email: Email, createdAt: optional(DateIso), }); ``` -------------------------------- ### Access App Owner Mnemonic in Vanilla JS Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx A straightforward way to access the app owner's mnemonic in plain JavaScript. This assumes Evolu has been initialized and is accessible. ```javascript const owner = await evolu.appOwner; console.log(owner.mnemonic); ``` -------------------------------- ### Define Indexes During Initialization Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/indexes/page.mdx Define indexes for your database schema when creating an Evolu instance. Evolu automatically manages the creation and dropping of these indexes based on the provided array. ```typescript const evolu = createEvolu(evoluReactWebDeps)(Schema, { // ... indexes: (create) => [create("todoCreatedAt").on("todo").column("createdAt")], }); ``` -------------------------------- ### Insert and Update Todo Item Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Demonstrates inserting a new todo item and then updating it. This pattern is common for creating and modifying records in Evolu. ```tsx const { insert, update } = useEvolu(); const result = insert("todo", { title: "New Todo", isCompleted: Evolu.sqliteFalse, }); if (result.ok) { update("todo", { id: result.value.id, isCompleted: Evolu.sqliteTrue }); } ``` ```ts const result = evolu.insert("todo", { title: "New Todo", isCompleted: Evolu.sqliteFalse, }); if (result.ok) { evolu.update("todo", { id: result.value.id, isCompleted: Evolu.sqliteTrue }); } ``` -------------------------------- ### Evolu Type: Branded Constraints and Basic Validation Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/effect-like-code-without-effect/page.mdx Demonstrates how to define branded constraints for strings and perform basic validation using Evolu's Type library, which returns a Result type. ```typescript // Branded constraints const NonEmptyString = minLength(1)(String); // string & Brand<"MinLength1"> type NonEmptyString = typeof NonEmptyString.Type; // Basic validation with Result const result = NonEmptyString.from("hello"); // Ok const error = NonEmptyString.from(""); // Err> ``` -------------------------------- ### Restore Synced Data with Mnemonic Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Use `evolu.restoreAppOwner(mnemonic)` to restore synced data on any device. This requires the correct mnemonic associated with the data. ```ts evolu.restoreAppOwner(mnemonic); ``` -------------------------------- ### Create Evolu for React Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Use this snippet to create an Evolu instance for a React application. It requires wrapping the app with EvoluProvider and uses a custom hook for accessing Evolu instance methods. ```tsx import { createEvolu, Name } from "@evolu/common"; import { createUseEvolu, EvoluProvider } from "@evolu/react"; import { evoluReactWebDeps } from "@evolu/react-web"; const evolu = createEvolu(evoluReactWebDeps)(Schema, { appName: Name.orThrow("your-app-name"), transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com }); // Wrap your app with {/* ... */} // Create a typed React Hook returning an instance of Evolu const useEvolu = createUseEvolu(evolu); // Use the Hook in your app const { insert, update } = useEvolu(); ``` -------------------------------- ### Direct Import (Tight Coupling) Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Directly importing a service like a database instance creates tight coupling, making it difficult to test or refactor. ```typescript import { db } from "./db"; // 🚨 Direct import creates tight coupling ``` -------------------------------- ### Use DisposableStack for Resource Cleanup Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/resource-management/page.mdx Shows the recommended way to manage multiple resources using DisposableStack. This ensures proper disposal and handles potential errors during cleanup. ```typescript // Use using disposer = new DisposableStack(); for (const resource of resources) { disposer.use(resource); } ``` -------------------------------- ### Importing a Copy-Pasted Result Type Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/the-copy-paste-typescript-standard-library/page.mdx Demonstrates how to import the Result type and its associated functions from a local copy-pasted file. ```typescript import { Result, ok, err, trySync, tryAsync, getOrThrow, } from "./_copypaste/Evolu/Result.js"; ``` -------------------------------- ### Create a Query for All Todos Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Defines a type-safe query using Evolu's integration with Kysely to select all entries from the 'todo' table. ```typescript const allTodos = evolu.createQuery((db) => db.selectFrom("todo").selectAll()); ``` -------------------------------- ### Named Imports and Exports Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/conventions/page.mdx Use named exports and named imports for clarity. Avoid namespaces as Evolu re-exports everything through a single index.ts. ```typescript import { bar, baz } from "Foo.ts"; export { bar, baz }; ``` -------------------------------- ### Convert External IDs to Evolu IDs Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Use `createIdFromString` to generate deterministic Evolu IDs from external system identifiers. This ensures consistency across clients. For type safety, specify the table name. ```typescript import { createIdFromString } from "@evolu/common"; // Convert external API ID to Evolu ID const evoluId = createIdFromString("user-api-123"); upsert("todo", { id: evoluId, title: "Task from external system", }); // With table branding for type safety const todoId = createIdFromString<"Todo">("external-todo-456"); ``` -------------------------------- ### Store Local-Only Data with Underscore Prefix Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Utilize tables prefixed with an underscore (`_`) to store data locally within an existing Evolu instance that should never be synced. This is efficient for drafts or temporary data. ```typescript const Schema = { // Regular synced table document: { id: DocumentId, title: NonEmptyString1000, content: NonEmptyString, }, // Local-only table (underscore prefix) _documentDraft: { id: DocumentId, title: NonEmptyString1000, content: NonEmptyString, }, }; // Save draft locally on every keystroke (no sync) evolu.upsert("_documentDraft", { id: documentId, title, content, }); // When ready to sync (e.g., on blur, route change) evolu.update("_documentDraft", { id: documentId, isDeleted: true }); evolu.upsert("document", { id: documentId, title, content }); ``` -------------------------------- ### Immutable Update Patterns Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/conventions/page.mdx Demonstrates the difference between mutable and immutable updates. Prefer immutable patterns to ensure referential transparency and predictable state changes. ```typescript // Mutable: same reference, different content const mutableItems = [1, 2, 3]; mutableItems.push(4); mutableItems === mutableItems; // true, but content changed // Immutable: new reference signals change const items = [1, 2, 3]; const newItems = [...items, 4]; items === newItems; // false ``` -------------------------------- ### Seed Initial Data with Deterministic IDs Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/faq/page.mdx Create initial data like categories using `createIdFromString` to ensure deterministic IDs. This prevents duplication if the seeding action is triggered multiple times or across devices. ```typescript const seedDefaultData = () => { evolu.upsert("category", { id: createIdFromString("groceries"), name: "Groceries" }); evolu.upsert("category", { id: createIdFromString("utilities"), name: "Utilities" }); evolu.upsert("category", { id: createIdFromString("entertainment"), name: "Entertainment" }); }; // In your UI, provide a button or onboarding step ``` -------------------------------- ### Query Data in Svelte Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Shows how to load query results once or subscribe to changes in Svelte using `queryState`. Note that `queryState` is specifically for Svelte components. ```typescript import { queryState } from "@evolu/svelte"; // Query once const todosOnce = await evolu.loadQuery(allTodos); // todosOnce.rows for all entries // Subscribe to changes, automatically filled when the Data changes const todos = queryState(evolu, () => allTodos); // todos.rows for all entries // Note this only works in .svelte or .svelte.js / .svelte.ts files due to the Svelte compiler ``` -------------------------------- ### Controlling Resource Disposal with Block Scopes Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/resource-management/page.mdx Demonstrates how block scopes (`{}`) can be used with the `using` declaration to precisely control the lifetime and disposal of resources. ```typescript const createLock = (name: string): Disposable => ({ [Symbol.dispose]: () => { console.log(`unlock:${name}`); }, }); const process = () => { console.log("start"); { using lock = createLock("a"); console.log("critical-section-a"); } // lock "a" released here console.log("between"); { using lock = createLock("b"); console.log("critical-section-b"); } // lock "b" released here console.log("end"); }; // Output: // "start" // "critical-section-a" // "unlock:a" // "between" // "critical-section-b" // "unlock:b" // "end" ``` -------------------------------- ### Testing Error Paths with Mocked Dependencies Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Easily test failure scenarios by providing mocked dependencies that return specific domain errors. This ensures robust error handling. ```typescript const createFailingStorage = (): Storage => ({ save: () => err({ type: "StorageFullError" }), }); test("handles storage full error", () => { const deps = { storage: createFailingStorage() }; const result = saveUserData(deps)(userData); expect(result).toEqual(err({ type: "StorageFullError" })); }); ``` -------------------------------- ### Using Non-Generic Dependency Interfaces Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Shows the recommended way to define dependency interfaces without generic parameters. This approach hides implementation details and makes the interface agnostic to specific data shapes, improving decoupling and simplicity. ```typescript // Good: No generic, implementation hidden interface Storage { getUsers: () => Result, StorageError>; } // Consumer doesn't know or care how data is stored const getUsers = (deps: StorageDep) => deps.storage.getUsers(); ``` -------------------------------- ### Automatic Resource Cleanup with `using` Declaration Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/resource-management/page.mdx Illustrates the `using` declaration in JavaScript for automatic resource disposal. Resources are guaranteed to be cleaned up when they go out of scope, even if errors occur. ```typescript const process = () => { using conn = openConnection(); doWork(conn); }; // conn is automatically disposed here ``` -------------------------------- ### Define Evolu Schema with Branded Types Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Define your app database schema using Evolu's Type system, including branded types for IDs and enforcing constraints like non-empty strings. ```typescript import * as Evolu from "@evolu/common"; // Primary keys are branded types, preventing accidental use of IDs across // different tables (e.g., a TodoId can't be used where a UserId is expected). const TodoId = Evolu.id("Todo"); type TodoId = typeof TodoId.Type; // Schema defines database structure with runtime validation. // Column types validate data on insert/update/upsert. const Schema = { todo: { id: TodoId, // Branded type ensuring titles are non-empty and ≤100 chars. title: Evolu.NonEmptyString100, // SQLite doesn't support the boolean type; it uses 0 and 1 instead. isCompleted: Evolu.nullOr(Evolu.SqliteBoolean), }, }; ``` -------------------------------- ### MessageChannel RPC with Callbacks Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(landing)/blog/you-might-not-need-comlink/page.mdx Implementing request-response correlation using MessageChannel and a callback registry for RPC. ```typescript const callbacks = createCallbacks(deps); const query = async (sql: string): Promise => { const { promise, resolve } = Promise.withResolvers(); const callbackId = callbacks.register(resolve); queryPort.postMessage({ sql, callbackId }); return promise; }; // When response arrives: queryPort.onmessage = (e) => { callbacks.execute(e.data.callbackId, e.data.result); }; ``` -------------------------------- ### Implement Time and Logger Factory Functions Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Create factory functions to instantiate Time and Logger dependencies. `createTime` uses `Date.now()`, and `createLogger` uses `console.log`. ```typescript /** Creates a {@link Time} using Date.now(). */ export const createTime = (): Time => ({ now: () => Date.now(), }); /** Creates a {@link Logger} using console.log. */ export const createLogger = (): Logger => ({ log: (...args) => { console.log(...args); }, }); ``` -------------------------------- ### Verbose try/finally for Resource Cleanup Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/resource-management/page.mdx Shows the verbosity of using try/finally blocks for resource cleanup. This pattern can become cumbersome and does not compose well. ```typescript const conn = openConnection(); try { doWork(conn); } finally { conn.close(); } ``` -------------------------------- ### Reset Local App Data Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/local-first/page.mdx Call `evolu.resetAppOwner()` to completely clear all local data from the device. This action is irreversible and not a soft delete. ```ts evolu.resetAppOwner(); ``` -------------------------------- ### Using Type Aliases for Composed Dependencies Source: https://github.com/evoluhq/evolu/blob/main/apps/web/src/app/(docs)/docs/dependency-injection/page.mdx Illustrates the preferred method of composing multiple dependencies using type aliases. This prevents accidental merging of interfaces across files, ensuring a stable and predictable dependency contract. ```typescript // Prefer: closed composition type AppDeps = LoggerDep & TimeDep & Partial; // Avoid for composed deps: interface can be merged elsewhere interface AppDeps extends LoggerDep, TimeDep { readonly metrics?: Metrics; } ```