Skip to content

Permissions

Type‑safe permissions with Zod. Define a schema once, then validate specific permission keys with simple predicates or rich outcomes. Array values are augmented with helpful helpers like contains, containsAny, and containsAll.

Quick start

import { z } from "zod";
import { createPermissions } from "@/lib/permissions";

const FeaturePermissions = createPermissions({
schema: {
max_agents: z.number().min(1),
features: z.enum(["premium_editor", "ai_tools", "phone_support"]).array(),
products: z.enum(["view", "create", "update", "delete"]).array(),
},
});

Validate permissions

Call validate with the permissions object and per‑field validators. Each validator gets a value conforming to your schema. Arrays include helpers.
const exampleUserPermissions = {
max_agents: 2,
features: ["ai_tools", "premium_editor"],
products: ["view", "create", "delete"],
};

const result = FeaturePermissions.validate(exampleUserPermissions, {
max_agents: (value) => value >= 3, // require at least 3 agents
features: (value) => value.containsAll(["phone_support"]),
products: (value) => value.containsAll(["create"]),
});

console.log(result);
// {
// max_agents: { valid: false, message: 'max_agents is invalid' },
// features: { valid: false, message: 'features is invalid' },
// products: { valid: true, message: 'products is valid' }
// }

Custom validation messages

Return an object from your validator to control messages.
const result = FeaturePermissions.validate({ max_agents: 2 }, {
max_agents: (value) => ({
valid: value >= 3,
invalidMessage: "You have exceeded your agent limit.",
validMessage: "You are allowed to create an agent.",
}),
});

if (!result.max_agents.valid) {
throw new Error(result.max_agents.invalidMessage);
}

Pre‑configure messages

Provide default messages per field once. They’re used whenever a validator returns only a boolean or omits messages.
import { z } from "zod";
import { createPermissions } from "@/lib/permissions";

const FeaturePermissions = createPermissions({
schema: {
max_agents: z.number().min(1),
features: z.enum(["premium_editor", "ai_tools", "phone_support"]).array(),
products: z.enum(["view", "create", "update", "delete"]).array(),
},
validationConfig: {
max_agents: {
invalidMessage: "You can't add more agents.",
validMessage: "You can add more agents",
},
products: {
invalidMessage: "You can't create products",
validMessage: "You can create products",
},
},
});

const permissionsResult = FeaturePermissions.validate(
{ max_agents: 2, products: ["view"] },
{ max_agents: (value) => value >= 3 }
);

console.log(permissionsResult.max_agents.invalidMessage);
// "You can't add more agents."

API

createPermissions({ schema, validationConfig? }): returns { schema, validate }.
schema: Zod object shape or z.object({ ... }).
validationConfig?: optional per‑field { invalidMessage?, validMessage? }.
validate(permissions, validators): validates only the keys you specify in validators.
permissions: your permissions object.
validators: map of field → validator.
Returns: record of field → { valid: boolean; message: string; invalidMessage?: string; validMessage?: string }.
Array helpers (for z.array(...) fields):
contains(item)
containsAny(items[])
containsAll(items[])

Notes

Each validated field is parsed with its Zod schema; failing to satisfy the schema yields { valid: false } and the configured or default message.
Only the fields you include in validators are evaluated.
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.