Appearance
Contributing
Thanks for your interest in Znight! Issues, discussions and pull requests are welcome on GitHub.
Setup
The repository is a Bun workspace. You need Bun 1.4 (the version pinned in package.json#packageManager) and Node.js 24+ (.nvmrc). Applications built with Znight only need Bun 1.3+ or Node.js 24+.
sh
git clone https://github.com/znight-org/znight.git
cd znight
bun install| Command | What it does |
|---|---|
bun run test | Tests of the packages, the docs and the repository (tests/), packages used from source |
bun run test:coverage | The same with coverage |
bun run test:examples | The test script of every example application |
bun run test:e2e | Builds the packages, then the examples with ZNIGHT_E2E=1, the golden test of the examples and the CLI end-to-end test |
bun run test:integration | Messaging drivers against real brokers (ZNIGHT_INTEGRATION=1, Docker and Testcontainers) |
bun run typecheck | tsc --noEmit for every workspace (sources and tests) and tests/ |
bun run check | Biome lint + format check |
bun run check:fix | Biome with fixes |
bun run build | Build every package with tsdown |
bun run docs:dev | Documentation site in development mode |
bun run docs:build | Build the documentation site (fails on dead links) |
Run an example
The example applications (examples/*) use the znight CLI and the production build, which load the packages' dist. Build the framework once, then run an example in development mode:
sh
bun install
bun run build
cd examples/rest-api
bun run devdev rebuilds and restarts the application on every change. The examples that need development settings (credentials, sample data) read them from their .env.development. Every example README lists its endpoints with curl commands; Examples describes each one. If znight reports that dist/cli.mjs is missing, run bun run build again from the repository root.
Repository layout
txt
znight/
├─ packages/
│ ├─ core/ # runtime: container, application, plugins, hooks, AOP, scopes, decorators, errors
│ ├─ compiler/ # Vite plugin, programmatic API, Bun preload: analysis, binding, validation, codegen
│ ├─ http/ # decorators, compiler extension, HttpPlugin, adapters (node, fastify, express, hono)
│ ├─ openapi/ # decorators, compiler extension, OpenApiPlugin (Scalar, Swagger UI), build-time emit
│ ├─ messaging/ # decorators, compiler extension, MessagingPlugin, drivers
│ ├─ schedule/ # decorators, compiler extension, SchedulePlugin, distributed locks
│ ├─ config/ # decorators, compiler extension, ConfigPlugin, loaders
│ ├─ observability/ # logger (pino), metrics (prom-client), tracing (OpenTelemetry)
│ ├─ testing/ # TestBed, TestApp, mock helpers
│ └─ cli/ # the znight binary
├─ examples/ # runnable applications with their tests: rest-api, secure-api, storefront-api,
│ # uptime-monitor, microservice, worker, monorepo
├─ benchmarks/ # performance benchmarks, run by hand (not in CI): one application per
│ # framework, the runner, the results of the benchmarks page
├─ rfcs/ # design documents of significant features, with their status
├─ tests/ # repository-wide tests: package boundaries, golden test of the examples
├─ scripts/ # generators of the brand assets and of the documentation diagrams
└─ docs/ # this site (VitePress); docs/internals holds the architecture specificationRFCs
Significant features (a new package, a new cross-package contract) start as an RFC in rfcs/, discussed before any implementation. Its README lists every RFC with its status and allocates the error code ranges of the packages. The roadmap summarises where each one stands.
The specification comes first
docs/internals/architecture.md is the normative contract between packages: the compiler generates code that runtime packages consume, so both sides must follow it. When an implementation needs to deviate, update the specification in the same change.
Conventions
- Source condition. Each package exposes a
@znight/sourceexport condition pointing to its TypeScript sources; repository scripts run with--conditions=@znight/source, so nothing needs to be built to test. Atsconfig.jsonthat type-checks the framework sources through the condition ("customConditions": ["@znight/source"], as the examples do, or importing them by path, asdocs/testdoes) also needs"allowImportingTsExtensions": true(withnoEmit): the sources import each other with the.tssuffix, whichtscotherwise rejects (TS5097). - Sources run as is on Node.js 24 and Bun: relative imports use the
.tssuffix;erasableSyntaxOnly(no parameter properties, enums, namespaces or decorators insrc/; tests may use them);isolatedDeclarations(explicit types on exports). - Small, focused modules, ESM only, JSDoc on public APIs, no
anywithout a justifiedbiome-ignore. - Tests live in
packages/<pkg>/test/**/*.test.tsand usebun:test; fixtures intest/fixtures/. Slow tests are opt-in:ZNIGHT_INTEGRATION=1(real brokers),ZNIGHT_CLI_E2E=1(a scaffolded application, end to end),ZNIGHT_E2E=1(the examples end to end and the golden test, afterbun run build; theclient:checkofexamples/storefront-apirunsnpm exec, so the first run needs npm and the registry).tests/boundaries.test.tsenforces the package boundaries of the specification (§2). - Integrations (fastify, amqplib, prom-client...) are optional peer dependencies, loaded from subpath exports.
- Generated-code contract: every helper the compiler-generated code calls is exported from the package's root entry, documented in a "Compiler contract" section of its README and kept stable.
- Errors use codes from
ErrorCodein@znight/core. A new code needs an entry inERROR_DESCRIPTIONS, in the specification and in the error reference. - Commits follow Conventional Commits (
feat(core): ...,fix(compiler): ...,docs: ...).
Documentation
The site lives in docs/ and is built with VitePress:
sh
bun run docs:dev # http://localhost:5173
bun run docs:build # production build, fails on dead links- Pages are Markdown with VitePress extensions (
::: tip,::: code-group,<Badge>...). - Link to other pages with absolute paths without extension (
/guide/scopes#rules-between-scopes). - Link to repository files with relative paths (
../../packages/core/src/errors.ts): they are rewritten to GitHub links at build time. - Every error code has an anchor (
/reference/error-codes#znight001) that runtime and compiler messages can link to. - A section describing an API that is not implemented yet is marked with an HTML comment starting with
TODO(api): verify against implementation(the docs tests reject any otherTODOcomment); remove it once the section has been checked against the implementation. - The brand assets (logo, mark, favicons, social preview) live in
docs/public.
Releases
Every change to main goes through a pull request, merged once CI passes: lint, typecheck, build and pack, unit and example tests, docs build, end-to-end tests on Node.js and Bun, Docker integration tests, and the packed packages installed in a fresh application.
All @znight/* packages are versioned in lockstep with Changesets: a pull request that changes a published package for its users adds a changeset (bun run changeset; before 1.0, a breaking change is a minor bump, everything else a patch). Changesets merged into main feed a "chore: version packages" pull request; merging it releases a new version to npm after a maintainer's approval, and deploys this site to GitHub Pages. The maintainer guide is RELEASING.md.