Naalya Handbook

How Chowbea works

Two generators sharing one CLI — OpenAPI for REST, the type bus for everything Swagger cannot carry.

The Education Hub never hand-writes API types. Chowbea (chowbea-axios on npm) is the CLI that keeps the Hub honest against the API. It has two pipes, and mixing them up is the usual first mistake.

Which pipe

You are sharing…Pipe
CreateDepartmentDto / GET /departmentsOpenAPI → api.op / api.contracts
RealtimeEventMap, InvalidationActionType bus → _generated/bus
Action / Resource / UserTypeType bus (the enums themselves). REST DTOs may still mention the string unions — the Hub prefers the bus enum as the runtime object
A Nest class, a function, a constNeither. Share logic with a real package, or expose a type/interface/enum instead

If you find yourself adding a dummy REST route so the Hub can import a type, you wanted the bus.

Two sources of truth, both generated

REST types come from the OpenAPI spec. Bus types come from TypeScript in the API repo. Neither is maintained by hand on the Hub. If a Hub type is wrong, fix the API (the DTO or the .chowbea.ts barrel), then regenerate. Never edit _generated/.

The REST pipe

The API serves a Swagger document (the OpenAPI description of every route) at /docs/swagger/json. Chowbea reads it and writes _generated/api.types.ts, api.operations.ts, and api.contracts.ts.

You call api.op.listCampuses(). Auth headers are interceptors; errors come back as a Result. The Hub-side detail lives in The Generated Client.

Use this pipe when the type appears on an HTTP request or response — a DTO with @ApiProperty, an operationId, a path. If you can hit it with curl, it belongs in Swagger.

The type bus

Some types never appear on a REST body:

  • Websocket payloads (RealtimeEventMap)
  • Domain enums the Hub needs as runtime values (Action, Resource, UserType, InvalidationAction)
  • Maps, generics, and unions you would otherwise fake as a DTO just to smuggle them through OpenAPI

Those live in *.chowbea.ts barrels on the API, get extracted into chowbea.bus.json, and are served at /.well-known/chowbea.json. The Hub's [bus] block fetches that manifest and writes _generated/bus/.

Use this pipe when putting the type in Swagger would be a lie — @ApiExtraModels for a websocket event, or duplicating enum Action as a DTO property just so codegen emits a const.

Hub config

Education Hub api.config.toml
api_endpoint = "http://localhost:8000/docs/swagger/json"

[output]
folder = "src/services/api"

[bus]
endpoint = "http://localhost:8000/.well-known/chowbea.json"

No [bus] block means the type bus is fully inert — REST codegen still runs, bus files are not updated. Both endpoints must be up when you watch.

Doing the work

On this page