Evo

schema-validated RPC between client, server and UI runtimes.

type-safe, schema-based RPC system for distributed TypeScript applications. enables validated communication across client, server, and UI contexts.

features

  • built for distributed runtime environments

    supports communication across client, server, and UI layers with a consistent, contract-driven interface.

  • contract-driven design

    define RPC methods with Zod schemas and auto-generate fully-typed APIs with runtime validation.

  • cross-environment communication

    handles bi-directional calls between Client ⇄ Server, Client ⇄ UI, and UI ⇄ Client.

  • retry and timeout handling

    built-in support for configurable retry strategies, delay enforcement, and timeout safeguards.

  • runtime environment safety

    prevents incorrect usage by validating the execution context before sending or handling RPC calls.

  • response routing and cleanup

    uses UUIDs to track and clean up response listeners automatically for better memory and safety control.

usage

// 1. Define a contract using Zod for type-safe args and return values
import { z } from 'zod';
import { Contract } from '@smaiill/evo';

const userContract = new Contract({
  getUser: {
    args: z.object({ id: z.number() }),
    returns: z.object({ name: z.string(), email: z.string() }),
  },
}).build();
// 2. Define a server-side RPC listener (RS = server, RC = client)
userContract.createListener('rs', 'rc', {
  getUser: async ({ id }) => {
    // Simulate user data fetching
    return { name: 'Alice', email: 'alice@example.com' };
  },
});
// 3. Define a client-side API (RC = client, RS = server)
const api = userContract.createApi('rc', 'rs');

// Make a request to the server from the client
const user = await api.getUser({ id: 1 });
// Output: { name: string; email: string }
// 4. Add retry options to make the method more resilient
const contractWithRetry = new Contract({
  getUser: {
    args: z.object({ id: z.number() }),
    returns: z.object({ name: z.string() }),
    retryOptions: {
      max: 3,          // Max 3 attempts
      delay: 1000,     // Wait 1 second between retries
      forceDelay: false,
    },
  },
}).build();
// 5. Global timeout for all API calls in the contract (in ms)
const contractWithTimeout = new Contract(
  {
    getUser: {
      args: z.object({ id: z.number() }),
      returns: z.object({ name: z.string() }),
    },
  },
  {
    timeout: 5000, // 5 seconds max timeout for RPC calls
  }
).build();

stack

TypeScript, Zod