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

@libar-dev/eslint-plugin-zod-convex

v0.1.0

Published

ESLint rules for zod-convex hybrid validation patterns

Readme

@libar-dev/eslint-plugin-zod-convex

npm version License: MIT TypeScript

ESLint plugin that enforces the zod-convex hybrid validation pattern — a 3-layer trust boundary model that achieves 90% memory reduction (60-65MB to 10-15MB) in Convex's 64MB runtime.

What is the Hybrid Validation Pattern?

The hybrid validation pattern combines:

  • Zod schemas (in src/validation-schemas/) — Define structure and business rules
  • Build-time generation (via @libar-dev/zod-convex-gen) — Convert to Convex validators
  • Type-only imports — Zero runtime Zod cost, full TypeScript type safety

Installation

npm install --save-dev @libar-dev/eslint-plugin-zod-convex

Peer Dependencies:

  • eslint ^8.0.0 || ^9.0.0
  • @typescript-eslint/parser ^8.49.0

Quick Start

Enable all recommended rules with a single config:

// eslint.config.mjs
import zodConvex from '@libar-dev/eslint-plugin-zod-convex';

export default [
  {
    plugins: {
      'zod-convex': zodConvex,
    },
    rules: {
      ...zodConvex.configs.recommended.rules,
    },
  },
];

Individual Rule Configuration

// eslint.config.mjs
import zodConvex from '@libar-dev/eslint-plugin-zod-convex';

export default [
  {
    plugins: {
      'zod-convex': zodConvex,
    },
    rules: {
      'zod-convex/require-schema-type-aliases': 'error',
      'zod-convex/no-runtime-zod-in-convex': 'error',
      'zod-convex/require-api-validation': 'error',
      'zod-convex/no-layer-3-validation': 'warn',
    },
  },
];

Rules

require-schema-type-aliases

Severity: error | Scope: convex/ directory

Enforces type alias exports from schema files and correct usage in consumer files.

Problem: Using z.infer<typeof Schema> with type-only imports breaks TypeScript compilation.

// WRONG: TypeScript error
import type { MyArgsSchema } from '../../src/validation-schemas/domain/mySchema';

handler: async (ctx, args: z.infer<typeof MyArgsSchema>) => {
  // ERROR: MyArgsSchema only refers to a type, but is being used as a value
}

Why: The typeof operator requires a runtime value, but import type erases values at compile time.

Solution: Schema files must export type aliases, consumers import the type alias.

// Schema file (src/validation-schemas/domain/mySchema.ts)
export const MyArgsSchema = z.object({
  userId: ids.userId(),
  data: z.string()
}).strict();

export type MyArgs = z.infer<typeof MyArgsSchema>; // REQUIRED

// Consumer file (convex/domain/myFunction.ts)
import type { MyArgs } from '../../src/validation-schemas/domain/mySchema';

handler: async (ctx, args: MyArgs) => {
  // Works perfectly - type alias is compile-time only
}

Naming Convention: The rule automatically derives type alias names by removing the Schema suffix:

  • FooArgsSchema -> FooArgs
  • CreateInvoiceArgsSchema -> CreateInvoiceArgs
  • UsersTableSchema -> User (singular for table schemas)

no-runtime-zod-in-convex

Severity: error | Scope: convex/ directory

Prevents runtime Zod imports in the Convex directory (Layer 2 enforcement).

Problem: Convex runtime has a 64MB memory limit. Including Zod adds 20-30MB to the bundle.

Solution: Use hybrid validation pattern with generated validators + type-only imports.

// WRONG: Runtime Zod in Convex (20-30MB overhead)
import { z } from 'zod';
import { zodToConvex } from '@libar-dev/zod-convex-core';

// RIGHT: Generated validators (zero Zod at runtime)
import type { MyArgs } from '../../src/validation-schemas/domain/mySchema';
import { myArgsFields } from '../generatedValidators/mySchema';

export const myMutation = mutation({
  args: myArgsFields,
  handler: async (ctx, args: MyArgs) => { ... }
});

Architectural Directives: When runtime Zod is architecturally justified (e.g., validating external component responses), use an architectural directive to suppress the warning:

/**
 * @architectural-directive: workflow-step-validation
 * Reason: Validates external Convex component responses.
 * Impact: Requires runtime Zod for parseWithSchema() validation.
 */
import { z } from 'zod';

Supported Directives (9 total):

| Category | Directive | Use Case | |----------|-----------|----------| | Validation | workflow-step-validation | Validating external component responses | | Validation | validation-at-boundary | Hybrid pattern with generated validators | | Infrastructure | schema-infrastructure | Schema factory utilities | | Infrastructure | workflow-validation-infrastructure | Workflow validation helpers | | Infrastructure | projection-validation-infrastructure | CQRS projection validation | | Infrastructure | schema-composition-utility | Zod composition utilities | | External | ai-response-normalization | AI/external response validation | | Testing | test-infrastructure | Testing utilities | | Testing | test-enforcement-safe | Test mocks requiring runtime Zod |

require-api-validation

Severity: error | Scope: app/api/, pages/api/, webhook files

Enforces Zod validation at API route boundaries (Layer 1 enforcement).

Problem: External API boundaries are security-critical. Unvalidated input leads to runtime errors and potential vulnerabilities.

// WRONG: No validation on external input
export async function POST(request: Request) {
  const body = await request.json();
  await ctx.db.insert('users', body); // Dangerous: unvalidated data
}

// RIGHT: Validate all external input
export async function POST(request: Request) {
  const body = await request.json();
  const result = CreateUserSchema.safeParse(body);
  if (!result.success) {
    return NextResponse.json({ error: result.error }, { status: 400 });
  }
  await ctx.db.insert('users', result.data);
}

Supports Next.js App Router (app/api/**/route.ts), Pages Router (pages/api/**/*.ts), and webhook handlers.

no-layer-3-validation

Severity: warn | Scope: components/, hooks/, utils/, lib/, app/ (excluding app/api/)

Prevents redundant runtime validation in the trusted zone (Layer 3).

Problem: Frontend code should trust already-validated data from API routes (Layer 1) or Convex functions (Layer 2). Redundant validation adds bundle size without security benefit.

// WRONG: Redundant validation in component
function UserCard({ user }: { user: unknown }) {
  const result = UserSchema.safeParse(user);
  // ...
}

// RIGHT: Trust validated data from API/Convex
import type { User } from '@/src/validation-schemas/users';

function UserCard({ user }: { user: User }) {
  // Data already validated at boundary
}

Exception: Form validation (react-hook-form, zodResolver) is acceptable for UX progressive enhancement. The rule detects form context and reports as informational instead of a warning.

Known Limitations

  • require-schema-type-aliases: Does not detect renamed imports (import type { Schema as MySchema }) or namespace imports (import type * as schemas)
  • require-api-validation: Does not track validation in helper functions called by the handler; validation must be directly in the handler body
  • no-layer-3-validation: Form detection relies on filename patterns and import heuristics
  • no-runtime-zod-in-convex: Directive detection scans preceding 1000 characters; very long preambles may not be detected

Related Packages

Contributing

This package is part of the @libar-dev/zod-convex monorepo. See CONTRIBUTING.md for details.

License

MIT