React setup

1. Install

pnpm add schelo
npm install schelo

Zod is a peer dependency (you define schemas with it). If it is not already in the project:

pnpm add schelo zod
npm install schelo zod

2. Schema module

From your app folder, run the CLI and choose React:

npx schelo init

That creates lib/api-schemas.ts or src/lib/api-schemas.ts and exports interceptor from createInterceptor({ ... }). You can add the file by hand instead if you prefer.

Example config:

import { createInterceptor } from "schelo";
import { z } from "zod";

const healthSchema = z.object({ status: z.literal("ok") });
const apiErrorSchema = z.object({ error: z.string() });

export const interceptor = createInterceptor({
  mode: "warn",
  warnOnUnmatched: true,
  routes: {
    "GET /api/health": {
      response: z.union([healthSchema, apiErrorSchema]),
    },
    "POST /api/items": {
      validate: false,
      request: z.object({ title: z.string() }),
      response: z.union([z.object({ id: z.string(), title: z.string() }), apiErrorSchema]),
    },
  },
});

3. Enable in the browser entry

Call interceptor.enable() in your browser entry file, before createRoot(...).render(...) (or ReactDOM.render). Import interceptor with a path that resolves from that entry (for example ./lib/api-schemas or ../lib/api-schemas).

Typical entry files:

Do not rely on useEffect for the first enable(): a child component may fetch before that effect runs. Put wrappers (StrictMode, router, and so on) inside render; keep enable() above it.

4. Example

import { createRoot } from "react-dom/client";
import { interceptor } from "./lib/api-schemas"; // import from api-schemas.ts
import App from "./App";
import "./index.css";

interceptor.enable(); //enable the interceptor

createRoot(document.getElementById("root")!).render(<App />);

5. disable() (optional)

Rarely needed: use interceptor.disable() in tests or when you need to restore the real fetch.

interceptor.disable();