### Quick Start Server Setup Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md A basic example demonstrating how to set up a server, define a user creation endpoint with body validation, and handle requests. ```typescript import { ServerBuilder, endpoint, ActionResult } from '@cleverbrush/server'; import { object, string, number } from '@cleverbrush/schema'; const CreateUserBody = object({ name: string(), age: number() }); const createUser = endpoint .post('/api/users') .body(CreateUserBody); const server = new ServerBuilder(); server.handle(createUser, ({ body }) => { // body is fully typed: { name: string; age: number } return ActionResult.created({ id: 1, ...body }, '/api/users/1'); }); await server.listen(3000); ``` -------------------------------- ### Development Setup Commands Source: https://github.com/cleverbrush/framework/blob/master/README.md Provides essential commands for setting up the development environment, including installing dependencies, linting, building, and testing. ```bash npm ci npm run lint npm run build npm run test ``` -------------------------------- ### Install Dependencies Source: https://github.com/cleverbrush/framework/blob/master/AGENTS.md Use this command to install dependencies, ensuring the lockfile is respected. Prefer `ci` over `install`. ```bash npm ci ``` -------------------------------- ### React Form Quick Start Example Source: https://github.com/cleverbrush/framework/blob/master/libs/react-form/README.md Set up a form with schema validation and custom UI renderers. Define your schema using '@cleverbrush/schema', register UI components via 'FormSystemProvider', and use 'useSchemaForm' to manage form state and submission. ```tsx import { object, string, number } from '@cleverbrush/schema'; import { useSchemaForm, FormSystemProvider, Field } from '@cleverbrush/react-form'; // 1. Define schema — reuse across forms, API validation, mapping, etc. const ContactSchema = object({ name: string().required('Name is required').minLength(2, 'Name must be at least 2 characters'), email: string().required('Email is required'), age: number().required('Age is required').min(18, 'Must be at least 18') }); // 2. Define renderers once per app — maps schema types to UI components const renderers = { string: ({ value, onChange, onBlur, error, touched }) => (
onChange(e.target.value)} onBlur={onBlur} /> {touched && error && {error}}
), number: ({ value, onChange, onBlur, error, touched }) => (
onChange(Number(e.target.value))} onBlur={onBlur} /> {touched && error && {error}}
) }; // 3. Each form component only picks which fields to show — no boilerplate function ContactForm() { const form = useSchemaForm(ContactSchema); const handleSubmit = async () => { const result = await form.submit(); if (result.valid) { console.log('Submitted:', result.object); } }; return (
t.name} form={form} /> t.email} form={form} /> t.age} form={form} />
); } // 4. Wrap once at the app root — all forms below share the renderers function App() { return ( ); } ``` -------------------------------- ### Install @cleverbrush/async Source: https://github.com/cleverbrush/framework/blob/master/libs/async/README.md Install the library using npm. ```bash npm install @cleverbrush/async ``` -------------------------------- ### Install @cleverbrush/otel and @opentelemetry/api Source: https://github.com/cleverbrush/framework/blob/master/libs/otel/README.md Install the core OpenTelemetry package and the API. Optional auto-instrumentations can also be installed if needed. ```bash npm install @cleverbrush/otel @opentelemetry/api # Optional auto-instrumentations (only if you want them): npm install @opentelemetry/instrumentation-http \ @opentelemetry/instrumentation-undici \ @opentelemetry/instrumentation-runtime-node ``` -------------------------------- ### Install @cleverbrush/deep Source: https://github.com/cleverbrush/framework/blob/master/libs/deep/README.md Install the library using npm. ```bash npm install @cleverbrush/deep ``` -------------------------------- ### Install @cleverbrush/log Source: https://github.com/cleverbrush/framework/blob/master/libs/log/README.md Install the library using npm. ```bash npm install @cleverbrush/log ``` -------------------------------- ### Starting Demo Application Source: https://github.com/cleverbrush/framework/blob/master/AGENTS.md Commands to start and stop the demo application, including its PostgreSQL database. Ensure libraries are built before running the backend dev server. ```bash npm run dev:demo # starts Postgres (Docker), runs migrations, starts servers ``` ```bash npm run dev:demo:stop # stops Postgres container ``` -------------------------------- ### Install @cleverbrush/knex-schema Source: https://github.com/cleverbrush/framework/blob/master/libs/knex-schema/README.md Install the package using npm. Ensure you have Knex.js installed as a peer dependency. ```bash npm install @cleverbrush/knex-schema ``` -------------------------------- ### Install @cleverbrush/di and @cleverbrush/schema Source: https://github.com/cleverbrush/framework/blob/master/libs/di/README.md Install the necessary packages for dependency injection and schema definition. ```bash npm install @cleverbrush/di @cleverbrush/schema ``` -------------------------------- ### Configure New Library Documentation Source: https://github.com/cleverbrush/framework/blob/master/DOCS_PIPELINE.md Example configuration for adding a new library to the documentation pipeline. ```json { "$schema": "https://typedoc.org/schema.json", "entryPoints": ["src/index.ts"], "excludePrivate": true } ``` -------------------------------- ### Install @cleverbrush/env Source: https://github.com/cleverbrush/framework/blob/master/libs/env/README.md Install the package and its required peer dependency. ```bash npm install @cleverbrush/env @cleverbrush/schema ``` -------------------------------- ### Install @cleverbrush/orm Source: https://github.com/cleverbrush/framework/blob/master/libs/orm/README.md Install the ORM package. Ensure knex is installed as a peer dependency. ```sh npm install @cleverbrush/orm ``` -------------------------------- ### Install dependencies Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Install the required packages to use the OpenAPI generation framework. ```bash npm install @cleverbrush/server-openapi @cleverbrush/server @cleverbrush/schema ``` -------------------------------- ### Develop Demo Application Source: https://github.com/cleverbrush/framework/blob/master/CLAUDE.md Start the demo application, which includes setting up PostgreSQL with migrations, the backend, and the frontend. Requires Docker for PostgreSQL. ```bash npm run dev:demo ``` -------------------------------- ### Install @cleverbrush/auth Source: https://github.com/cleverbrush/framework/blob/master/libs/auth/README.md Install the @cleverbrush/auth package using npm. ```bash npm install @cleverbrush/auth ``` -------------------------------- ### Install @cleverbrush/server Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Install the @cleverbrush/server package along with @cleverbrush/schema for request validation. ```bash npm install @cleverbrush/server @cleverbrush/schema ``` -------------------------------- ### Quick Start: Initialize and Add Jobs Source: https://github.com/cleverbrush/framework/blob/master/libs/scheduler/README.md Initialize the JobScheduler with a root folder for job files and add jobs with their respective schedules and configurations. Start the scheduler to begin executing jobs. ```typescript import { JobScheduler } from '@cleverbrush/scheduler'; const scheduler = new JobScheduler({ rootFolder: '/path/to/your/jobs' }); scheduler.addJob({ id: 'my-job-1', path: 'job1.js', schedule: { every: 'minute', interval: 5 } }); scheduler.addJob({ id: 'my-job-2', path: 'job2.js', schedule: { every: 'week', interval: 2, dayOfWeek: [1, 3, 5], hour: 9, minute: 30 }, timeout: 1000 * 60 * 4, maxRetries: 3 }); scheduler.start(); ``` -------------------------------- ### Quick Start: Get ClickHouse Connection Source: https://github.com/cleverbrush/framework/blob/master/libs/knex-clickhouse/README.md Initialize a Knex instance for ClickHouse using getClickhouseConnection. Supports select, insert, and raw queries. ```typescript import { getClickhouseConnection } from '@cleverbrush/knex-clickhouse'; const db = getClickhouseConnection({ connection: { url: 'http://localhost:8123', user: 'default', password: '', database: 'my_database' } }); // Select const [rows] = await db('my_table').select('*').where('id', 1); // Insert await db('my_table').insert({ id: 1, name: 'Alice' }); // Raw queries const [rows] = await db.raw('SELECT * FROM my_table WHERE id = ?', [1]); ``` -------------------------------- ### Install @cleverbrush/schema-json Source: https://github.com/cleverbrush/framework/blob/master/libs/schema-json/README.md Install the package using npm. Ensure @cleverbrush/schema@^2.0.0 is also installed as a peer dependency. ```bash npm install @cleverbrush/schema-json ``` -------------------------------- ### End-to-End React Form Example Source: https://github.com/cleverbrush/framework/blob/master/libs/react-form/README.md Demonstrates a complete registration form with nested address, custom validation, and MUI renderers. It shows schema definition, renderer configuration, form component, and app setup with FormSystemProvider. ```tsx import { object, string, number } from '@cleverbrush/schema'; import { useSchemaForm, FormSystemProvider, Field } from '@cleverbrush/react-form'; import { TextField } from '@mui/material'; // Schema — single source of truth for types, validation, and form fields const RegistrationSchema = object({ name: string().required('Name is required').minLength(2, 'Too short'), email: string().required('Email is required').matches(/^[^\\s@]+@[^\\s@]+\\. [^\\s@]+$/, 'Invalid email'), age: number().required('Age is required').min(18, 'Must be 18+'), address: object({ city: string().required('City is required'), zip: string().required('ZIP is required').minLength(5, 'Invalid ZIP') }) }); // Renderers — define once, reuse everywhere const renderers = { string: ({ value, onChange, onBlur, error, touched }) => ( onChange(e.target.value)} onBlur={onBlur} error={touched && !!error} helperText={touched ? error : undefined} fullWidth margin="normal" /> ), number: ({ value, onChange, onBlur, error, touched }) => ( onChange(Number(e.target.value))} onBlur={onBlur} error={touched && !!error} helperText={touched ? error : undefined} fullWidth margin="normal" /> ) }; // Form component — just declare which fields to show function RegistrationForm() { const form = useSchemaForm(RegistrationSchema); return (
t.name} form={form} /> t.email} form={form} /> t.age} form={form} /> t.address.city} form={form} /> t.address.zip} form={form} />
); } // App — wrap with provider function App() { return ( ); } ``` -------------------------------- ### Start Demo Application Source: https://github.com/cleverbrush/framework/blob/master/README.md Command to launch the demo application, which includes the backend, frontend, and local database stack for workflow testing. ```bash npm run dev:demo ``` -------------------------------- ### Install @cleverbrush/scheduler Source: https://github.com/cleverbrush/framework/blob/master/libs/scheduler/README.md Install the library using npm. This library requires Node.js v16+. ```bash npm install @cleverbrush/scheduler ``` -------------------------------- ### Attach Named Request Body Examples Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Use .examples() to provide multiple named examples with summaries and descriptions. ```ts const CreateUser = endpoint .post('/api/users') .body(UserSchema) .examples({ minimal: { summary: 'Minimal', value: { name: 'Alice' } }, full: { summary: 'Complete', description: 'A fully populated user', value: { name: 'Alice', email: 'alice@example.com', age: 30 } } }); ``` -------------------------------- ### Install Cleverbrush Schema Source: https://github.com/cleverbrush/framework/blob/master/libs/schema/README.md Install the Cleverbrush Schema library using npm. ```bash npm install @cleverbrush/schema ``` -------------------------------- ### Install @cleverbrush/react-form Source: https://github.com/cleverbrush/framework/blob/master/libs/react-form/README.md Command to install the @cleverbrush/react-form package using npm. ```bash npm install @cleverbrush/react-form ``` -------------------------------- ### Install @cleverbrush/knex-clickhouse Source: https://github.com/cleverbrush/framework/blob/master/libs/knex-clickhouse/README.md Install the package using npm. Ensure you have Knex version 3.1.0 or higher installed as a peer dependency. ```bash npm install @cleverbrush/knex-clickhouse ``` -------------------------------- ### Quick Start: Basic Dependency Injection Source: https://github.com/cleverbrush/framework/blob/master/libs/di/README.md Demonstrates defining service contracts with schemas, registering services with different lifetimes, building a service provider, and resolving dependencies. ```typescript import { ServiceCollection } from '@cleverbrush/di'; import { object, string, number, func } from '@cleverbrush/schema'; // 1. Define service contracts as schemas (used as keys) const IConfig = object({ port: number(), host: string() }); const ILogger = object({ info: func().addParameter(string()) }); // 2. Register services const services = new ServiceCollection(); services.addSingleton(IConfig, { port: 3000, host: 'localhost' }); services.addSingleton(ILogger, () => ({ info: (msg) => console.log(msg) })); // 3. Build the provider const provider = services.buildServiceProvider(); // 4. Resolve — fully typed, no explicit generics needed const config = provider.get(IConfig); config.port; // number ``` -------------------------------- ### Install @cleverbrush/orm-cli Source: https://github.com/cleverbrush/framework/blob/master/libs/orm-cli/README.md Install the ORM CLI as a development dependency in your project. ```bash npm install --save-dev @cleverbrush/orm-cli ``` -------------------------------- ### Clone and Install Dependencies Source: https://github.com/cleverbrush/framework/blob/master/CONTRIBUTING.md Clone the repository and install project dependencies using npm ci. ```bash git clone https://github.com/cleverbrush/framework.git cd framework npm ci ``` -------------------------------- ### Install Playwright Chromium Source: https://github.com/cleverbrush/framework/blob/master/demos/e2e/README.md Install the Chromium browser required for UI tests. Run this command after `npm install` from the `demos/e2e` directory. ```bash cd demos/e2e && npx playwright install chromium ``` -------------------------------- ### Attach Single Request Body Example Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Use .example() to pre-fill the Swagger UI Try it out panel for an endpoint. ```ts const CreateUser = endpoint .post('/api/users') .body(UserSchema) .example({ name: 'Alice', email: 'alice@example.com' }); ``` ```yaml requestBody: content: application/json: schema: { ... } example: { name: Alice, email: alice@example.com } ``` -------------------------------- ### Attaching Example Values to Schemas Source: https://github.com/cleverbrush/framework/blob/master/libs/schema/README.md Use `.example(value)` to attach example data to schemas. Examples are purely metadata and do not affect validation. They are useful for documentation generation. ```typescript import { string, number, object } from '@cleverbrush/schema'; const Email = string().example('user@example.com'); const Age = number().example(30); const User = object({ email: Email, age: Age, }).example({ email: 'alice@example.com', age: 25 }); ``` -------------------------------- ### Real-World Example: Order Mapping Source: https://github.com/cleverbrush/framework/blob/master/libs/mapper/README.md An example demonstrating how to map API response data to a domain model using the mapper and various mapping strategies. ```APIDOC ## Real-World Example A complete example mapping API responses through multiple layers: ```typescript import { object, string, number } from '@cleverbrush/schema'; import { mapper } from '@cleverbrush/mapper'; // API response shape const ApiOrderResponse = object({ order_id: string(), customer_name: string(), total_cents: number(), status_code: number() }); // Domain model const Order = object({ id: string(), customer: string(), totalPrice: string(), status: string() }); const registry = mapper().configure( ApiOrderResponse, Order, (m) => m .for((t) => t.id) .from((s) => s.order_id) .for((t) => t.customer) .from((s) => s.customer_name) .for((t) => t.totalPrice) .compute((s) => `$${(s.total_cents / 100).toFixed(2)}`) .for((t) => t.status) .compute((s) => { const statuses: Record = { 0: 'pending', 1: 'confirmed', 2: 'shipped', 3: 'delivered' }; return statuses[s.status_code] ?? 'unknown'; }) ); const mapOrder = registry.getMapper(ApiOrderResponse, Order); const order = await mapOrder({ order_id: 'ORD-123', customer_name: 'Alice Smith', total_cents: 4999, status_code: 2 }); // { id: 'ORD-123', customer: 'Alice Smith', totalPrice: '$49.99', status: 'shipped' } ``` ``` -------------------------------- ### Attach Schema-level Examples Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Examples attached to schemas propagate to all parameters and responses using that schema. ```ts const PageParam = number().example(1); const UserResponse = object({ id: number(), name: string() }).example({ id: 1, name: 'Alice' }); ``` -------------------------------- ### Accessing Example Metadata Source: https://github.com/cleverbrush/framework/blob/master/libs/schema/README.md Retrieve example values attached to a schema using `.introspect().example`. This metadata is consumed by tools like `@cleverbrush/schema-json` and `@cleverbrush/server-openapi`. ```typescript Email.introspect().example; // 'user@example.com' ``` -------------------------------- ### Install @cleverbrush/mapper Source: https://github.com/cleverbrush/framework/blob/master/libs/mapper/README.md Install the @cleverbrush/mapper package using npm. Ensure you also have @cleverbrush/schema as a peer dependency. ```bash npm install @cleverbrush/mapper ``` -------------------------------- ### Quick Start JWT Authentication Source: https://github.com/cleverbrush/framework/blob/master/libs/auth/README.md Demonstrates setting up JWT authentication with a custom claims mapping and authenticating a request context. ```typescript import { jwtScheme, Principal } from '@cleverbrush/auth'; type UserClaims = { sub: string; role: string }; const jwt = jwtScheme({ secret: process.env.JWT_SECRET!, mapClaims: claims => ({ sub: claims.sub as string, role: claims.role as string }) }); // Authenticate a request context (built from HTTP headers) const result = await jwt.authenticate({ headers: { authorization: 'Bearer ' }, cookies: {}, items: new Map() }); if (result.succeeded) { const principal: Principal = result.principal; principal.isAuthenticated; // true principal.hasRole('admin'); // boolean principal.value.sub; // string } ``` -------------------------------- ### Quick start OpenAPI generation Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Initialize a server and expose an OpenAPI specification endpoint using serveOpenApi middleware. ```typescript import { ServerBuilder, endpoint } from '@cleverbrush/server'; import { serveOpenApi } from '@cleverbrush/server-openapi'; import { object, string, number } from '@cleverbrush/schema'; const GetUser = endpoint .get('/api/users/:id') .summary('Get a user by ID') .tags('users'); const server = new ServerBuilder(); server .use(serveOpenApi({ server, info: { title: 'My API', version: '1.0.0' } })) .handle(GetUser, ({ params }) => ({ id: params.id })); await server.listen(3000); // GET /openapi.json → OpenAPI 3.1 document ``` -------------------------------- ### Complete API response to domain model mapping Source: https://github.com/cleverbrush/framework/blob/master/libs/mapper/README.md Full implementation example showing schema definition, registry configuration, and execution. ```typescript import { object, string, number } from '@cleverbrush/schema'; import { mapper } from '@cleverbrush/mapper'; // API response shape const ApiOrderResponse = object({ order_id: string(), customer_name: string(), total_cents: number(), status_code: number() }); // Domain model const Order = object({ id: string(), customer: string(), totalPrice: string(), status: string() }); const registry = mapper().configure( ApiOrderResponse, Order, (m) => m .for((t) => t.id) .from((s) => s.order_id) .for((t) => t.customer) .from((s) => s.customer_name) .for((t) => t.totalPrice) .compute((s) => `$${(s.total_cents / 100).toFixed(2)}`) .for((t) => t.status) .compute((s) => { const statuses: Record = { 0: 'pending', 1: 'confirmed', 2: 'shipped', 3: 'delivered' }; return statuses[s.status_code] ?? 'unknown'; }) ); const mapOrder = registry.getMapper(ApiOrderResponse, Order); const order = await mapOrder({ order_id: 'ORD-123', customer_name: 'Alice Smith', total_cents: 4999, status_code: 2 }); // { id: 'ORD-123', customer: 'Alice Smith', totalPrice: '$49.99', status: 'shipped' } ``` -------------------------------- ### Headless Usage Example Source: https://github.com/cleverbrush/framework/blob/master/libs/react-form/README.md Example demonstrating how to use the `useSchemaForm` hook directly for full control over rendering without the `Field` component. ```APIDOC ## Headless Usage (without Field component) For full control over rendering, use `form.useField()` directly: ```tsx function UserForm() { const form = useSchemaForm(UserSchema); const name = form.useField((t) => t.name); const email = form.useField((t) => t.email); return ( <> name.onChange(e.target.value)} onBlur={name.onBlur} /> {name.touched && name.error && {name.error}} email.onChange(e.target.value)} onBlur={email.onBlur} /> ); } ``` ``` -------------------------------- ### OpenAPI Specification Configuration Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Configuration examples for defining OpenAPI metadata and path parameters. ```APIDOC ## OpenAPI Configuration ### Description Defines how to register top-level tags and API information for OpenAPI spec generation. ### Request Example ```ts generateOpenApiSpec({ registrations, info: { title: 'My API', version: '1.0.0' }, tags: [ { name: 'users', description: 'User management endpoints', externalDocs: { url: 'https://docs.example.com/users' } } ] }); ``` ``` -------------------------------- ### Middleware Usage Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Example of configuring client with various middleware for enhanced request handling. ```APIDOC ## Client Configuration with Middlewares ### Description Middlewares wrap the `fetch` call, allowing interception, modification, or short-circuiting of requests and responses. They compose like an onion. ### Example ```javascript import { createClient } from '@cleverbrush/client'; import { retry } from '@cleverbrush/client/retry'; import { timeout } from '@cleverbrush/client/timeout'; import { dedupe } from '@cleverbrush/client/dedupe'; import { throttlingCache } from '@cleverbrush/client/cache'; const client = createClient(api, { baseUrl: 'https://api.example.com', middlewares: [ retry({ limit: 3 }), timeout({ timeout: 10000 }), dedupe(), throttlingCache({ throttle: 2000 }), ], }); ``` ``` -------------------------------- ### Install Chromium for Playwright Source: https://github.com/cleverbrush/framework/blob/master/demos/e2e/README.md Command to install the Chromium browser, necessary for Playwright to run headless browser tests. ```bash npx playwright install chromium ``` -------------------------------- ### Project Directory Structure Source: https://github.com/cleverbrush/framework/blob/master/demos/e2e/README.md Overview of the project's directory layout, including setup, support utilities, API tests, and UI tests. ```tree src/ setup/ global-setup.ts # docker compose orchestration + health waits support/ auth.ts # createUser(), authedRequest() clickhouse.ts # waitForRows(), pingClickhouse() db.ts # pg pool + getUserByEmail / getTodoById / promoteToAdmin env.ts # config object reading E2E_* vars http.ts # request() / streamRequest() / json() ids.ts # uniqueEmail(), uniqueTitle(), shortId() playwright.ts # withPage(fn) — isolated browser context per test ws.ts # connectWs(path, {token}) — WebSocket client wrapper api/ # Vitest project: parallel; ~46 tests, ~70 s *.api.test.ts # REST + import/export + admin + activity + telemetry *.ws.test.ts # WebSocket subscriptions ui/ # Vitest project: serial (singleFork); ~4 tests, ~25 s *.ui.test.ts # Playwright UI smoke flows ``` -------------------------------- ### Direct Fetch Example Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Demonstrates how to perform direct HTTP requests using the typed client. All parameters, bodies, and responses are fully type-safe. ```typescript // Direct fetch (both clients) const todos = await client.todos.list({ query: { page: 1, limit: 10 } }); // ^? TodoResponse[] const todo = await client.todos.get({ params: { id: 1 } }); // ^? TodoResponse const created = await client.todos.create({ body: { title: 'Buy milk' } }); // ^? TodoResponse await client.todos.delete({ params: { id: 1 } }); // ^? undefined (204 No Content) ``` -------------------------------- ### Custom Middleware Example Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Demonstrates how to create and use custom middleware to intercept and modify requests and responses. ```APIDOC ## Writing custom middleware ```ts import type { Middleware } from '@cleverbrush/client'; const logger: Middleware = (next) => async (url, init) => { console.log('→', init.method, url); const res = await next(url, init); console.log('←', res.status); return res; }; ``` ``` -------------------------------- ### Quick Start Logger Configuration Source: https://github.com/cleverbrush/framework/blob/master/libs/log/README.md Create a logger with console output, hostname, and process ID enrichment. Logs messages at 'information' level or higher. Ensure to dispose of the logger when done. ```typescript import { createLogger, consoleSink, hostnameEnricher, processIdEnricher, } from '@cleverbrush/log'; const logger = createLogger({ minimumLevel: 'information', sinks: [consoleSink({ theme: 'dark' })], enrichers: [hostnameEnricher(), processIdEnricher()], }); logger.info('Server started on port {Port}', { Port: 3000 }); logger.error(new Error('oops'), 'Request failed for {UserId}', { UserId: 42 }); await logger.dispose(); ``` -------------------------------- ### Resolving Services from the Provider Source: https://github.com/cleverbrush/framework/blob/master/libs/di/README.md Demonstrates how to retrieve registered services using `get()` and `getOptional()` from a built `ServiceProvider`. ```typescript const provider = services.buildServiceProvider(); // Throws if not registered const config = provider.get(IConfig); // Returns undefined if not registered (no throw) const mailer = provider.getOptional(IMailer); ``` -------------------------------- ### Register and Handle Endpoints Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Initialize a `ServerBuilder` and use the `.handle()` method to register endpoint handlers. Middleware can be applied per-endpoint using an options object. Start the server using `.listen()`. ```typescript const server = new ServerBuilder(); server.handle(CreateUser, ({ body, context }) => { return ActionResult.created({ id: 42, ...body }, `/api/users/42`); }); // Per-endpoint middleware server.handle(AdminEp, ({ params }) => { /* … */ }, { middlewares: [loggingMiddleware] }); await server.listen(3000); ``` -------------------------------- ### Defining HTTP Methods Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Use the `endpoint` singleton to start a builder chain for defining HTTP methods like GET, POST, PUT, and DELETE. ```APIDOC ## HTTP Methods Use the `endpoint` singleton to start a builder chain: ```ts import { endpoint } from '@cleverbrush/server'; const getUser = endpoint.get('/api/users/:id'); const postUser = endpoint.post('/api/users'); const putUser = endpoint.put('/api/users/:id'); const delUser = endpoint.delete('/api/users/:id'); ``` ``` -------------------------------- ### Define HTTP Method Endpoints Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Examples of defining endpoints for common HTTP methods (GET, POST, PUT, DELETE) using the `endpoint` singleton. ```typescript import { endpoint } from '@cleverbrush/server'; const getUser = endpoint.get('/api/users/:id'); const postUser = endpoint.post('/api/users'); const putUser = endpoint.put('/api/users/:id'); const delUser = endpoint.delete('/api/users/:id'); ``` -------------------------------- ### Client Initialization and Authentication Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Demonstrates how to create a client instance and how authentication tokens are automatically appended to WebSocket connections. ```APIDOC ## Client Initialization ### Description Initialize the client with your API endpoint and configuration, including a method to retrieve authentication tokens. ### Method `createClient(api, options)` ### Parameters - **api**: The API endpoint URL. - **options** (object) - Optional configuration object: - **baseUrl** (string) - The base URL for API requests. - **getToken** (function) - A function that returns the authentication token. ### Request Example ```ts const client = createClient(api, { baseUrl: 'https://api.example.com', getToken: () => localStorage.getItem('token'), }); ``` ### Authentication Auth tokens are sent as a `?token=` query parameter for WebSocket connections. ### Request Example ```ts // Token is automatically appended: // wss://api.example.com/ws/events?token= const sub = client.live.events(); ``` ``` -------------------------------- ### Registering and Handling Endpoints Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Demonstrates how to build a server instance and register handlers for specific endpoints, including per-endpoint middleware. ```APIDOC ## Registering and Handling Endpoints ```ts const server = new ServerBuilder(); server.handle(CreateUser, ({ body, context }) => { return ActionResult.created({ id: 42, ...body }, `/api/users/42`); }); // Per-endpoint middleware server.handle(AdminEp, ({ params }) => { /* ... */ }, { middlewares: [loggingMiddleware] }); await server.listen(3000); ``` ``` -------------------------------- ### Build All Libraries Source: https://github.com/cleverbrush/framework/blob/master/CLAUDE.md Build all publishable packages within the 'libs' directory, skipping website packages. ```bash npm run build ``` -------------------------------- ### Client Configuration Options Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Details the parameters available for `createClient`, including `baseUrl`, `getToken`, `onUnauthorized`, custom `fetch` implementation, default `headers`, `middlewares`, and `hooks`. ```markdown | Parameter | Type | Description | |-----------|------|-------------| | `contract` | `ApiContract` | Contract created with `defineApi()` | | `options.baseUrl` | `string` | Base URL prepended to every request (default: `''`) | | `options.getToken` | `() => string \| null` | Returns auth token for `Authorization: Bearer` header | | `options.onUnauthorized` | `() => void` | Called on 401 responses | | `options.fetch` | `typeof fetch` | Custom fetch implementation (default: `globalThis.fetch`) | | `options.headers` | `Record` | Extra headers sent with every request | | `options.middlewares` | `Middleware[]` | Middleware functions that wrap the fetch call | | `options.hooks` | `ClientHooks` | Lifecycle hooks invoked at various stages of a request | ``` -------------------------------- ### View Demo Backend Logs Source: https://github.com/cleverbrush/framework/blob/master/demos/e2e/README.md Command to view logs from the demo backend service, useful for troubleshooting startup issues. ```bash docker logs demos-backend-1 ``` -------------------------------- ### Build and Typecheck Docs Site Source: https://github.com/cleverbrush/framework/blob/master/AGENTS.md This command sequence builds all packages and performs typechecking specifically for the documentation website. ```bash npm run lint && npm run build npm run typecheck:docs-site ``` -------------------------------- ### Run Quality Gates (Lint, Build, Test) Source: https://github.com/cleverbrush/framework/blob/master/README.md Execute these commands to ensure code quality and that all tests pass before committing changes. Website changes may require specific site build commands. ```bash npm run lint npm run build npm run test ``` -------------------------------- ### Endpoint Authorization Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Examples of securing endpoints using `authorize()`. The first example protects against any authenticated user, while the second restricts access to users with the 'admin' role. ```typescript import { object, string } from '@cleverbrush/schema'; const UserPrincipal = object({ sub: string(), role: string() }); // Any authenticated user const ProtectedEp = endpoint.get('/api/profile').authorize(UserPrincipal); // Specific roles const AdminEp = endpoint.delete('/api/users/:id').authorize(UserPrincipal, 'admin'); ``` -------------------------------- ### Validate Object Schema and Get Per-Property Errors Source: https://github.com/cleverbrush/framework/blob/master/libs/schema/README.md Use `ObjectSchemaBuilder.validate()` with `doNotStopOnFirstError: true` to get detailed validation results, including errors for individual properties via `getErrorsFor()`. This is the recommended method for inline form error display. ```typescript const PersonSchema = object({ name: string().minLength(1), address: object({ city: string(), zip: number() }) }); const result = PersonSchema.validate(person, { doNotStopOnFirstError: true }); if (!result.valid) { // Get errors for a single property const nameErrors = result.getErrorsFor((p) => p.name); console.log(nameErrors.isValid); // false console.log(nameErrors.errors); // ['must be at least 1 character'] console.log(nameErrors.seenValue); // the value that was validated // Works with nested properties too const cityErrors = result.getErrorsFor((p) => p.address.city); console.log(cityErrors.errors); } ``` -------------------------------- ### Build and Test Project Source: https://github.com/cleverbrush/framework/blob/master/CONTRIBUTING.md Build all packages in the monorepo and run tests with typechecking. ```bash npm run build npm run test ``` -------------------------------- ### GET /asyncapi.json Source: https://github.com/cleverbrush/framework/blob/master/libs/server-openapi/README.md Exposes an AsyncAPI 3.0 document for WebSocket subscriptions via middleware. ```APIDOC ## GET /asyncapi.json ### Description Serves an automatically generated AsyncAPI 3.0 document based on WebSocket subscription registrations. ### Method GET ### Endpoint /asyncapi.json ### Response #### Success Response (200) - **body** (object) - The generated AsyncAPI 3.0 specification document. ``` -------------------------------- ### Bootstrap OpenTelemetry SDK Source: https://github.com/cleverbrush/framework/blob/master/libs/otel/README.md Initialize the OpenTelemetry SDK with your service details and desired instrumentations. This must be run before any other code that relies on telemetry. ```typescript // telemetry.ts — load FIRST import { setupOtel } from '@cleverbrush/otel'; import { outboundHttpInstrumentations, runtimeMetrics } from '@cleverbrush/otel/instrumentations'; export const otel = setupOtel({ serviceName: 'todo-backend', serviceVersion: '1.0.0', environment: process.env.NODE_ENV, otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT, instrumentations: [ ...outboundHttpInstrumentations(), ...runtimeMetrics() ] }); ``` -------------------------------- ### Cache Tags Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Defines how to use cache tags for invalidation on GET endpoints and how mutations can clear these tags. ```APIDOC ## Cache Tags Tag-based cache invalidation. Tags declared on endpoints flow to the [`cacheTags` middleware](/client/cache-tags) for automatic HTTP caching and invalidation on mutating requests. ### Declaring Cache Tags - **`.cacheTag(name)`**: Declares the endpoint's data belongs to a cache group. Use on GET endpoints. - **`.clearsCacheTag(name)`**: Declares that this mutation clears matching cache entries on success. Use on POST / PUT / PATCH / DELETE. - **`.cacheTag(name, p => ({ ... }))`**: Property-based tag; each selected property becomes part of the cache key (different pages → different entries). - **Immutability**: Both methods return a new builder; the original is unchanged. ```ts const ListTodos = endpoint .get('/api/todos') .query(TodoListQuerySchema) .cacheTag('todo-list', p => ({ page: p.query.page, limit: p.query.limit })) .returns(array(TodoSchema)); const UpdateTodo = endpoint .patch('/api/todos/:id') .body(UpdateTodoBody) .clearsCacheTag('todo-list') // clears the collection cache .clearsCacheTag('todo', p => ({ id: p.params.id })) // clears specific entity .returns(TodoSchema); ``` ``` -------------------------------- ### Build and Typecheck Schema Site Source: https://github.com/cleverbrush/framework/blob/master/AGENTS.md This command sequence builds all packages and performs typechecking specifically for the schema website. ```bash npm run lint && npm run build npm run typecheck:schema-site ``` -------------------------------- ### Validate Any Promise with `promise()` Source: https://github.com/cleverbrush/framework/blob/master/libs/schema/README.md Use `promise()` to validate that a value is a JavaScript Promise. This example shows untyped validation. ```typescript import { promise, string, number, InferType } from '@cleverbrush/schema'; // Untyped — validates that the value is any Promise const anyPromise = promise(); anyPromise.validate(Promise.resolve(42)); // { valid: true } anyPromise.validate('not a promise' as any); // { valid: false } ``` -------------------------------- ### Retrieve and execute a mapper function Source: https://github.com/cleverbrush/framework/blob/master/libs/mapper/README.md Use the registry to get a registered mapping function and apply it to a source object. ```typescript const mapFn = registry.getMapper(ApiUser, DomainUser); const result = await mapFn(sourceObject); ``` -------------------------------- ### Dependency Injection Source: https://github.com/cleverbrush/framework/blob/master/libs/server/README.md Illustrates how to use dependency injection to provide services, like repositories, to endpoint handlers. ```APIDOC ## Dependency Injection ```ts import { ServiceCollection } from '@cleverbrush/di'; import { object, func, string } from '@cleverbrush/schema'; const IUserRepo = object({ findById: func() }); const GetUser = endpoint .get('/api/users/:id') .inject({ repo: IUserRepo }); server .services(svc => svc.addSingleton(IUserRepo, () => new UserRepository())) .handle(GetUser, ({ params }, { repo }) => { return repo.findById(params.id); }); ``` ``` -------------------------------- ### toJsonSchema Function Source: https://github.com/cleverbrush/framework/blob/master/libs/schema-json/README.md Converts a `@cleverbrush/schema` builder to a JSON Schema object. It handles descriptions, examples, and discriminated unions automatically. ```APIDOC ## toJsonSchema(schema, opts?) ### Description Converts a `@cleverbrush/schema` builder to a JSON Schema object. ### Signature ```ts function toJsonSchema( schema: SchemaBuilder, opts?: ToJsonSchemaOptions, ): Record ``` ### Parameters #### Parameters - **schema** (SchemaBuilder) - Required - any builder from `@cleverbrush/schema` - **opts** (ToJsonSchemaOptions) - Optional - optional output configuration ### Returns A plain JavaScript object that is safe to `JSON.stringify`. ### Features - Descriptions set via `.describe(text)` are emitted as the `description` field. - Examples set via `.example(value)` are emitted as the `examples` array. #### Discriminated unions When a `union()` is a discriminated union (all branches are objects sharing a required property with unique literal values), `toJsonSchema()` automatically emits the `discriminator` keyword alongside `anyOf`. When a `nameResolver` is provided and union branches resolve to `$ref` pointers, a `mapping` is also emitted, enabling code-generation tools to produce proper tagged union types. #### `ToJsonSchemaOptions` | Option | Type | Default | Description | | --- | --- | --- | --- | | `draft` | `'2020-12' | '07'` | `'2020-12'` | JSON Schema draft version for the `$schema` URI | | `$schema` | `boolean` | `true` | Whether to include the `$schema` header in the output | | `nameResolver` | `(schema: SchemaBuilder) => string | null` | `undefined` | Called for every node before conversion. Return a non-null string to emit `{ $ref: '#/components/schemas/' }` instead of an inline schema. | ### Examples ```ts // Embed in OpenAPI (suppress the $schema header) t অনুমোদিত(schema, { $schema: false }); // Use Draft 07 t অনুমোদিত(schema, { draft: '07' }); ``` ``` -------------------------------- ### Embed Schema in OpenAPI Source: https://github.com/cleverbrush/framework/blob/master/libs/schema-json/README.md Example of using `toJsonSchema` to embed a schema within an OpenAPI specification by suppressing the `$schema` header. ```typescript toJsonSchema(schema, { $schema: false }); ``` -------------------------------- ### Run Node.js with Telemetry Import Source: https://github.com/cleverbrush/framework/blob/master/libs/otel/README.md Execute your Node.js application, ensuring the telemetry initialization script is imported first. ```bash node --import ./dist/telemetry.js dist/index.js ``` -------------------------------- ### JobScheduler Events Source: https://github.com/cleverbrush/framework/blob/master/libs/scheduler/README.md Emits events related to job execution lifecycle, including start, end, errors, timeouts, and messages. ```APIDOC ## JobScheduler Events ### `job:start` Emitted when a job begins execution. ```typescript scheduler.on('job:start', ({ jobId, instanceId, startDate }) => { ... }); ``` ### `job:end` Emitted when a job completes successfully. ```typescript scheduler.on('job:end', ({ jobId, instanceId, startDate, endDate, stdout, stderr }) => { ... }); ``` ### `job:error` Emitted when a job encounters an error during execution. ```typescript scheduler.on('job:error', ({ jobId, instanceId, startDate, endDate, stdout, stderr }) => { ... }); ``` ### `job:timeout` Emitted when a job exceeds its specified timeout. ```typescript scheduler.on('job:timeout', ({ jobId, instanceId, startDate, endDate }) => { ... }); ``` ### `job:message` Emitted when a job sends a message to the scheduler. ```typescript scheduler.on('job:message', ({ jobId, instanceId, message }) => { ... }); ``` #### Event Payload Properties: - `jobId` (string): The ID of the job. - `instanceId` (string): A unique identifier for this specific job run. - `startDate` (Date): The timestamp when the job started. - `endDate` (Date): The timestamp when the job ended. - `stdout` (string): The standard output from the job execution. - `stderr` (string): The standard error output from the job execution. - `message` (any): The message payload sent from the job. ``` -------------------------------- ### Use JSON Schema Draft 07 Source: https://github.com/cleverbrush/framework/blob/master/libs/schema-json/README.md Example of configuring `toJsonSchema` to output JSON Schema using the Draft 07 specification. ```typescript toJsonSchema(schema, { draft: '07' }); ``` -------------------------------- ### Queries with Parameters Source: https://github.com/cleverbrush/framework/blob/master/libs/client/README.md Demonstrates how to fetch data for a specific resource using query parameters, such as an item's ID. ```APIDOC ## Queries with Parameters ```tsx function TodoDetail({ id }: { id: number }) { const { data } = client.todos.get.useQuery({ params: { id } }); return

