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

@rexeus/typeweaver

v0.11.0

Published

🧡✨ Typeweaver CLI. Entry point into the Typeweaver framework to scaffold, validate, and generate API assets.

Downloads

2,701

Readme

🧡✨ @rexeus/typeweaver

npm version License TypeScript Node.js Deno Bun

Typeweaver is a type-safe HTTP API framework built for API-first development with a focus on developer experience. Use typeweaver to specify your HTTP APIs in TypeScript and Zod, and generate clients, validators, routers, and more ✨


πŸ“₯ Installation

# Node.js (npm)
npm install -D @rexeus/typeweaver
npm install @rexeus/typeweaver-core

# Node.js (pnpm)
pnpm add -D @rexeus/typeweaver
pnpm add @rexeus/typeweaver-core

# Deno
deno add npm:@rexeus/typeweaver npm:@rexeus/typeweaver-core

# Bun
bun add -D @rexeus/typeweaver
bun add @rexeus/typeweaver-core

Now you are ready to start building! Check out Quickstart

🎯 Why typeweaver?

  • πŸ“ Define once, generate everything: API contracts in Zod become clients, servers, validators, and docs.
  • πŸ“‚ Resource-based architecture: APIs organized by resources (like user, todo, project, tag, blog-post, etc.), each with its operations and generated components (e.g. clients). Scale naturally as your API grows.
  • πŸ”’ Real type safety: From API definition to client usage, every request and response is fully typed. No more any types sneaking in.
  • βœ… Automatic validation: Invalid requests never reach your code.
  • πŸ”Œ Bring your own framework: Ready-made adapters for popular frameworks, extensible plugin system for everything else.
  • 😊 Finally, DX that doesn't suck: One schema, no duplication, pure TypeScript.

πŸ”Œ Available Plugins

| Package | Description | Version | | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | @rexeus/typeweaver-types | Plugin for request/response types and validation - the foundation for all other plugins and always included | npm | | @rexeus/typeweaver-clients | Plugin for HTTP clients using fetch | npm | | @rexeus/typeweaver-server | Plugin for a zero-dependency, Fetch API-native server with built-in routing and middleware | npm | | @rexeus/typeweaver-hono | Plugin for Hono routers | npm | | @rexeus/typeweaver-aws-cdk | Plugin for AWS CDK constructs for API Gateway V2 | npm |

More plugins are planned. If you want to build your own, check out the plugin system

Plugin system.


⌨️ CLI

Generate TypeScript code from a spec entrypoint file:

# Node.js (npm)
npx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients

# Node.js (pnpm)
pnpx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients

# Deno
deno run -A npm:@rexeus/typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients

# Bun
bunx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients

Note: Deno may require the --sloppy-imports flag or equivalent configuration in deno.json when your API definitions use extensionless TypeScript imports.

βš™οΈ Options

  • --input, -i <path>: Spec entrypoint file (required)
  • --output, -o <path>: Output directory for generated code (required)
  • --config, -c <path>: Configuration file path (.js, .mjs, or .cjs, optional)
  • --plugins, -p <plugins>: Comma-separated list of plugins to use (e.g., "clients,hono" or "all" for all plugins)
  • --format / --no-format: Enable/disable code formatting with oxfmt (default: true)
  • --clean / --no-clean: Enable/disable output directory cleaning (default: true)

πŸ“ Configuration File

Create a JavaScript config file (for example typeweaver.config.mjs) for more complex configurations:

export default {
  input: "./api/spec/index.ts",
  output: "./api/generated",
  plugins: ["clients", "hono", "aws-cdk"],
  format: true,
  clean: true,
};

Then run:

npx typeweaver generate --config ./typeweaver.config.mjs

Replace npx with pnpx, deno run -A npm:@rexeus/typeweaver, or bunx depending on your runtime.

TypeScript config files (.ts, .mts, .cts) are no longer supported by the published CLI. Convert them to JavaScript first if needed.

🌱 Get Started

πŸ“ Project Structure

Typeweaver reads a single spec entrypoint. Organize files however you want, then assemble the resource map in defineSpec(...). Here is an example layout:

api/spec/
β”œβ”€β”€ index.ts                              # Spec entrypoint β€” exports defineSpec(...)
β”œβ”€β”€ user/
β”‚   β”œβ”€β”€ index.ts                          # Barrel exports for the user resource
β”‚   β”œβ”€β”€ userSchema.ts                     # Zod schemas for the user entity
β”‚   β”œβ”€β”€ GetUserDefinition.ts              # defineOperation(...) for GET /users/:userId
β”‚   └── errors/
β”‚       └── UserNotFoundErrorDefinition.ts
└── shared/
    β”œβ”€β”€ sharedResponses.ts                # Array of common error responses
    └── ValidationErrorDefinition.ts

This is just one way to organize your spec. The directory layout is up to you β€” typeweaver only cares about the defineSpec(...) entrypoint, not about folder names or file conventions.

  • Resource names come from defineSpec({ resources: ... }), not from directory names.
  • Shared responses and schemas can live anywhere that your spec entrypoint imports from.
  • The CLI bundles the entrypoint, so local spec imports should stay within your project.

πŸ’» Sample Spec

// api/spec/user/GetUserDefinition.ts
import {
  defineOperation,
  defineResponse,
  HttpMethod,
  HttpStatusCode,
} from "@rexeus/typeweaver-core";
import { z } from "zod";
import { sharedResponses } from "../shared/sharedResponses";
import { userSchema } from "./userSchema";
import { UserNotFoundErrorDefinition } from "./errors/UserNotFoundErrorDefinition";

