https://github.com/cleverbrush/framework
A collection of lightweight, strongly-typed TypeScript utility libraries — schema validation with type inference, async helpers, deep object operations, object mapping, job scheduling, and more.
https://github.com/cleverbrush/framework
async-utility clickhouse deep-merge job-scheduler knex monorepo npm-workspaces object-mapping schema-validation typescript utility-library vitest
Last synced: 9 days ago
JSON representation
A collection of lightweight, strongly-typed TypeScript utility libraries — schema validation with type inference, async helpers, deep object operations, object mapping, job scheduling, and more.
- Host: GitHub
- URL: https://github.com/cleverbrush/framework
- Owner: cleverbrush
- License: other
- Created: 2022-03-03T11:49:09.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2026-04-04T23:06:56.000Z (22 days ago)
- Last Synced: 2026-04-05T00:34:02.300Z (22 days ago)
- Topics: async-utility, clickhouse, deep-merge, job-scheduler, knex, monorepo, npm-workspaces, object-mapping, schema-validation, typescript, utility-library, vitest
- Language: TypeScript
- Homepage: https://docs.cleverbrush.com
- Size: 3.48 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Cleverbrush Framework
[](https://github.com/cleverbrush/framework/actions/workflows/ci.yml)
[](./LICENSE)
[](https://standardschema.dev/)

A monorepo of production-quality TypeScript libraries. Written with zero runtime dependencies, strict types, and a strong focus on correctness — every package ships with unit tests, full TypeScript type coverage, and automated CI on every pull request.
The flagship package is **`@cleverbrush/schema`** — a schema validation library that is faster than Zod in 14 out of 15 benchmarks (up to 204× faster on invalid input), 3× smaller than Zod v4 in bundle size, and compatible with 50+ ecosystem tools via [Standard Schema v1](https://standardschema.dev/).
---
## Packages
| Package | Description |
| --- | --- |
| [`@cleverbrush/schema`](./libs/schema) | Schema definition, type inference, and runtime validation. [Standard Schema v1](https://standardschema.dev/) compatible — works with tRPC, TanStack Form, React Hook Form, T3 Env, Hono, and 50+ other tools. Wraps external schemas (Zod, Valibot, ArkType) via `extern()` |
| [`@cleverbrush/mapper`](./libs/mapper) | Schema-driven object mapping with compile-time completeness checking and type-safe property selectors |
| [`@cleverbrush/react-form`](./libs/react-form) | Headless, schema-driven form system for React — type-safe field binding, auto-field rendering, UI-agnostic |
| [`@cleverbrush/schema-json`](./libs/schema-json) | Bidirectional JSON Schema conversion: `toJsonSchema()` + `fromJsonSchema()` with full type inference |
| [`@cleverbrush/async`](./libs/async) | Async utilities: `Collector`, `debounce`, `throttle`, `retry` |
| [`@cleverbrush/deep`](./libs/deep) | Deep operations on objects: deep equality, deep merge, flattening, hashing |
| [`@cleverbrush/scheduler`](./libs/scheduler) | Cron-like job scheduler for Node.js using worker threads |
| [`@cleverbrush/knex-clickhouse`](./libs/knex-clickhouse) | Knex query builder dialect for ClickHouse |
---
## Why @cleverbrush/schema?
If you have used Zod, Yup, or Joi, the fluent API will feel immediately familiar — with several important differences.
### One schema, four capabilities
```
@cleverbrush/schema
│
├── TypeScript inference (InferType)
├── Runtime validation (.validate() / .validateAsync())
├── @cleverbrush/mapper (type-safe object mapping)
├── @cleverbrush/react-form (auto-generated, schema-driven forms)
└── @cleverbrush/schema-json (bidirectional JSON Schema)
```
Define a schema once and get all four capabilities for free — no duplication between types, validators, mappers, and form configs.
### Quick example
```ts
import { object, string, number, InferType } from '@cleverbrush/schema';
const UserSchema = object({
name: string().nonempty().minLength(2),
email: string().email(),
age: number().min(18).optional(),
});
// TypeScript type — inferred automatically, no duplication
type User = InferType;
// Runtime validation
const result = UserSchema.validate({ name: 'Alice', email: 'alice@example.com' });
if (result.valid) {
console.log(result.object); // typed as User
} else {
const nameErrors = result.getErrorsFor((p) => p.name);
console.log(nameErrors.errors); // ['Name must be at least 2 characters']
}
// Standard Schema interop — pass directly to tRPC, TanStack Form, T3 Env, …
const validator = UserSchema['~standard'];
```
### Performance vs Zod
Benchmarked with [Vitest bench](https://vitest.dev/guide/features.html#benchmarking) against Zod v4 on the same machine:
| Benchmark | @cleverbrush/schema | Zod | Ratio |
| --- | --- | --- | --- |
| Array 100 objects — valid | 35,228 ops/s | 13,277 ops/s | **2.65× faster** |
| Array 100 objects — invalid | 899,329 ops/s | 4,396 ops/s | **204× faster** |
| Complex order — valid | 198,988 ops/s | 136,090 ops/s | **1.46× faster** |
| Complex order — invalid | 884,706 ops/s | 26,106 ops/s | **33.9× faster** |
| Flat object — valid | 1,001,194 ops/s | 840,725 ops/s | **1.19× faster** |
| Flat object — invalid | 2,653,630 ops/s | 176,222 ops/s | **15.1× faster** |
| Nested object — valid | 690,556 ops/s | 368,893 ops/s | **1.87× faster** |
| Nested object — invalid | 2,739,319 ops/s | 87,245 ops/s | **31.4× faster** |
| String — valid | 5,348,564 ops/s | 3,533,945 ops/s | **1.51× faster** |
| String — invalid | 5,749,087 ops/s | 482,961 ops/s | **11.9× faster** |
| Number — valid | 7,911,266 ops/s | 4,806,511 ops/s | **1.65× faster** |
| Number — invalid | 5,387,475 ops/s | 637,513 ops/s | **8.45× faster** |
| Union first branch | 1,925,508 ops/s | 1,529,547 ops/s | **1.26× faster** |
| Union last branch | 676,107 ops/s | 732,682 ops/s | 0.92× |
| Union no match — invalid | 5,873,118 ops/s | 385,453 ops/s | **15.2× faster** |
**14 out of 15 benchmarks.** The early-exit optimization on invalid data produces especially large gains — up to 204× — because type errors are caught at the first failing field without evaluating the rest.
Run the benchmarks yourself:
```bash
npm run bench
```
### Bundle size vs competitors
| Bundle | Gzipped | Notes |
| --- | --- | --- |
| `@cleverbrush/schema` (full) | **14 KB** | All builders + built-in extensions |
| `@cleverbrush/schema/string` | **3.8 KB** | Sub-path import, one builder only |
| `@cleverbrush/schema/object` | **5.8 KB** | Sub-path import, one builder only |
| Zod v3 (full) | 14.4 KB | For reference |
| Zod v4 (full) | **41 KB** | **3× larger than @cleverbrush/schema** |
Sub-path exports (`@cleverbrush/schema/string`, `/number`, `/object`, `/array`, `/core`) enable fine-grained tree-shaking for bundle-critical applications.
### Competitive feature comparison
| | @cleverbrush/schema | Zod | Yup | Joi |
| --- | --- | --- | --- | --- |
| TypeScript type inference | ✓ | ✓ | ~ | ✗ |
| [Standard Schema v1](https://standardschema.dev/) | ✓ | ✓ | ✗ | ✗ |
| **PropertyDescriptors** (runtime introspection) | ✓ | ✗ | ✗ | ✗ |
| **Type-safe extension system** | ✓ | ✗ | ✗ | ✗ |
| **Built-in object mapper** | ✓ | ✗ | ✗ | ✗ |
| **Built-in form generation** | ✓ | ✗ | ✗ | ✗ |
| Bidirectional JSON Schema | ✓ | ~ (output only) | ✗ | ✗ |
| **External schema interop** (`extern()`) | ✓ | ✗ | ✗ | ✗ |
| JSDoc comment preservation | ✓ | ✗ | ✗ | ✗ |
| Immutable fluent API | ✓ | ✓ | ✗ | ✗ |
| Zero runtime dependencies | ✓ | ✓ | ✗ | ✗ |
| Bundle size (full, gzipped) | **14 KB** | 41 KB (v4) | ~19 KB | ~26 KB |
**PropertyDescriptors** are the architectural differentiator. Every schema emits a structured descriptor tree at runtime — not just a black-box validator function. This is what enables the mapper to provide type-safe property selectors, react-form to auto-generate fields, and schema-json to produce accurate JSON Schema output. No other popular validation library exposes this level of runtime metadata.
---
## Code Quality
Every pull request must pass all of the following gates before merging — enforced by the CI pipeline:
| Gate | Tool | What it checks |
| --- | --- | --- |
| **Linting** | [Biome](https://biomejs.dev/) | Code style, formatting, and static analysis across all packages and the website |
| **Type checking** | TypeScript (strict mode) | Strict null-checks, no implicit `any`, full type coverage |
| **Unit tests** | [Vitest](https://vitest.dev/) | Runtime behaviour + type-level tests (`expectTypeOf`) — coverage spans all builders, extensions, edge cases, and error paths |
| **Build** | [tsup](https://tsup.egoist.dev/) + [Turbo](https://turbo.build/) | ESM output compiles cleanly with no TypeScript errors |
| **Benchmarks** | Vitest bench | Performance regressions are visible before merge |
Run everything locally before opening a PR:
```bash
npm run lint # Biome static analysis
npm run build # compile all packages
npm test # unit tests + type checks
npm run bench # performance benchmarks
```
---
## Development
This project uses [npm workspaces](https://docs.npmjs.com/cli/using-npm/workspaces) and [Turborepo](https://turbo.build/) for incremental builds. All library source is under `libs/`.
### Setup
```bash
npm install
```
### Build
```bash
npm run build
```
### Test
```bash
npm test
```
### Documentation
API docs are generated by [TypeDoc](https://typedoc.org/) and published at https://docs.cleverbrush.com/.
```bash
npm run docs
```
Each library has its own `README.md` with usage examples and full API reference.
---
## Release
This project uses [Changesets](https://github.com/changesets/changesets) for versioning and publishing. All packages are versioned together.
1. **Add a changeset** after making changes:
```bash
npm run changeset
```
Follow the prompts to describe the change. A changeset file is created in `.changeset/`.
2. **Version packages** when ready to release:
```bash
npm run version
```
This bumps `package.json` versions and updates `CHANGELOG.md` files.
3. **Publish** to npm:
```bash
npm run release
```
For a beta release:
```bash
npm run publish:beta
```
---
## Contributing
Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for full guidelines.
The short version: make sure your changes include tests, pass linting (`npm run lint`), and don't break existing tests (`npm test`). If you add or change behaviour, update the relevant JSDoc comments — that's all the documentation update that's usually needed.
Extensions are the easiest place to start contributing — each one is a self-contained file with tests. Look for issues labelled **good first issue**.
---
## License
[BSD-3-Clause](./LICENSE)