field-guard

field-guard is a lightweight, fully type-safe, field-level access control library for TypeScript with zero runtime dependencies.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "field-guard" with this command: npx skills add mohhh-ok/field-guard/mohhh-ok-field-guard-field-guard

field-guard skill

field-guard is a lightweight, fully type-safe, field-level access control library for TypeScript with zero runtime dependencies.

Import

import { defineGuard, combineGuards, mergeFieldVerdicts } from "field-guard";

Define a Guard

type Ctx = { userId: string; role: "admin" | "user" }; type User = { id: string; email: string; name: string };

const userGuard = defineGuard<Ctx>()({ fields: ["id", "email", "name"], policy: { owner: true, // all fields allowed admin: true, // all fields allowed other: { id: true, name: true }, // whitelist — only id and name banned: false, // no fields allowed }, });

Policy Modes

Value Behavior

true

Allow all fields for this level

false

Deny all fields for this level

{ id: true, name: true }

Whitelist — only listed fields allowed

{ secret: false }

Blacklist — all fields except listed ones

fields and policy are both optional. You can omit either or both.

.withCheck<Target>()

Resolves the access level based on context and a target object. Use verdictMap[level] to return the correct FieldVerdict .

const userGuard = defineGuard<Ctx>()({ fields: ["id", "email", "name"], policy: { owner: true, other: { id: true, name: true }, }, }).withCheck<User>()(({ ctx, target, verdictMap }) => { const level = ctx.userId === target.id ? "owner" : "other"; return verdictMap[level]; });

// Evaluate const g = userGuard.for({ userId: "1", role: "user" }); const verdict = g.check({ id: "1", email: "me@example.com", name: "Me" }); verdict.allowedFields; // ["id", "email", "name"]

.withDerive()

Computes extra properties from context. Can also produce row-level filter conditions.

import { eq } from "drizzle-orm";

type Post = { id: string; content: string; authorId: string };

const postGuard = defineGuard<Ctx>()({ fields: ["id", "content", "authorId"], policy: { owner: true, other: { id: true, content: true }, }, }) .withDerive(({ ctx }) => ({ // Row-level filter (e.g. for Drizzle ORM WHERE clause) where: ctx.role === "admin" ? undefined : eq(posts.authorId, ctx.userId), })) .withCheck<Post>()(({ ctx, target, verdictMap }) => { const level = ctx.userId === target.authorId ? "owner" : "other"; return verdictMap[level]; });

// Usage const g = postGuard.for({ userId: "1", role: "user" }); const rows = await db.select().from(posts).where(g.where); // row-level const results = rows.map((row) => g.check(row).pick(row)); // field-level

combineGuards

Bundles multiple guards for different resources and binds them all at once with a single .for() call.

const guards = combineGuards<Ctx>()({ users: userGuard, posts: postGuard, });

const g = guards.for({ userId: "1", role: "user" });

g.users.check({ id: "1", email: "a@b.com", name: "A" }); g.posts.check({ id: "p1", content: "hello", authorId: "1" });

FieldVerdict Helpers

verdict.allowedFields; // string[] of allowed field names verdict.coversAll(["id", "name"]); // true if all given fields are allowed verdict.coversSome(["email"]); // true if any given field is allowed verdict.pick(obj); // returns object with only allowed fields

mergeFieldVerdicts

Merges multiple verdicts with "union" (any-of) or "intersection" (all-of) strategy.

// Union: field allowed if ANY verdict allows it mergeFieldVerdicts("union", [verdictA, verdictB], fields);

// Intersection: field allowed only if ALL verdicts allow it mergeFieldVerdicts("intersection", [verdictA, verdictB], fields);

Also available as mergeVerdicts on every guard instance:

const verdict = guard.mergeVerdicts("union", { owner: true, admin: false });

Type Safety

All fields, levels, and verdicts are inferred from your definitions. The TypeScript compiler immediately flags:

  • Unknown field names in policy

  • Unknown levels in verdictMap lookups

  • Incorrect return types from .withCheck()

Type errors from AI-generated code become instant feedback — no runtime surprises.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

canopy-i18n

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

HTML to Markdown

Convert HTML↔Markdown for web clipping, clean notes, and batch content migration. Use when users ask 网页转Markdown/Markdown转HTML/批量转换. Supports local files, UR...

Registry SourceRecently Updated
Coding

Podfetcher Tools

Search podcasts, browse episodes, and fetch podcast transcripts from Podfetcher using the bundled Node.js CLI, SDK, or MCP server.

Registry SourceRecently Updated
Coding

test

Extract and categorize expenses from receipts or statements, map to GL codes, check compliance with policies, and flag anomalies for review.

Registry SourceRecently Updated