export const GetUserDefinition = defineOperation({
  operationId: "getUser",
  method: HttpMethod.GET,
  path: "/users/:userId",
  summary: "Get a user by id",
  request: {
    param: z.object({
      userId: z.uuid(),
    }),
  },
  responses: [
    defineResponse({
      name: "GetUserSuccess",
      statusCode: HttpStatusCode.OK,
      description: "User successfully retrieved",
      header: z.object({
        "Content-Type": z.literal("application/json"),
      }),
      body: userSchema,
    }),
    UserNotFoundErrorDefinition,
    ...sharedResponses,
  ],
});
// api/spec/index.ts
import { defineSpec } from "@rexeus/typeweaver-core";
import { GetUserDefinition } from "./user/GetUserDefinition";

export const spec = defineSpec({
  resources: {
    user: {
      operations: [GetUserDefinition],
    },
  },
});
// api/spec/user/userSchema.ts
import { z } from "zod";

export const userStatusSchema = z.enum(["ACTIVE", "INACTIVE", "SUSPENDED"]);

export const userSchema = z.object({
  id: z.uuid(),
  name: z.string(),
  email: z.email(),
  status: userStatusSchema,
  createdAt: z.iso.date(),
  updatedAt: z.iso.date(),
});
// api/spec/shared/sharedResponses.ts
import { ForbiddenErrorDefinition } from "./ForbiddenErrorDefinition";
import { InternalServerErrorDefinition } from "./InternalServerErrorDefinition";
import { TooManyRequestsErrorDefinition } from "./TooManyRequestsErrorDefinition";
import { UnauthorizedErrorDefinition } from "./UnauthorizedErrorDefinition";
import { UnsupportedMediaTypeErrorDefinition } from "./UnsupportedMediaTypeErrorDefinition";
import { ValidationErrorDefinition } from "./ValidationErrorDefinition";

export const sharedResponses = [
  ForbiddenErrorDefinition,
  InternalServerErrorDefinition,
  TooManyRequestsErrorDefinition,
  UnauthorizedErrorDefinition,
  UnsupportedMediaTypeErrorDefinition,
  ValidationErrorDefinition,
];

πŸ”§ Generate using plugins

# Generate with plugins:
# - Hono: to easily provide a web server
# - Clients: to get fitting API clients
npx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients,hono

The CLI accepts a default export, a named spec export, or the module namespace itself as the SpecDefinition entrypoint.

🌐 Create Hono web server

// api/user-handlers.ts
import type { Context } from "hono";
import type { HonoUserApiHandler, IGetUserRequest, GetUserResponse } from "./generated";
import { createGetUserSuccessResponse } from "./generated";

// Implement HonoUserApiHandler β€” the generated interface enforces
// that every operation in the "user" resource has a handler.
export class UserHandlers implements HonoUserApiHandler {
  public constructor() {}

  public async handleGetUserRequest(
    request: IGetUserRequest,
    context: Context
  ): Promise<GetUserResponse> {
    // Simulate fetching user data
    const fetchedUser = {
      id: request.param.userId,
      name: "John Doe",
      email: "[email protected]",
      status: "ACTIVE",
      createdAt: new Date("2023-01-01").toISOString(),
      updatedAt: new Date("2023-01-01").toISOString(),
    };

    return createGetUserSuccessResponse({
      header: {
        "Content-Type": "application/json",
      },
      body: fetchedUser,
    });
  }

  // Implement further handlers for each operation in the resource.
  // TypeScript enforces the contract β€” every handler declared in
  // HonoUserApiHandler must be implemented before the code compiles.
}
// api/server.ts
import { serve } from "@hono/node-server";
import { Hono } from "hono";
// an index file exporting all generated components is automatically provided
import { UserHandlers } from "./user-handlers";
import { PostHandlers } from "./post-handlers"; // Implement similarly to UserHandlers
import { UserHono, PostHono } from "./generated";

const app = new Hono();

const userHandlers = new UserHandlers();
const postHandlers = new PostHandlers();

// you have further config options, e.g. custom error response handling
// (useful for mapping validation errors to your specific response format)
const userRouter = new UserHono({
  requestHandlers: userHandlers,
});
const postRouter = new PostHono({
  requestHandlers: postHandlers,
});

app.route("/", userRouter);
app.route("/", postRouter);

// Start server on port 3000
serve(
  {
    fetch: app.fetch,
    port: 3000,
  },
  () => {
    console.log("Server is running on http://localhost:3000");
  }
);
# Start your server locally
tsx api/server.ts

πŸ”— Communicate by using Clients

// api/client-test.ts
import { UserClient, GetUserRequestCommand } from "./generated";

const client = new UserClient({ baseUrl: "http://localhost:3000" });

const getUserRequestCommand = new GetUserRequestCommand({
  param: { userId: "123" },
});
const response = await client.send(getUserRequestCommand);

if (response.type === "GetUserSuccess") {
  console.log("Successfully fetched user:", response.body);
} else if (response.type === "UserNotFoundError") {
  console.error("User not found:", response.body);
} else {
  console.error("Other error occurred:", response.type);
}
# Call your created Hono server
tsx api/client-test.ts

πŸ“„ License

Apache 2.0 Β© Dennis Wentzien 2026