@7ender/schemarpc
v0.1.2
Published
Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.
Downloads
285
Readme
@7ender/schemarpc
Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.
What is SchemaRPC?
SchemaRPC is a schema-driven API framework for TypeScript that turns your database schema into a fully functional, type-safe backend. Define your schema once and get CRUD endpoints, relations, filtering, and built-in security — without writing controllers or routers.
Built on top of Drizzle ORM and tRPC, SchemaRPC focuses on API generation, not just database access, with a transport-agnostic runtime and production-ready features out of the box.
Core Flow
Schema → createPlatform() → Secure API + Policies → tRPC / OpenAPI → Client (React / any)Best Fit
- Multi-tenant SaaS applications
- Admin panels & internal tools
- CRUD-heavy backends
- Rapid development with minimal boilerplate
Features
- Auto-generated CRUD API - Create full CRUD operations from Drizzle schema
- RBAC - Role-based access control at operation level
- ABAC - Attribute-based access control with owner/tenant policies
- RLS - Row-level security at database level
- Caching - Built-in Redis caching with tag-based invalidation
- i18n - Internationalization support for JSONB fields
- Audit logging - Track all database changes
- Realtime - WebSocket/SSE support for real-time updates
Installation
npm install @7ender/schemarpcQuick Start
import { drizzle } from 'drizzle-orm/postgres-js'
import { pgTable, serial, text } from 'drizzle-schema/pg-core'
import { createPlatform, createCrudApi } from '@7ender/schemarpc'
// Define your schema
const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull(),
})
// Create platform
const platform = createPlatform({
db: drizzle(connectionString),
schema: { users },
})
// Create CRUD API
const api = createCrudApi(platform, {
users: {
operations: ['list', 'get', 'create', 'update', 'delete'],
},
})Architecture
| Layer | Files | Purpose | |-------|-------|---------| | Core | create-platform.ts, crud-factory.ts | Schema iteration, full CRUD generation | | Plugins | rls.ts, rbac.ts, abac.ts, cache.ts, i18n.ts | Middleware hooks for cross-cutting concerns | | Utils | filters.ts, tags.ts | Query building, cache key generation | | Adapters | trpc.ts, orpc.ts, openapi.ts | Transport layer adapters | | Client | react.ts, query-client.ts | React hooks and fetch client |
Plugins
RBAC (Role-Based Access Control)
Operation-level permissions: Can user call this endpoint?
import { rbacPlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
rbacPlugin({
roles: {
admin: ['*'],
user: ['list', 'get'],
},
}),
],
},
})ABAC (Attribute-Based Access Control)
Data-level: Which records can user access?
import { abacPlugin, ownerPolicy } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
posts: {
plugins: [
abacPlugin({
policies: {
owner: ownerPolicy('userId'),
},
}),
],
},
})RLS (Row-Level Security)
Tenant isolation at database level:
import { rlsPlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
rlsPlugin({ tenantColumn: 'tenantId' }),
],
},
})Cache Plugin
Redis caching with tag invalidation:
import { cachePlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
cachePlugin({ ttl: 60, prefix: 'app' }),
],
},
})i18n Plugin
Localized field extraction from JSONB:
import { i18nPlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
i18nPlugin({ defaultLang: 'en', fallback: true }),
],
},
})Audit Plugin
Track database changes:
import { auditPlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
auditPlugin(),
],
},
})Realtime Plugin
Broadcast SSE/WebSocket events:
import { realtimePlugin } from '@7ender/schemarpc'
const api = createCrudApi(platform, {
users: {
plugins: [
realtimePlugin(),
],
},
})CRUD Operations
| Operation | Method | Input | Features |
|-----------|--------|-------|----------|
| list | query | { where?, orderBy?, limit?, offset?, include? } | Filtering, pagination, sorting, eager relations |
| getById | query | { id: string, include? } | Single record fetch with eager relations |
| create | mutation | InsertSchema | Auto-validated via Zod |
| update | mutation | { id, data: Partial<InsertSchema> } | Partial updates, auto updatedAt |
| createMany | mutation | InsertSchema[] | Batch insertion |
| updateMany | mutation | { where, data: Partial<InsertSchema> } | Batch updates with partial data |
| delete | mutation | { id: string } | Soft delete support |
| count | query | { where? } | For pagination totals |
| onChanges | subscription | { action? } | Real-time DB changes Event Stream |
Filter Operators
Basic Operators
- eq - Exact match (NULL-safe)
- neq - Not equal (NULL-safe)
- contains - LIKE %val%
- startsWith - LIKE val%
- endsWith - LIKE %val
- gt / gte - Greater than
- lt / lte - Less than
- in - IN array
- notIn - NOT IN array
- between - Range (inclusive)
- isNull - IS NULL / IS NOT NULL
Logical Grouping
- AND (object) - Single where object, all operators combined with AND
- OR (array) - Array of where objects, AND inside each group, OR between groups
Aggregations
- sum - Sum of a numeric column
- avg - Average of a numeric column
- min - Minimum value
- max - Maximum value
- count - Row count
- groupBy - Group aggregate results by columns
Adapters
Export your API with different adapters:
import { createTRPCRouter } from '@7ender/schemarpc/adapters/trpc'
import { createORPCRouter } from '@7ender/schemarpc/adapters/orpc'
import { createOpenAPIRouter } from '@7ender/schemarpc/adapters/openapi'Example Usage
// server/platform.ts
import * as schema from "./db/schema"
import { eq, or } from "drizzle-orm"
import { createPlatform } from "@7ender/schemarpc"
import { rbacPlugin, abacPlugin, rlsPlugin, cachePlugin, i18nPlugin } from "@7ender/schemarpc/plugins"
export const platform = createPlatform({
schema,
// Auto-generate CRUD endpoints from Drizzle schema
config: {
users: { expose: true, softDelete: true },
listings: { expose: true, softDelete: true, timestamps: true },
},
plugins: [
rbacPlugin({
permissions: {
users: { list: "users:read" },
listings: { list: "listings:read", create: "listings:create" },
},
}),
abacPlugin({
policies: {
listings: {
list: ({ ctx }) => or(
eq(schema.listings.ownerId, ctx.userId),
eq(schema.listings.status, "published")
),
create: ({ ctx }) => !!ctx.userId,
}
},
}),
rlsPlugin({ tenantColumn: "tenantId" }),
cachePlugin({ ttl: 60, prefix: "app" }),
i18nPlugin({ defaultLang: "en", fallback: true }),
],
})
// Runtime usage (transport-agnostic)
const rows = await platform.apis.listings.list.handler({
ctx: {
db,
tenantId: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
userId: "11111111-1111-4111-8111-111111111111",
lang: "ru", // translated from JSONB title_i18n
rbac: { has: () => true },
},
input: {
where: { status: { eq: "published" } },
orderBy: { field: "createdAt", direction: "desc" },
limit: 10,
},
})
// rows[0].titleI18n -> localized string for "ru"Roadmap
Phase 1: Completed
- Full CRUD operations
- Plugin architecture (RLS, RBAC, ABAC, Cache, i18n)
- tRPC + OpenAPI adapters
- React hooks client
- Advanced filtering (10+ operators)
- Deep relations with eager loading
- Batch operations (createMany, updateMany)
Phase 2: Completed
- Audit log plugin
- Performance Benchmarking (+0.1ms overhead)
- Real-time subscriptions (PubSub + tRPC Observable)
- TypeScript strict mode without any tails
- Connection Pooling & Transaction Support
- Schema Migration CLI tool (
schemarpc diff)
License
MIT
