npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ahmedrowaihi/openapi-ts-orpc

v2.3.2

Published

oRPC plugin for @hey-api/openapi-ts - Generate type-safe RPC clients and servers from OpenAPI specs

Readme

@ahmedrowaihi/openapi-ts-orpc

Generates type-safe oRPC contracts, routers, server skeletons, clients, and mock factories from OpenAPI specifications. Plugin for @hey-api/openapi-ts.

Installation

bun add -d @ahmedrowaihi/openapi-ts-orpc @hey-api/openapi-ts
bun add @orpc/contract @orpc/server @orpc/client zod

What it generates

| File | Description | Required | | ----------------------- | -------------------------------------------------------- | --------------------- | | contract.gen.ts | Type-safe oRPC contracts with input/output schemas | Always | | router.gen.ts | Organized router structure | Always | | server.gen.ts | os = implement(router) helper | Optional | | client.gen.ts | Client factory functions (RPC, WebSocket, OpenAPI, etc.) | Optional | | tanstack.gen.ts | TanStack Query utilities | Optional | | faker.gen.ts | Mock data factory functions per tag | Optional (faker mode) | | src/handlers/<tag>.ts | Handler files with three modes | Optional |


Basic Usage

import { defineConfig } from "@hey-api/openapi-ts";
import { defineConfig as defineORPCConfig } from "@ahmedrowaihi/openapi-ts-orpc";

export default defineConfig({
  input: "openapi.json",
  output: { path: "./src/generated" },
  plugins: [
    "@hey-api/typescript",
    "zod",
    defineORPCConfig(), // contracts + router only (default)
  ],
});

Server (Backend)

defineORPCConfig({
  server: {
    implementation: true,
    handlers: {
      dir: "src/handlers",
      importAlias: "#/",
      mode: "stub", // 'stub' | 'faker' | 'proxy'
    },
  },
});

Handler modes

stub (default) — throws ORPCError('NOT_IMPLEMENTED'):

getUser: os.users.getUser.handler(async () => {
  throw new ORPCError("NOT_IMPLEMENTED");
}),

faker — returns mock data from generated faker.gen.ts factories:

getUser: os.users.getUser.handler(async () => mockGetUser()),

Requires @faker-js/faker as a dependency. Generates type-safe factories with:

  • Field name heuristics (email, phone, url, etc.)
  • Enum support via faker.helpers.arrayElement()
  • Nested objects and arrays from schema
  • Date .toISOString() chaining

proxy — forwards requests through the generated OpenAPI client:

getUser: os.users.getUser.handler(async ({ input }) => apiClient.users.getUser(input)),

Configure the client import:

handlers: {
  mode: 'proxy',
  proxy: { clientImport: { name: 'apiClient', from: '#/lib/client' } },
}

Handler file management

  • New tags create new handler files
  • Existing files only get missing procedures appended (never overwritten)
  • override: true rewrites files completely on each run

Client (Frontend)

defineORPCConfig({
  client: {
    rpc: true, // HTTP client (native oRPC RPC protocol)
    openapi: true, // REST client (OpenAPI protocol)
    tanstack: true, // TanStack Query utilities
  },
});

| Option | Description | | ------------- | ----------------------------------------- | | rpc | HTTP/Fetch client (native RPC protocol) | | websocket | WebSocket client | | messageport | MessagePort client (Web Workers, iframes) | | openapi | REST client (OpenAPI protocol) | | tanstack | TanStack Query utilities |


Full Configuration Reference

defineORPCConfig({
  // Server-side generation
  server: {
    implementation: false,
    handlers: {
      dir: "src/handlers",
      importAlias: "#/",
      implementer: { name: "publicOs", from: "#/procedures" },
      mode: "stub", // 'stub' | 'faker' | 'proxy'
      override: false, // rewrite files on each run
      proxy: { clientImport: { name: "apiClient", from: "#/lib/client" } },
    },
  },

  // Client-side generation
  client: {
    rpc: false,
    websocket: false,
    messageport: false,
    openapi: false,
    tanstack: false,
  },

  // Input structure mode
  mode: "compact", // 'compact' | 'detailed'

  // Router grouping
  group: "tags", // 'tags' | 'paths' | 'flat' | 'operationId'

  // JSDoc comments on contracts
  comments: true,

  // Naming rules (uses hey-api's applyNaming)
  naming: {
    contract: { casing: "PascalCase" }, // contract constant names
    operation: { casing: "camelCase" }, // router/procedure keys
  },

  // Validator configuration
  validator: "zod", // string | false | { input: string | false, output: string | false }
});

mode — Input structure

| Mode | Description | | --- | --- | | compact (default) | Flat merged input — path + body for mutations, path + query for reads | | detailed | Structured { params, query, body, headers } input |

Note: Standard validators (zod, valibot, arktype) always use detailed mode regardless of this setting. Compact mode is only supported with Typia. This is because hey-api's createRequestSchema API always returns a structured object.

group — Router grouping

| Mode | Description | Example | | ---------------- | --------------------------- | ---------------------------- | | tags (default) | Group by OpenAPI tag | router.users.getById() | | paths | Group by URL structure | router.api.users.getById() | | flat | No grouping | router.getUserById() | | operationId | Group by operationId prefix | router.auth.login() |

validator — Validation configuration

Works with any hey-api validator plugin (zod, valibot, arktype):

// Single validator for both input and output (default)
validator: 'zod'

// Separate input/output validators
validator: { input: 'zod', output: false }

// Disable validation entirely
validator: false

naming — Name customization

Uses applyNaming from @hey-api/shared:

naming: {
  contract: { casing: 'PascalCase' },   // GetUserContract
  operation: { casing: 'camelCase' },    // getUser
}

Supports 'camelCase', 'PascalCase', 'snake_case', 'SCREAMING_SNAKE_CASE', 'preserve', or a custom transform function.


Requirements

  • @hey-api/openapi-ts >= 0.95.0
  • @hey-api/typescript plugin (auto-included as dependency)
  • A validator plugin (zod, valibot, arktype) configured in your plugins

Typia Integration

Want compile-time validators instead of Zod? See docs/typia.md.

Set validator: { input: 'typia', output: 'typia' } to use Typia's Standard Schema validators.