Skip to content

pierre-H/secure-convex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

secure-convex

secure-convex is a lightweight TypeScript library that supercharges your Convex backend with strongly-typed runtime validation powered by Valibot and granular permission control via Permix.

It’s designed to make your Convex functions safer, cleaner, and easier to maintain by ensuring:

  • End-to-end strong typing – from input validation to database writes.
  • Every function input is validated against a strict Valibot schema before execution.
  • Your database schema is derived directly from Valibot schemas, keeping data types in sync automatically.
  • Every write operation is validated against the corresponding Valibot schema before hitting the database.
  • Access rules are centralized and enforced consistently.
  • Developer experience stays smooth with minimal boilerplate.

Key features

  • Automatic input validation for Convex queries & mutations.
  • 🗄 DB schema generation from Valibot schemas.
  • 🔒 Permission middleware with flexible, composable rules.
  • 🛡 Schema-validated writes for consistent, safe data.
  • 🧑‍💻 Full TypeScript support with strong, inferred types everywhere.
  • Zero extra config – just wrap your functions.
  • 🧩 Works perfectly with existing Convex codebases.

Get started

Create you schema with valibot :

// convex/db.ts
import * as v from "valibot";
import { convexId } from "secure-convex";

export enum PostStatus {
    DRAFT,
    PUBLISHED,
}

export const myDb = {
    users: {
        name: v.pipe(v.string(), v.trim(), v.minLength(3), v.maxLength(100)),
        email: v.pipe(v.string(), v.email(), v.maxLength(150)),
    },
    posts: {
        userId: convexId("users"),
        title: v.pipe(v.string(), v.maxLength(100)),
        status: v.enum(PostStatus),
        highlighted: v.boolean(),
        publishedAt: v.optional(v.number()), // timestamp
    },
};

Use it in your Convex schema:

// convex/schema.ts
import { defineSchema } from "convex/server";
import { defineSecureTable } from "secure-convex";
import { myDb } from "./db.ts";

const schema = defineSchema({
    users: defineSecureTable(myDb.users).index("byEmail", ["email"]),
    posts: defineSecureTable(myDb.posts).index("byStatusHighlited", [
        "status",
        "highlighted",
    ]),
});

export default schema;

Then, create a custom secure mutation :

// convex/test.ts
import { secureMutation } from "secure-convex";
import { myDb } from "./db.ts";

const myMutation = secureMutation(myDb);

With myMutation, ctx.db will always performs valibot.parseAsync for insert patch and replace. There is alse a ctx.insecureDb which is the original convex db object.

### Notes

  • Always use exactOptional, not optional or undefinedable, as convex doesn't support the value undefined
  • for union or variant table, use defineSecureUnionTable instead of defineSecureTable

Permix

You can also create a permix object from your schema :

// convex/permix.ts
import { createPermixFromDataModel } from "secure-convex";
import type { DataModel } from "../_generated/dataModel";

export const permix = createPermixFromDataModel<
    DataModel,
    {
        users: {
            action: "edit" | "delete";
            dataRequired: true;
        };
        posts: {
            action: "read";
        };
    }
>();

The dataType is automatically inserted from the Convex data model for Convex table name.

About

A library to secure your Convex database with Valibot and Permix

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published