{data?.title}

; } ``` ``` -------------------------------- ### Convert SchemaBuilder to JSON Schema Source: https://github.com/cleverbrush/framework/blob/master/libs/schema-json/README.md Converts a schema builder instance into a JSON Schema object. Descriptions and examples from the builder are preserved. ```typescript function toJsonSchema( schema: SchemaBuilder, opts?: ToJsonSchemaOptions, ): Record ``` -------------------------------- ### Initialize Knex with ClickhouseKnexClient Source: https://github.com/cleverbrush/framework/blob/master/libs/knex-clickhouse/README.md Directly use ClickhouseKnexClient with Knex for more control over initialization. Requires importing Knex and ClickhouseKnexClient. ```typescript import Knex from 'knex'; import { ClickhouseKnexClient } from '@cleverbrush/knex-clickhouse'; const db = Knex({ client: ClickhouseKnexClient, connection: { url: 'http://localhost:8123', user: 'default', password: '', database: 'my_database' } }); ``` -------------------------------- ### Snapshot Documentation Source: https://github.com/cleverbrush/framework/blob/master/DOCS_PIPELINE.md Commands to snapshot the current documentation for a specific release version. ```bash npm run docs # regenerate latest npm run docs:snapshot # copies latest/ → v{version}/, updates picker git add website/public/api-docs/ git commit -m "docs: snapshot v1.2.0 API reference" ``` -------------------------------- ### query(knex, schema, baseQuery?) Source: https://github.com/cleverbrush/framework/blob/master/libs/knex-schema/README.md Creates a `SchemaQueryBuilder`. `schema` must have `.hasTableName()` set. Optionally pass a `baseQuery` as the starting point. ```APIDOC ## `query(knex, schema, baseQuery?)` Creates a `SchemaQueryBuilder`. `schema` must have `.hasTableName()` set. Optionally pass a `baseQuery` (e.g. a scoped `knex('users').where('deleted_at', null)`) as the starting point. ``` -------------------------------- ### Run UI End-to-End Tests Source: https://github.com/cleverbrush/framework/blob/master/demos/e2e/README.md Execute only the UI project's end-to-end tests. This requires Chromium to be installed. This command is run from the repository root. ```bash npm run test:e2e:ui ```