Releases: cleverbrush/framework
@cleverbrush/server@4.0.0
Major Changes
-
9235c76: Add contract composition utilities —
mergeContracts,pickGroups, andomitGroups.@cleverbrush/server— contract compositionThree new functions exported from both
@cleverbrush/serverand
@cleverbrush/server/contractmake it straightforward to define
audience-scoped API bundles.mergeContracts<A, B>(a, b)Combines two
ApiContractobjects into one frozen contract. Groups that
only exist in one source are passed through unchanged; groups whose key
appears in both have their endpoint maps shallowly merged. The TypeScript
return type isMergedContracts<A, B>— a precise mapped type that reflects
the combined shape.const publicApi = defineApi({ todos: {...}, auth: {...} }); const adminApi = defineApi({ admin: { activityLog: ... } }); const fullApi = mergeContracts(publicApi, adminApi); // TypeScript: { todos, auth, admin }
pickGroups<T, K>(contract, ...groups)Returns a new frozen contract containing only the listed groups. The return
type isPick<T, K>— the compiler sees exactly those groups and nothing
else.const clientApi = pickGroups(fullApi, "todos", "auth"); // TypeScript: { todos, auth } // 'admin' is absent at both the type level and runtime
omitGroups<T, K>(contract, ...groups)Inverse of
pickGroups— strips the listed groups and keeps everything else.
Return type isOmit<T, K>.const publicApi = omitGroups(fullApi, "admin", "debug"); // TypeScript: { todos, auth }
Bundle isolation pattern
Define separate entry-point files that export different contract slices:
shared-contracts/src/public.ts → export const publicApi = defineApi({ ... }) shared-contracts/src/full.ts → export const fullApi = mergeContracts(publicApi, adminApi)Client apps import
publicApi; admin apps importfullApi. Admin schemas
are never included in the client bundle.
Patch Changes
@cleverbrush/server-openapi@4.0.0
@cleverbrush/schema@4.0.0
Patch Changes
-
3bfc1e1: Add named projections to
@cleverbrush/knex-schema.@cleverbrush/knex-schema— new featureObjectSchemaBuilder.projection(name, columns)— define a named column subset on the schema.
Two forms are supported:- String-tuple form:
.projection('summary', ['id', 'title'] as const)— the column list
is areadonly string[]const that TypeScript uses to narrow the query result type. - Accessor form:
.projection('detail', t => [t.id, t.title])— refactor-safe accessor that
resolves property names at runtime via the schema's property-descriptor tree.
- String-tuple form:
SchemaQueryBuilder.projected(name)— apply a named projection at query time.- Restricts the
SELECTclause to the registered columns (respectinghasColumnName()mappings). - Narrows the TypeScript result type to
Pick<Row, Keys>for tuple-form projections. - Registered projection names are constrained at the type level — unregistered names are a
compile-time error. - Throws at runtime if combined with
.select(),.distinct(), or any aggregate method
(.count(),.min(), etc.) on the same query.
- Restricts the
- Calling
.projection()with a name that is already registered on the schema throws immediately.
@cleverbrush/schema— internal extensionPROJECTION_BRANDunique symbol exported from the core extension system.FixedMethodsupdated with a 4thTProjectionstype parameter that accumulates the
name → keys map as.projection()calls are chained, enablingSchemaQueryBuilderto
extract the column list at the type level.PropertyDescriptor/PropertyDescriptorInnernow accept an optional 4th type parameter
TPropertyKey extends string = stringthat carries the property key literal so accessor-form
descriptors can propagate their key name through the type system.
-
cbdfa69: Add
@cleverbrush/otel— OpenTelemetry instrumentation for the framework.@cleverbrush/otel(new library)End-to-end OpenTelemetry support for
@cleverbrush/server,@cleverbrush/orm,
and@cleverbrush/log. Ships traces, logs, and runtime metrics over OTLP/HTTP
to any compatible backend (ClickStack, Grafana Tempo, Jaeger, …).setupOtel(config)— bootstraps the Node SDK (traces + logs + metrics)
with sensible defaults and a singleshutdown()hook for graceful exit.tracingMiddleware()—@cleverbrush/servermiddleware that opens a
SpanKind.SERVERspan per request, names it from the endpoint metadata
(operationIdorMETHOD route), tags it with HTTP semantic-convention
attributes, and extracts inbound W3Ctraceparentheaders.instrumentKnex(knex)— wires Knexquery/query-response/
query-errorevents intoSpanKind.CLIENTspans withdb.system.name,
db.namespace,db.operation.name, anddb.query.text. Spans are
automatically parented under the active request span.otelLogSink()—@cleverbrush/logsink that emits OTLP log records
with severity, body, structured attributes, and exception info.traceEnricher()— log enricher that attachesTraceId/SpanId/
TraceFlagsto every event when a span is active.configureOtel(services)— registersITracerandIMeterin
@cleverbrush/di.outboundHttpInstrumentations()/runtimeMetrics()— opt-in
lazy loaders for HTTP / undici / Node runtime metrics auto-instrumentation
(declared as optional peer dependencies).
The
todo-backenddemo is fully wired and ships traces / logs / metrics to
a ClickStack container included indemos/docker-compose.yml.@cleverbrush/logTypedTemplate.template— new optional property on theTypedTemplate<T>
interface. When present, theLoggeruses it as the raw{Property}pattern
string formessageTemplate, so log events with the same shape are grouped
correctly in Seq, ClickStack, and other structured-log UIs.ParseStringSchemaBuilder
now implements this property automatically.correlationIdMiddleware/useLogging—responseHeader(and the new
UseLoggingOptions.correlationResponseHeader) now acceptfalseto suppress
theX-Correlation-Idresponse header entirely. Useful when OTel's
traceparent/traceresponseheader already provides traceability and a
second correlation header would be redundant.traceEnricherremoved — theglobalThis.opentelemetry-based enricher
that was included in earlier builds has been removed. UsetraceEnricher
from@cleverbrush/otelinstead — it reads the active span via
@opentelemetry/apidirectly and also capturesTraceFlags.
@cleverbrush/schemaParseStringSchemaBuilder.template— new read-only getter that returns
the human-readable{Property}pattern string (e.g.
"Todo created: #{TodoId} \"{Title}\" by user {UserId}"). This satisfies the
TypedTemplate.templatecontract, so schema-parsed log templates are
automatically grouped by shape in structured-log UIs.
@cleverbrush/schema-json@4.0.0
@cleverbrush/scheduler@4.0.0
@cleverbrush/react-form@4.0.0
@cleverbrush/otel@4.0.0
Major Changes
-
cbdfa69: Add
@cleverbrush/otel— OpenTelemetry instrumentation for the framework.@cleverbrush/otel(new library)End-to-end OpenTelemetry support for
@cleverbrush/server,@cleverbrush/orm,
and@cleverbrush/log. Ships traces, logs, and runtime metrics over OTLP/HTTP
to any compatible backend (ClickStack, Grafana Tempo, Jaeger, …).setupOtel(config)— bootstraps the Node SDK (traces + logs + metrics)
with sensible defaults and a singleshutdown()hook for graceful exit.tracingMiddleware()—@cleverbrush/servermiddleware that opens a
SpanKind.SERVERspan per request, names it from the endpoint metadata
(operationIdorMETHOD route), tags it with HTTP semantic-convention
attributes, and extracts inbound W3Ctraceparentheaders.instrumentKnex(knex)— wires Knexquery/query-response/
query-errorevents intoSpanKind.CLIENTspans withdb.system.name,
db.namespace,db.operation.name, anddb.query.text. Spans are
automatically parented under the active request span.otelLogSink()—@cleverbrush/logsink that emits OTLP log records
with severity, body, structured attributes, and exception info.traceEnricher()— log enricher that attachesTraceId/SpanId/
TraceFlagsto every event when a span is active.configureOtel(services)— registersITracerandIMeterin
@cleverbrush/di.outboundHttpInstrumentations()/runtimeMetrics()— opt-in
lazy loaders for HTTP / undici / Node runtime metrics auto-instrumentation
(declared as optional peer dependencies).
The
todo-backenddemo is fully wired and ships traces / logs / metrics to
a ClickStack container included indemos/docker-compose.yml.@cleverbrush/logTypedTemplate.template— new optional property on theTypedTemplate<T>
interface. When present, theLoggeruses it as the raw{Property}pattern
string formessageTemplate, so log events with the same shape are grouped
correctly in Seq, ClickStack, and other structured-log UIs.ParseStringSchemaBuilder
now implements this property automatically.correlationIdMiddleware/useLogging—responseHeader(and the new
UseLoggingOptions.correlationResponseHeader) now acceptfalseto suppress
theX-Correlation-Idresponse header entirely. Useful when OTel's
traceparent/traceresponseheader already provides traceability and a
second correlation header would be redundant.traceEnricherremoved — theglobalThis.opentelemetry-based enricher
that was included in earlier builds has been removed. UsetraceEnricher
from@cleverbrush/otelinstead — it reads the active span via
@opentelemetry/apidirectly and also capturesTraceFlags.
@cleverbrush/schemaParseStringSchemaBuilder.template— new read-only getter that returns
the human-readable{Property}pattern string (e.g.
"Todo created: #{TodoId} \"{Title}\" by user {UserId}"). This satisfies the
TypedTemplate.templatecontract, so schema-parsed log templates are
automatically grouped by shape in structured-log UIs.
Patch Changes
@cleverbrush/orm@1.0.0
Major Changes
-
6e66e9a: Add
@cleverbrush/orm— EF-Core-like typed ORM — and@cleverbrush/orm-climigration tooling.@cleverbrush/orm(new library)A typed ORM layer built on top of
@cleverbrush/knex-schemathat provides:-
createDb(knex, entityMap, opts?)— creates aDbContextwith typedDbSet<TEntity>
properties for each entry in the entity map. Pass{ tracking: true }to get a
TrackedDbContextwith an identity map and change tracker. -
defineEntity(schema)— wraps a@cleverbrush/knex-schemaschema and enables
fluent relation and variant declarations:.hasOne(sel, EntityDef, fkKey)/.hasMany(sel, EntityDef, fkKey)— child relations.belongsTo(sel, fkKey)— parent relation.belongsToMany(sel, EntityDef, opts)— many-to-many via pivot table.discriminator(key)— marks the entity as polymorphic.stiVariant(key, schema)— Single-Table Inheritance variant (shared table).ctiVariant(key, EntityDef, fkSel, opts?)— Class-Table Inheritance variant (separate table)
-
DbSet<TEntity>— typed query starter with:.find(pk)/.findOrFail(pk)/.findMany([pk…])— PK-based lookups.save(graph)— transactional graph persistence with FK propagation.ofVariant(key)— return a typedVariantDbSetscoped to a polymorphic variant
(analogous to EF Core'sSet<DerivedType>())- All
SchemaQueryBuildermethods (.where(),.include(),.execute(), etc.)
-
VariantDbSet<TEntity, K>— typed handle for a single polymorphic variant:.insert(payload)— insert with discriminator set automatically (STI/CTI aware).update(patch)/.delete()— scoped writes for rows matched by.where().find(pk)/.findOrFail(pk)/.findMany([pk…])— variant-typed lookups.where()/.include()/.withTransaction()— full chain support- Calling
.insert()/.update()/.delete()on the base polymorphicDbSet
throws a runtime error; use.ofVariant(key)instead
-
TrackedDbContextadditions:- Identity map — same PK always returns the same object reference
- Automatic change detection — mutate entities normally; flush with
saveChanges() .attach(key, entity)/.detach(entity)/.entry(entity)— manual tracker control.remove(entity)— mark entity for deletion.saveChanges()— flush allAdded / Modified / Deletedentries in one transaction.discardChanges()— roll back all in-memory changes.reload(entity)— re-fetch from DB and refresh snapshot.onSavingChanges(hook)— pre-flush callback for audit fields, etc.[Symbol.asyncDispose]()—await usingsupport; throwsPendingChangesErroron unsaved changes.rowVersion()column support — auto-increments on UPDATE, throwsConcurrencyErroron conflict
-
Error classes:
EntityNotFoundError,ConcurrencyError,InvariantViolationError,
PendingChangesError
@cleverbrush/orm-cli(new library)CLI tool for managing PostgreSQL schema migrations from entity definitions:
cb-orm migrate generate [name]— diff entity schemas vs live DB, emit typed TS migration filecb-orm migrate run [--to <file>]— apply pending migrations viaknex.migrate.latestcb-orm migrate rollback [--all]— roll back last (or all) migration batch(es)cb-orm migrate status— list applied and pending migration filescb-orm db push [--yes]— apply schema diff in-place without a migration file (dev only)
Config is loaded from
db.config.tsin the working directory viadefineConfig({ knex, entities, migrations }).@cleverbrush/knex-schema(extensions for ORM)New schema extension points consumed by
@cleverbrush/orm:- Entity & relation extensions —
defineEntity,Entity,POLYMORPHIC_TYPE_BRAND,
getVariants,getPolymorphicVariantSchemasand the full relation-registration API
(RelationInfo,EntityRelations,EntityPropSelector, etc.) - Migration support —
tableExistsInDb,introspectDatabase,diffSchema,
generateCreateTableSource,generateMigration,applyDiff - DDL helpers —
buildColumnMap,getPrimaryKeyColumns,extractPkValues,buildPkKey - Snapshot utilities —
snapshotEntityfor change-tracker baseline capture rowVersion()column extension onNumberSchemaBuilder
-
Patch Changes
@cleverbrush/orm-cli@1.0.0
Major Changes
-
6e66e9a: Add
@cleverbrush/orm— EF-Core-like typed ORM — and@cleverbrush/orm-climigration tooling.@cleverbrush/orm(new library)A typed ORM layer built on top of
@cleverbrush/knex-schemathat provides:-
createDb(knex, entityMap, opts?)— creates aDbContextwith typedDbSet<TEntity>
properties for each entry in the entity map. Pass{ tracking: true }to get a
TrackedDbContextwith an identity map and change tracker. -
defineEntity(schema)— wraps a@cleverbrush/knex-schemaschema and enables
fluent relation and variant declarations:.hasOne(sel, EntityDef, fkKey)/.hasMany(sel, EntityDef, fkKey)— child relations.belongsTo(sel, fkKey)— parent relation.belongsToMany(sel, EntityDef, opts)— many-to-many via pivot table.discriminator(key)— marks the entity as polymorphic.stiVariant(key, schema)— Single-Table Inheritance variant (shared table).ctiVariant(key, EntityDef, fkSel, opts?)— Class-Table Inheritance variant (separate table)
-
DbSet<TEntity>— typed query starter with:.find(pk)/.findOrFail(pk)/.findMany([pk…])— PK-based lookups.save(graph)— transactional graph persistence with FK propagation.ofVariant(key)— return a typedVariantDbSetscoped to a polymorphic variant
(analogous to EF Core'sSet<DerivedType>())- All
SchemaQueryBuildermethods (.where(),.include(),.execute(), etc.)
-
VariantDbSet<TEntity, K>— typed handle for a single polymorphic variant:.insert(payload)— insert with discriminator set automatically (STI/CTI aware).update(patch)/.delete()— scoped writes for rows matched by.where().find(pk)/.findOrFail(pk)/.findMany([pk…])— variant-typed lookups.where()/.include()/.withTransaction()— full chain support- Calling
.insert()/.update()/.delete()on the base polymorphicDbSet
throws a runtime error; use.ofVariant(key)instead
-
TrackedDbContextadditions:- Identity map — same PK always returns the same object reference
- Automatic change detection — mutate entities normally; flush with
saveChanges() .attach(key, entity)/.detach(entity)/.entry(entity)— manual tracker control.remove(entity)— mark entity for deletion.saveChanges()— flush allAdded / Modified / Deletedentries in one transaction.discardChanges()— roll back all in-memory changes.reload(entity)— re-fetch from DB and refresh snapshot.onSavingChanges(hook)— pre-flush callback for audit fields, etc.[Symbol.asyncDispose]()—await usingsupport; throwsPendingChangesErroron unsaved changes.rowVersion()column support — auto-increments on UPDATE, throwsConcurrencyErroron conflict
-
Error classes:
EntityNotFoundError,ConcurrencyError,InvariantViolationError,
PendingChangesError
@cleverbrush/orm-cli(new library)CLI tool for managing PostgreSQL schema migrations from entity definitions:
cb-orm migrate generate [name]— diff entity schemas vs live DB, emit typed TS migration filecb-orm migrate run [--to <file>]— apply pending migrations viaknex.migrate.latestcb-orm migrate rollback [--all]— roll back last (or all) migration batch(es)cb-orm migrate status— list applied and pending migration filescb-orm db push [--yes]— apply schema diff in-place without a migration file (dev only)
Config is loaded from
db.config.tsin the working directory viadefineConfig({ knex, entities, migrations }).@cleverbrush/knex-schema(extensions for ORM)New schema extension points consumed by
@cleverbrush/orm:- Entity & relation extensions —
defineEntity,Entity,POLYMORPHIC_TYPE_BRAND,
getVariants,getPolymorphicVariantSchemasand the full relation-registration API
(RelationInfo,EntityRelations,EntityPropSelector, etc.) - Migration support —
tableExistsInDb,introspectDatabase,diffSchema,
generateCreateTableSource,generateMigration,applyDiff - DDL helpers —
buildColumnMap,getPrimaryKeyColumns,extractPkValues,buildPkKey - Snapshot utilities —
snapshotEntityfor change-tracker baseline capture rowVersion()column extension onNumberSchemaBuilder
-