A create endpoint isn’t much without a read endpoint. Add the read RPC and return a declared service-local error when the order does not exist.

Add the schemas to schemas.ts:

export const GetOrderRequest = Type.Object({
  orderId: Type.String(),
});
export type GetOrderRequest = Static<typeof GetOrderRequest>;

export const GetOrderResponse = Type.Object({
  orderId: Type.String(),
  customerId: Type.String(),
  status: Type.String(),
  items: Type.Array(Type.Object({
    productId: Type.String(),
    quantity: Type.Number(),
  })),
});
export type GetOrderResponse = Static<typeof GetOrderResponse>;

When an order does not exist, return a declared service error instead of an ad-hoc { type, message } object. Built-in Trellis errors cover platform failures such as validation, auth, transport, and unexpected internal errors. Domain failures belong to your service.

Create errors.ts next to schemas.ts:

import { defineError } from "@qlever-llc/trellis";
import { Type } from "@sinclair/typebox";

export const NotFoundError = defineError({
  type: "NotFoundError",
  fields: {
    resource: Type.String(),
    resourceId: Type.String(),
  },
  message: ({ resource, resourceId }) => `${resource} ${resourceId} not found`,
});

export const errors = {
  NotFoundError,
} as const;

Register Orders.Get in the contract’s rpc section alongside Orders.Create. Also import and pass the error map to defineServiceContract(...):

import { defineServiceContract } from "@qlever-llc/trellis";
import { errors } from "../errors.ts";
import * as schemas from "../schemas.ts";

export const ordersService = defineServiceContract(
  { schemas, errors },
  (ref) => ({
    // ...

    capabilities: {
      "orders.write": { /* ... */ },
      "orders.read": {
        displayName: "Read orders",
        description: "Read order records.",
      },
    },

    rpc: {
      "Orders.Create": { /* ... */ },
      "Orders.Get": {
        version: "v1",
        input: ref.schema("GetOrderRequest"),
        output: ref.schema("GetOrderResponse"),
        capabilities: { call: ["orders.read"] },
        errors: [ref.error("NotFoundError"), ref.error("UnexpectedError")],
      },
    },
  }),
);

Now add the typed read handler to handlers/orders.ts:

import { err, isErr, ok } from "@qlever-llc/trellis";
import { NotFoundError } from "../errors.ts";
import type {
  RpcHandlerArgs,
  RpcHandlerResult,
} from "../contracts/orders_service.ts";

type Args = RpcHandlerArgs<"Orders.Get">;
type Result = RpcHandlerResult<"Orders.Get">;

export async function getOrderHandler({
  input,
  client,
}: Args): Promise<Result> {
  const result = await client.kv.orders.get(input.orderId).take();
  if (isErr(result)) {
    return err(new NotFoundError({
      resource: "Order",
      resourceId: input.orderId,
    }));
  }

  return ok(result.value);
}

Mount it from main.ts:

import { getOrderHandler } from "./handlers/orders.ts";

await app.handle.rpc.orders.get(getOrderHandler);

client.kv.orders.get(key) returns a Result<TypedKVEntry<Order>, KVError>. When the key doesn’t exist, it returns an Err. Translate that into a declared service-local NotFoundError for the caller.

Callers can now branch on the declared error class:

import { isErr } from "@qlever-llc/trellis";
import { NotFoundError } from "./errors.ts";

const result = await client.rpc.orders.get({ orderId: "ord_123" });
const value = result.take();

if (isErr(value) && value.error instanceof NotFoundError) {
  console.log(value.error.resource, value.error.resourceId);
}

Upgrade and restart as before.