https://github.com/forinda/kick-js
A declarative progressive backend framework
https://github.com/forinda/kick-js
api dependency-injection expressjs joi kickjs mongoose typescript vite vitejs zod
Last synced: 29 days ago
JSON representation
A declarative progressive backend framework
- Host: GitHub
- URL: https://github.com/forinda/kick-js
- Owner: forinda
- License: mit
- Created: 2025-09-19T23:43:28.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2026-06-08T19:33:35.000Z (about 1 month ago)
- Last Synced: 2026-06-08T20:17:17.625Z (about 1 month ago)
- Topics: api, dependency-injection, expressjs, joi, kickjs, mongoose, typescript, vite, vitejs, zod
- Language: TypeScript
- Homepage: https://forinda.github.io/kick-js/
- Size: 8.35 MB
- Stars: 10
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
A production-grade, decorator-driven Node.js framework for TypeScript — runs on Express, Fastify, or h3, swap the engine in one line.
NestJS ergonomics without the complexity — decorators, DI, module system, code generators, and end-to-end type safety, powered by Zod and Vite.
## Install
```bash
pnpm add @forinda/kickjs express reflect-metadata zod
pnpm add -D @forinda/kickjs-cli
```
Or scaffold a new project:
```bash
npx @forinda/kickjs-cli new my-api
cd my-api && pnpm dev
```
## Hello World
A fresh `kick new my-api` scaffolds a complete project. Here are the files that matter, exactly as the CLI generates them:
```ts
// src/modules/hello/hello.service.ts
import { Service } from '@forinda/kickjs'
@Service()
export class HelloService {
greet(name: string) {
return { message: `Hello ${name} from KickJS!`, timestamp: new Date().toISOString() }
}
healthCheck() {
return { status: 'ok', uptime: process.uptime() }
}
}
```
```ts
// src/modules/hello/hello.controller.ts
import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
import { HelloService } from './hello.service'
@Controller()
export class HelloController {
@Autowired() private readonly helloService!: HelloService
@Get('/')
index(ctx: Ctx) {
ctx.json(this.helloService.greet('World'))
}
@Get('/health')
health(ctx: Ctx) {
ctx.json(this.helloService.healthCheck())
}
}
```
```ts
// src/modules/hello/hello.module.ts
import { defineModule } from '@forinda/kickjs'
import { HelloController } from './hello.controller'
export const HelloModule = defineModule({
name: 'HelloModule',
build: () => ({
routes() {
return { path: '/hello', controller: HelloController }
},
}),
})
```
```ts
// src/modules/index.ts
import { defineModules } from '@forinda/kickjs'
import { HelloModule } from './hello/hello.module'
export const modules = defineModules().mount(HelloModule())
```
```ts
// src/index.ts
import 'reflect-metadata'
import './config' // registers env schema before bootstrap
import { bootstrap } from '@forinda/kickjs'
import { modules } from './modules'
export const app = await bootstrap({ modules })
```
> `KickRoutes.HelloController['index']` is generated by `kick typegen`
> (auto-runs on `kick dev`), giving fully typed `ctx.params`, `ctx.body`,
> and `ctx.query`. Env keys typed via `KickEnv` after running typegen too.
## Highlights
**Factory-first extensibility** — the full extension surface. No class hierarchies to inherit from.
```ts
defineAdapter() defineModule()
definePlugin() defineHttpContextDecorator()
```
**Custom DI container** — constructor and property injection, three scopes (singleton / transient / request), zero external dependency. Slash-delimited tokens carry intent and scope from the type definition straight through to error messages.
```ts
const REPO = createToken('app/users/repository')
container.register(REPO, PrismaUserRepo)
```
**Typed Context Contributors** — `defineHttpContextDecorator()` populates `ctx.set('key', value)` once per request. `dependsOn` is typed against `keyof ContextMeta` so typos are TS errors, not boot-time `MissingContributorError`. Same registration runs across HTTP / WS / queue / cron.
**End-to-end type safety via typegen** — `kick typegen` (auto on `kick dev`) emits augmentations from source scan. `ctx.params/body/query`, `@Inject` literals, and asset paths all narrow as you save.
```ts
KickRoutes // ctx.params / body / query per route
KickJsPluginRegistry // @Inject literals
KickAssets // typed asset paths
KickEnv // ConfigService.get keys
```
**Decorator-driven**:
```ts
@Controller @Get @Post @Put @Delete @Patch
@Service @Autowired @Middleware
@Cacheable @Cron @Asset
```
**DDD generators** — full hook surface emitted so you delete what you don't need.
```bash
kick g module users # complete module scaffold
kick g adapter # full hook surface
kick g plugin # full plugin shape
```
**`kick g agents`** — regenerates `CLAUDE.md` at the project root and `.agents/AGENTS.md` / `.agents/GEMINI.md` / `.agents/COPILOT.md` + per-skill `.agents/skills//SKILL.md`. One CLI command keeps every AI coding agent in sync with the latest framework conventions.
**Cooperative shutdown** — observability SDKs (OpenTelemetry, Sentry) own SIGTERM without racing the framework. `Promise.allSettled` for adapter shutdown so one slow flush can't block siblings.
```ts
bootstrap({ processHooks: 'errors-only' })
```
**Zod-native validation** — schemas double as OpenAPI documentation.
**Vite HMR** — single-port dev server, zero-downtime hot reload, preserves DB/Redis/Socket connections, customizable HMR log.
**Auto OpenAPI** — Swagger UI and ReDoc from decorators + Zod schemas; pluggable schema parser + UI renderer for adopters who want corporate branding.
**Built-in middleware** — helmet, CORS, CSRF, rate limiting, file uploads, request logging, request scope (AsyncLocalStorage).
**DevTools dashboard** — `/_debug` browser panel with topology, container, routes, metrics; adapter authors expose state via `introspect()` ([type lives in `@forinda/kickjs` directly](https://forinda.github.io/kick-js/guide/devtools.html) — no extra import needed) + `devtoolsTabs()` from `@forinda/kickjs-devtools-kit`.
**Extensible CLI** — custom commands in `kick.config.ts`, plugin generators registered as real Commander subcommands so they appear in `kick g --help`, jiti-powered TS config loading, walk-up project-root resolution.
## Ecosystem
KickJS deliberately ships a small, stable core. The extension surface — `defineAdapter()`, `definePlugin()`, `defineHttpContextDecorator()`, plus `getRequestValue` and `processHooks` from `@forinda/kickjs` — is the same one the framework itself uses, so adopter-built integrations stay first-class: typed DI, lifecycle hooks, the contributor pipeline, and DevTools `introspect()` all work without any framework changes.
### Core packages
Three packages ship with every project — `kick new` always installs them, and `kick add` won't list them as optional. Together they're the framework runtime + the dev/build/scaffold loop:
| Package | Description |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@forinda/kickjs`](packages/kickjs/) | Core framework — DI, decorators, pluggable HTTP runtimes (Express / Fastify / h3), routing, middleware, contributors, request store, `processHooks` |
| [`@forinda/kickjs-vite`](packages/vite/) | Vite plugin — single-port HMR, typegen watcher, customizable HMR log |
| [`@forinda/kickjs-cli`](packages/cli/) | Scaffolding, DDD generators, custom commands, `kick g agents`, jiti-powered TS config loading, walk-up project root |
### Optional packages
Everything else — swagger, the db family, queue, ws, devtools, drizzle, prisma — installs on demand. The catalog moves over time, so the live list lives next to the CLI rather than this README:
```bash
kick add --list # current optional catalog
kick add swagger drizzle # install several at once
```
Browse `packages/` in this repo for the full source layout.
## Example Apps
Runnable reference apps live in **[forinda/kickjs-examples-archive](https://github.com/forinda/kickjs-examples-archive)** — Drizzle / Prisma / Mongoose / `@forinda/kickjs-db` task apps, multi-tenant patterns, and a minimal starter. Open the archive's README for the current catalog.
```bash
git clone https://github.com/forinda/kickjs-examples-archive
```
The fastest way to start a real project is still `kick new ` — `kick.config.ts`, `tsconfig`, `vite.config`, modules, and env wiring scaffolded for you. The archive is for reading reference patterns; the CLI is for starting your own.
## CLI
```bash
# Project lifecycle
kick new my-api # Scaffold project (rest | ddd | cqrs | minimal)
kick dev # Vite HMR dev server (~200ms reload)
kick build && kick start # Production build + run
# Code generation
kick g module users # Full DDD module
kick g module users --repo prisma # …with a Prisma repository
kick g module users --repo drizzle # …with a Drizzle repository
kick g scaffold post title:string body:text:optional # CRUD from field defs
kick g controller users # Single @Controller class
kick g service payment # Single @Service class
kick g adapter websocket # AppAdapter — every hook stubbed + JSDoc
kick g plugin analytics # KickPlugin — every hook stubbed + JSDoc
kick g job / dto / guard / middleware / test # one-file scaffolds
# AI agent docs (regenerate from upstream templates after framework upgrades)
kick g agents # CLAUDE.md (root) + .agents/{AGENTS,GEMINI,COPILOT}.md + .agents/skills/*/SKILL.md
kick g agents --only skills -f # Just the per-skill SKILL.md files
kick g agents --only gemini -f # Just .agents/GEMINI.md
# Package management
kick add swagger drizzle # Install KickJS packages with peer deps
kick add --list # Show all available packages
# Introspection
kick info # System + framework version
kick inspect # Inspect a running KickJS app
kick tinker # Interactive REPL with full DI graph
```
## Technical Decisions
| Area | Choice | Why |
| ---------- | ---------------------- | -------------------------------------------------------------------- |
| Runtime | Node.js 20+ | LTS with native ESM |
| HTTP | Express / Fastify / h3 | Pluggable runtime — pick the engine at bootstrap |
| Validation | Zod | Runtime + static types, doubles as OpenAPI schema |
| Build | Vite 8 | Unified toolchain — library builds, HMR, SSR |
| Test | Vitest 4 | ESM-native, fast, Vite-compatible |
| Logging | console (pluggable) | Zero-dep default; swap for Pino / Winston via `Logger.setProvider()` |
| Monorepo | pnpm + Turborepo | Efficient deps, build caching |
## Runtime Compatibility
| Feature | Node 20+ | Node 22+ | Node 24+ | Bun | Deno |
| --------------- | -------- | -------- | -------- | ------------ | ---- |
| Production | Yes | Yes | Yes | Experimental | No |
| Dev Mode (HMR) | Yes | Yes | Yes | No | No |
| Tests (Vitest) | Yes | Yes | Yes | Partial | No |
| CLI (`kick`) | Yes | Yes | Yes | Experimental | No |
| Pure ESM Import | Yes | Yes | Yes | Yes | Yes |
> **Node 20** is the minimum supported version (LTS with native ESM).
>
> **Bun**: core DI and decorators work; full HTTP pipeline is experimental.
>
> **Deno**: blocked by `reflect-metadata`. The default logger is `console`-based (zero deps), so logging is not a blocker.
## Documentation
**[forinda.github.io/kick-js](https://forinda.github.io/kick-js/)**
New here? The **[Samples guide](https://forinda.github.io/kick-js/guide/samples)** is a one-page, copy-pasteable tour of the recommended patterns — controllers, DI, modules, config, context decorators, error handling, adapters, and extending the CLI — each linking into the full guide. It doubles as the mental model.
## Contributing
```bash
git clone https://github.com/forinda/kick-js.git
cd kick-js
pnpm install && pnpm build && pnpm test
```
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.
## License
MIT — see [LICENSE](LICENSE)