{"_id":"@7ender/schemarpc","_rev":"3-5ab1708a356ca947b1350a08197cabca","name":"@7ender/schemarpc","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@7ender/schemarpc","version":"0.1.0","license":"MIT","_id":"@7ender/schemarpc@0.1.0","maintainers":[{"name":"7ender","email":"root@shock.ee"}],"bin":{"schemarpc":"dist/cli/index.js"},"dist":{"shasum":"de04d9a55272e0ebc60bda20faf5ddbb4a3a665e","tarball":"https://registry.npmjs.org/@7ender/schemarpc/-/schemarpc-0.1.0.tgz","fileCount":118,"integrity":"sha512-OOSTm8OWUlVAcsbDfBkr+elattdoZloAOpoCnfqwiVFhheK4+gvUSse4ntY/IPUuUVcyvZ+gEeOmsLb21hiT3g==","signatures":[{"sig":"MEYCIQDxdYFgBrExusNxuJHj8RljAsdhtb5XPdMdEmt23lPLOQIhAMx9GwFwkVc5SwKHWw8aG4cm2Ijcb6NvbRrAWGYVHuVA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":269588},"main":"./dist/index.js","_from":"file:7ender-schemarpc-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./plugins":{"types":"./dist/plugins/index.d.ts","default":"./dist/plugins/index.js"},"./utils/*":{"types":"./dist/utils/*.d.ts","default":"./dist/utils/*.js"},"./client/*":{"types":"./dist/client/*.d.ts","default":"./dist/client/*.js"},"./server/*":{"types":"./dist/server/*.d.ts","default":"./dist/server/*.js"},"./plugins/*":{"types":"./dist/plugins/*.d.ts","default":"./dist/plugins/*.js"},"./adapters/*":{"types":"./dist/adapters/*.d.ts","default":"./dist/adapters/*.js"},"./package.json":"./package.json"},"scripts":{"dev":"next dev --turbopack","lint":"tsc --noEmit","test":"vitest run","build":"tsc -p tsconfig.build.json","start":"next start","test:e2e":"vitest run __tests__/e2e","build:web":"next build","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"7ender","email":"root@shock.ee"},"_resolved":"/private/var/folders/nj/3_n1_0611870gfrb9ql5sqm40000gn/T/39b7fc9cb874a2ea31fe48a565bdb1a0/7ender-schemarpc-0.1.0.tgz","_integrity":"sha512-OOSTm8OWUlVAcsbDfBkr+elattdoZloAOpoCnfqwiVFhheK4+gvUSse4ntY/IPUuUVcyvZ+gEeOmsLb21hiT3g==","_npmVersion":"11.6.2","description":"Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"pg":"^8.20.0","zod":"^4.3.6","clsx":"^2.1.1","next":"^16.2.1","react":"^19.2.4","commander":"^14.0.3","react-dom":"^19.2.4","drizzle-orm":"^0.45.1","drizzle-zod":"^0.8.3","@orpc/client":"^1.13.11","@orpc/server":"^1.13.11","@trpc/server":"^11.15.0","lucide-react":"^1.6.0","tailwind-merge":"^3.5.0","class-variance-authority":"^0.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","vitest":"^4.1.1","typescript":"^6.0.2","@types/node":"^25.5.0","tailwindcss":"^4.2.2","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@vitest/coverage-v8":"^4.1.1","@electric-sql/pglite":"^0.4.1","@tailwindcss/postcss":"^4.2.2"},"_npmOperationalInternal":{"tmp":"tmp/schemarpc_0.1.0_1774473852200_0.09889954804154377","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@7ender/schemarpc","version":"0.1.1","license":"MIT","_id":"@7ender/schemarpc@0.1.1","maintainers":[{"name":"7ender","email":"root@shock.ee"}],"bin":{"schemarpc":"dist/cli/index.js"},"dist":{"shasum":"cdca3196158aaad790727c1f40c57c5f989ae3de","tarball":"https://registry.npmjs.org/@7ender/schemarpc/-/schemarpc-0.1.1.tgz","fileCount":118,"integrity":"sha512-4MrqTI6nr6y4VrBNuB286XuJvmMfh1wPLBUHw9jrfmLducusbO5a00jBRutTgYLOOSa6A1KKnxazqQkiW1sR/Q==","signatures":[{"sig":"MEQCIBRKsnIgcetc9AXfucXi7loyBFSkX2vbpdz2gZfiDABbAiAEQKie6zFHe06lR8/qySXirRhs3cTTFQXpSI6UEpI5tQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":269153},"main":"./dist/index.js","_from":"file:7ender-schemarpc-0.1.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./plugins":{"types":"./dist/plugins/index.d.ts","default":"./dist/plugins/index.js"},"./utils/*":{"types":"./dist/utils/*.d.ts","default":"./dist/utils/*.js"},"./client/*":{"types":"./dist/client/*.d.ts","default":"./dist/client/*.js"},"./server/*":{"types":"./dist/server/*.d.ts","default":"./dist/server/*.js"},"./plugins/*":{"types":"./dist/plugins/*.d.ts","default":"./dist/plugins/*.js"},"./adapters/*":{"types":"./dist/adapters/*.d.ts","default":"./dist/adapters/*.js"},"./package.json":"./package.json"},"scripts":{"dev":"next dev --turbopack","lint":"tsc --noEmit","test":"vitest run","build":"tsc -p tsconfig.build.json","start":"next start","test:e2e":"vitest run __tests__/e2e","build:web":"next build","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"7ender","email":"root@shock.ee"},"_resolved":"/private/var/folders/nj/3_n1_0611870gfrb9ql5sqm40000gn/T/aeee96194523f4056fae68e57b6d27f6/7ender-schemarpc-0.1.1.tgz","_integrity":"sha512-4MrqTI6nr6y4VrBNuB286XuJvmMfh1wPLBUHw9jrfmLducusbO5a00jBRutTgYLOOSa6A1KKnxazqQkiW1sR/Q==","_npmVersion":"11.6.2","description":"Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"zod":"^4.3.6","drizzle-orm":"^0.45.1","drizzle-zod":"^0.8.3","@orpc/client":"^1.13.11","@orpc/server":"^1.13.11"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^6.0.2","@types/node":"^25.5.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/schemarpc_0.1.1_1774474213866_0.19895882380822116","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@7ender/schemarpc","version":"0.1.2","description":"Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.","license":"MIT","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./plugins":{"types":"./dist/plugins/index.d.ts","default":"./dist/plugins/index.js"},"./plugins/*":{"types":"./dist/plugins/*.d.ts","default":"./dist/plugins/*.js"},"./adapters/*":{"types":"./dist/adapters/*.d.ts","default":"./dist/adapters/*.js"},"./client/*":{"types":"./dist/client/*.d.ts","default":"./dist/client/*.js"},"./server/*":{"types":"./dist/server/*.d.ts","default":"./dist/server/*.js"},"./utils/*":{"types":"./dist/utils/*.d.ts","default":"./dist/utils/*.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"dependencies":{"@orpc/client":"^1.13.11","@orpc/server":"^1.13.11","drizzle-orm":"^0.45.1","drizzle-zod":"^0.8.3","zod":"^4.3.6"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"devDependencies":{"@types/node":"^25.5.0","typescript":"^6.0.2"},"bin":{"schemarpc":"dist/cli/index.js"},"scripts":{"dev":"next dev --turbopack","build":"tsc -p tsconfig.build.json","build:web":"next build","start":"next start","lint":"tsc --noEmit","test":"vitest run","test:e2e":"vitest run __tests__/e2e","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_id":"@7ender/schemarpc@0.1.2","_integrity":"sha512-NYJzkOBHB2em3HWwTAwVJrvyjjv5JYiZuySESCso/PKUivtxEbLaijNsYk8C/YJHFR3gBin8xX4fIgf8G3EvFg==","_resolved":"/private/var/folders/nj/3_n1_0611870gfrb9ql5sqm40000gn/T/700138da3ff48a2cc193f411705ed829/7ender-schemarpc-0.1.2.tgz","_from":"file:7ender-schemarpc-0.1.2.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-NYJzkOBHB2em3HWwTAwVJrvyjjv5JYiZuySESCso/PKUivtxEbLaijNsYk8C/YJHFR3gBin8xX4fIgf8G3EvFg==","shasum":"e0137d9a55fce4ea2964f8704541db42d47990be","tarball":"https://registry.npmjs.org/@7ender/schemarpc/-/schemarpc-0.1.2.tgz","fileCount":119,"unpackedSize":277705,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCID6wFreYb1MU6q7o7Yn3BFduMATvPOXonDdRsY0ctn0BAiBV4lO5tWw6zEm2uQNfbLqtH4JKuZQPcCQ/hoDY9wAyiQ=="}]},"_npmUser":{"name":"7ender","email":"root@shock.ee"},"directories":{},"maintainers":[{"name":"7ender","email":"root@shock.ee"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/schemarpc_0.1.2_1774474875666_0.3947534056661135"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-25T21:24:12.137Z","modified":"2026-03-25T21:41:15.947Z","0.1.0":"2026-03-25T21:24:12.377Z","0.1.1":"2026-03-25T21:30:14.039Z","0.1.2":"2026-03-25T21:41:15.817Z"},"license":"MIT","description":"Generate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.","maintainers":[{"name":"7ender","email":"root@shock.ee"}],"readme":"# @7ender/schemarpc\n\nGenerate production-ready CRUD APIs from Drizzle schema with built-in RBAC, ABAC, and RLS.\n\n## What is SchemaRPC?\n\n**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.\n\nBuilt 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.\n\n### Core Flow\n\n```\nSchema → createPlatform() → Secure API + Policies → tRPC / OpenAPI → Client (React / any)\n```\n\n### Best Fit\n- Multi-tenant SaaS applications\n- Admin panels & internal tools\n- CRUD-heavy backends\n- Rapid development with minimal boilerplate\n\n## Features\n\n- **Auto-generated CRUD API** - Create full CRUD operations from Drizzle schema\n- **RBAC** - Role-based access control at operation level\n- **ABAC** - Attribute-based access control with owner/tenant policies\n- **RLS** - Row-level security at database level\n- **Caching** - Built-in Redis caching with tag-based invalidation\n- **i18n** - Internationalization support for JSONB fields\n- **Audit logging** - Track all database changes\n- **Realtime** - WebSocket/SSE support for real-time updates\n\n## Installation\n\n```bash\nnpm install @7ender/schemarpc\n```\n\n## Quick Start\n\n```typescript\nimport { drizzle } from 'drizzle-orm/postgres-js'\nimport { pgTable, serial, text } from 'drizzle-schema/pg-core'\nimport { createPlatform, createCrudApi } from '@7ender/schemarpc'\n\n// Define your schema\nconst users = pgTable('users', {\n  id: serial('id').primaryKey(),\n  name: text('name').notNull(),\n  email: text('email').notNull(),\n})\n\n// Create platform\nconst platform = createPlatform({\n  db: drizzle(connectionString),\n  schema: { users },\n})\n\n// Create CRUD API\nconst api = createCrudApi(platform, {\n  users: {\n    operations: ['list', 'get', 'create', 'update', 'delete'],\n  },\n})\n```\n\n## Architecture\n\n| Layer | Files | Purpose |\n|-------|-------|---------|\n| Core | create-platform.ts, crud-factory.ts | Schema iteration, full CRUD generation |\n| Plugins | rls.ts, rbac.ts, abac.ts, cache.ts, i18n.ts | Middleware hooks for cross-cutting concerns |\n| Utils | filters.ts, tags.ts | Query building, cache key generation |\n| Adapters | trpc.ts, orpc.ts, openapi.ts | Transport layer adapters |\n| Client | react.ts, query-client.ts | React hooks and fetch client |\n\n## Plugins\n\n### RBAC (Role-Based Access Control)\n\nOperation-level permissions: Can user call this endpoint?\n\n```typescript\nimport { rbacPlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      rbacPlugin({\n        roles: {\n          admin: ['*'],\n          user: ['list', 'get'],\n        },\n      }),\n    ],\n  },\n})\n```\n\n### ABAC (Attribute-Based Access Control)\n\nData-level: Which records can user access?\n\n```typescript\nimport { abacPlugin, ownerPolicy } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  posts: {\n    plugins: [\n      abacPlugin({\n        policies: {\n          owner: ownerPolicy('userId'),\n        },\n      }),\n    ],\n  },\n})\n```\n\n### RLS (Row-Level Security)\n\nTenant isolation at database level:\n\n```typescript\nimport { rlsPlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      rlsPlugin({ tenantColumn: 'tenantId' }),\n    ],\n  },\n})\n```\n\n### Cache Plugin\n\nRedis caching with tag invalidation:\n\n```typescript\nimport { cachePlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      cachePlugin({ ttl: 60, prefix: 'app' }),\n    ],\n  },\n})\n```\n\n### i18n Plugin\n\nLocalized field extraction from JSONB:\n\n```typescript\nimport { i18nPlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      i18nPlugin({ defaultLang: 'en', fallback: true }),\n    ],\n  },\n})\n```\n\n### Audit Plugin\n\nTrack database changes:\n\n```typescript\nimport { auditPlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      auditPlugin(),\n    ],\n  },\n})\n```\n\n### Realtime Plugin\n\nBroadcast SSE/WebSocket events:\n\n```typescript\nimport { realtimePlugin } from '@7ender/schemarpc'\n\nconst api = createCrudApi(platform, {\n  users: {\n    plugins: [\n      realtimePlugin(),\n    ],\n  },\n})\n```\n\n## CRUD Operations\n\n| Operation | Method | Input | Features |\n|-----------|--------|-------|----------|\n| list | query | `{ where?, orderBy?, limit?, offset?, include? }` | Filtering, pagination, sorting, eager relations |\n| getById | query | `{ id: string, include? }` | Single record fetch with eager relations |\n| create | mutation | InsertSchema | Auto-validated via Zod |\n| update | mutation | `{ id, data: Partial<InsertSchema> }` | Partial updates, auto updatedAt |\n| createMany | mutation | InsertSchema[] | Batch insertion |\n| updateMany | mutation | `{ where, data: Partial<InsertSchema> }` | Batch updates with partial data |\n| delete | mutation | `{ id: string }` | Soft delete support |\n| count | query | `{ where? }` | For pagination totals |\n| onChanges | subscription | `{ action? }` | Real-time DB changes Event Stream |\n\n## Filter Operators\n\n### Basic Operators\n\n- **eq** - Exact match (NULL-safe)\n- **neq** - Not equal (NULL-safe)\n- **contains** - LIKE %val%\n- **startsWith** - LIKE val%\n- **endsWith** - LIKE %val\n- **gt / gte** - Greater than\n- **lt / lte** - Less than\n- **in** - IN array\n- **notIn** - NOT IN array\n- **between** - Range (inclusive)\n- **isNull** - IS NULL / IS NOT NULL\n\n### Logical Grouping\n\n- **AND (object)** - Single where object, all operators combined with AND\n- **OR (array)** - Array of where objects, AND inside each group, OR between groups\n\n### Aggregations\n\n- **sum** - Sum of a numeric column\n- **avg** - Average of a numeric column\n- **min** - Minimum value\n- **max** - Maximum value\n- **count** - Row count\n- **groupBy** - Group aggregate results by columns\n\n## Adapters\n\nExport your API with different adapters:\n\n```typescript\nimport { createTRPCRouter } from '@7ender/schemarpc/adapters/trpc'\nimport { createORPCRouter } from '@7ender/schemarpc/adapters/orpc'\nimport { createOpenAPIRouter } from '@7ender/schemarpc/adapters/openapi'\n```\n\n## Example Usage\n\n```typescript\n// server/platform.ts\nimport * as schema from \"./db/schema\"\nimport { eq, or } from \"drizzle-orm\"\nimport { createPlatform } from \"@7ender/schemarpc\"\nimport { rbacPlugin, abacPlugin, rlsPlugin, cachePlugin, i18nPlugin } from \"@7ender/schemarpc/plugins\"\n\nexport const platform = createPlatform({\n  schema,\n\n  // Auto-generate CRUD endpoints from Drizzle schema\n  config: {\n    users: { expose: true, softDelete: true },\n    listings: { expose: true, softDelete: true, timestamps: true },\n  },\n\n  plugins: [\n    rbacPlugin({\n      permissions: {\n        users: { list: \"users:read\" },\n        listings: { list: \"listings:read\", create: \"listings:create\" },\n      },\n    }),\n\n    abacPlugin({\n      policies: {\n        listings: {\n          list: ({ ctx }) => or(\n            eq(schema.listings.ownerId, ctx.userId),\n            eq(schema.listings.status, \"published\")\n          ),\n          create: ({ ctx }) => !!ctx.userId,\n        }\n      },\n    }),\n\n    rlsPlugin({ tenantColumn: \"tenantId\" }),\n    cachePlugin({ ttl: 60, prefix: \"app\" }),\n    i18nPlugin({ defaultLang: \"en\", fallback: true }),\n  ],\n})\n\n// Runtime usage (transport-agnostic)\nconst rows = await platform.apis.listings.list.handler({\n  ctx: {\n    db,\n    tenantId: \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\n    userId: \"11111111-1111-4111-8111-111111111111\",\n    lang: \"ru\", // translated from JSONB title_i18n\n    rbac: { has: () => true },\n  },\n  input: {\n    where: { status: { eq: \"published\" } },\n    orderBy: { field: \"createdAt\", direction: \"desc\" },\n    limit: 10,\n  },\n})\n\n// rows[0].titleI18n -> localized string for \"ru\"\n```\n\n## Roadmap\n\n### Phase 1: Completed\n- Full CRUD operations\n- Plugin architecture (RLS, RBAC, ABAC, Cache, i18n)\n- tRPC + OpenAPI adapters\n- React hooks client\n- Advanced filtering (10+ operators)\n- Deep relations with eager loading\n- Batch operations (createMany, updateMany)\n\n### Phase 2: Completed\n- Audit log plugin\n- Performance Benchmarking (+0.1ms overhead)\n- Real-time subscriptions (PubSub + tRPC Observable)\n- TypeScript strict mode without any tails\n- Connection Pooling & Transaction Support\n- Schema Migration CLI tool (`schemarpc diff`)\n\n## License\n\nMIT","readmeFilename":"README.md"}