Skip to content

Extension guides

Typed protocols

A protocol is the single source of truth for renderer-to-host method calls and host-to-renderer events. TypeScript infers it and both processes validate it.

Define a protocol

src/protocol.ts
import { defineProtocol } from "@nativepi/extension-api";
import { z } from "@nativepi/extension-api/schema";

const task = z.object({
  id: z.string(),
  title: z.string(),
  complete: z.boolean(),
});

export const taskProtocol = defineProtocol({
  methods: {
    list: { result: z.array(task) },
    add: {
      params: z.object({ title: z.string().min(1) }),
      result: task,
    },
    clear: { result: z.null() },
  },
  events: {
    changed: z.array(task),
    invalidated: undefined,
  },
});

Methods

Every method declares a result schema. Add a params schema when the method takes one argument; omit it when the method takes no arguments. Use z.null() for an action with no meaningful result so the response is still explicit JSON.

await context.channel.call("list");
await context.channel.call("add", { title: "Review diff" });
await context.channel.call("clear");

A params schema whose output includes undefined makes the argument optional. Otherwise TypeScript requires exactly one argument.

Events

An event maps directly to its payload schema. Use undefined for a payload-free event. The host emits events and the renderer subscribes:

host.emit("changed", tasks);
host.emit("invalidated");

const off = context.channel.on("changed", (nextTasks) => {
  setTasks(nextTasks);
});

// Call when the component unmounts.
off();

Validation path

  • Method parameters are validated before leaving the renderer.
  • The Pi host validates parameters again before invoking a handler.
  • Method results are validated in the host and again in the renderer.
  • Event payloads are validated when emitted and before each listener runs.

Errors identify the method or event where invalid data originated, which is more useful than allowing a malformed value to fail later in React.

JSON-compatible values

Values may contain null, booleans, finite numbers, strings, arrays, and plain objects containing those values. Do not send class instances, functions, symbols, dates, maps, sets, binary buffers, cyclic objects,NaN, or infinities. Convert them to explicit JSON shapes.

Schema libraries

The recommended Zod export comes from @nativepi/extension-api/schema. NativePi provides that module to renderer bundles. Any synchronous object with a compatible parse(value) method and JSON-compatible output also works.

Next, implement the protocol with the host channel.