{"id":47603156,"url":"https://github.com/forinda/kick-js","last_synced_at":"2026-06-14T10:01:23.639Z","repository":{"id":315673382,"uuid":"1060445247","full_name":"forinda/kick-js","owner":"forinda","description":"A declarative progressive backend framework","archived":false,"fork":false,"pushed_at":"2026-06-08T19:33:35.000Z","size":8760,"stargazers_count":10,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T20:17:17.625Z","etag":null,"topics":["api","dependency-injection","expressjs","joi","kickjs","mongoose","typescript","vite","vitejs","zod"],"latest_commit_sha":null,"homepage":"https://forinda.github.io/kick-js/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/forinda.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-19T23:43:28.000Z","updated_at":"2026-06-08T19:28:55.000Z","dependencies_parsed_at":"2025-09-20T02:37:55.377Z","dependency_job_id":null,"html_url":"https://github.com/forinda/kick-js","commit_stats":null,"previous_names":["forinda/kick-js"],"tags_count":234,"template":false,"template_full_name":null,"purl":"pkg:github/forinda/kick-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forinda%2Fkick-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forinda%2Fkick-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forinda%2Fkick-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forinda%2Fkick-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/forinda","download_url":"https://codeload.github.com/forinda/kick-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/forinda%2Fkick-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34316823,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","dependency-injection","expressjs","joi","kickjs","mongoose","typescript","vite","vitejs","zod"],"created_at":"2026-04-01T18:58:43.247Z","updated_at":"2026-06-14T10:01:23.632Z","avatar_url":"https://github.com/forinda.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://forinda.github.io/kick-js/\"\u003e\n    \u003cimg src=\"docs/public/banner.svg\" alt=\"KickJS\" width=\"600\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  A production-grade, decorator-driven Node.js framework for TypeScript — runs on Express, Fastify, or h3, swap the engine in one line.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@forinda/kickjs\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/@forinda/kickjs?color=FACC15\u0026label=npm\" alt=\"npm version\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/forinda/kick-js/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/forinda/kick-js?color=312E81\" alt=\"license\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://nodejs.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/node-%3E%3D20-brightgreen\" alt=\"node version\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nNestJS ergonomics without the complexity — decorators, DI, module system, code generators, and end-to-end type safety, powered by Zod and Vite.\n\n## Install\n\n```bash\npnpm add @forinda/kickjs express reflect-metadata zod\npnpm add -D @forinda/kickjs-cli\n```\n\nOr scaffold a new project:\n\n```bash\nnpx @forinda/kickjs-cli new my-api\ncd my-api \u0026\u0026 pnpm dev\n```\n\n## Hello World\n\nA fresh `kick new my-api` scaffolds a complete project. Here are the files that matter, exactly as the CLI generates them:\n\n```ts\n// src/modules/hello/hello.service.ts\nimport { Service } from '@forinda/kickjs'\n\n@Service()\nexport class HelloService {\n  greet(name: string) {\n    return { message: `Hello ${name} from KickJS!`, timestamp: new Date().toISOString() }\n  }\n\n  healthCheck() {\n    return { status: 'ok', uptime: process.uptime() }\n  }\n}\n```\n\n```ts\n// src/modules/hello/hello.controller.ts\nimport { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'\nimport { HelloService } from './hello.service'\n\n@Controller()\nexport class HelloController {\n  @Autowired() private readonly helloService!: HelloService\n\n  @Get('/')\n  index(ctx: Ctx\u003cKickRoutes.HelloController['index']\u003e) {\n    ctx.json(this.helloService.greet('World'))\n  }\n\n  @Get('/health')\n  health(ctx: Ctx\u003cKickRoutes.HelloController['health']\u003e) {\n    ctx.json(this.helloService.healthCheck())\n  }\n}\n```\n\n```ts\n// src/modules/hello/hello.module.ts\nimport { defineModule } from '@forinda/kickjs'\nimport { HelloController } from './hello.controller'\n\nexport const HelloModule = defineModule({\n  name: 'HelloModule',\n  build: () =\u003e ({\n    routes() {\n      return { path: '/hello', controller: HelloController }\n    },\n  }),\n})\n```\n\n```ts\n// src/modules/index.ts\nimport { defineModules } from '@forinda/kickjs'\nimport { HelloModule } from './hello/hello.module'\n\nexport const modules = defineModules().mount(HelloModule())\n```\n\n```ts\n// src/index.ts\nimport 'reflect-metadata'\nimport './config' // registers env schema before bootstrap\nimport { bootstrap } from '@forinda/kickjs'\nimport { modules } from './modules'\n\nexport const app = await bootstrap({ modules })\n```\n\n\u003e `KickRoutes.HelloController['index']` is generated by `kick typegen`\n\u003e (auto-runs on `kick dev`), giving fully typed `ctx.params`, `ctx.body`,\n\u003e and `ctx.query`. Env keys typed via `KickEnv` after running typegen too.\n\n## Highlights\n\n**Factory-first extensibility** — the full extension surface. No class hierarchies to inherit from.\n\n```ts\ndefineAdapter() defineModule()\ndefinePlugin() defineHttpContextDecorator()\n```\n\n**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.\n\n```ts\nconst REPO = createToken\u003cUserRepo\u003e('app/users/repository')\ncontainer.register(REPO, PrismaUserRepo)\n```\n\n**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.\n\n**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.\n\n```ts\nKickRoutes // ctx.params / body / query per route\nKickJsPluginRegistry // @Inject literals\nKickAssets // typed asset paths\nKickEnv // ConfigService.get keys\n```\n\n**Decorator-driven**:\n\n```ts\n@Controller @Get @Post @Put @Delete @Patch\n@Service @Autowired @Middleware\n@Cacheable @Cron @Asset\n```\n\n**DDD generators** — full hook surface emitted so you delete what you don't need.\n\n```bash\nkick g module users  # complete module scaffold\nkick g adapter       # full hook surface\nkick g plugin        # full plugin shape\n```\n\n**`kick g agents`** — regenerates `CLAUDE.md` at the project root and `.agents/AGENTS.md` / `.agents/GEMINI.md` / `.agents/COPILOT.md` + per-skill `.agents/skills/\u003cslug\u003e/SKILL.md`. One CLI command keeps every AI coding agent in sync with the latest framework conventions.\n\n**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.\n\n```ts\nbootstrap({ processHooks: 'errors-only' })\n```\n\n**Zod-native validation** — schemas double as OpenAPI documentation.\n\n**Vite HMR** — single-port dev server, zero-downtime hot reload, preserves DB/Redis/Socket connections, customizable HMR log.\n\n**Auto OpenAPI** — Swagger UI and ReDoc from decorators + Zod schemas; pluggable schema parser + UI renderer for adopters who want corporate branding.\n\n**Built-in middleware** — helmet, CORS, CSRF, rate limiting, file uploads, request logging, request scope (AsyncLocalStorage).\n\n**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`.\n\n**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.\n\n## Ecosystem\n\nKickJS 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.\n\n### Core packages\n\nThree 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:\n\n| Package                                  | Description                                                                                                                                         |\n| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`@forinda/kickjs`](packages/kickjs/)    | Core framework — DI, decorators, pluggable HTTP runtimes (Express / Fastify / h3), routing, middleware, contributors, request store, `processHooks` |\n| [`@forinda/kickjs-vite`](packages/vite/) | Vite plugin — single-port HMR, typegen watcher, customizable HMR log                                                                                |\n| [`@forinda/kickjs-cli`](packages/cli/)   | Scaffolding, DDD generators, custom commands, `kick g agents`, jiti-powered TS config loading, walk-up project root                                 |\n\n### Optional packages\n\nEverything 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:\n\n```bash\nkick add --list           # current optional catalog\nkick add swagger drizzle  # install several at once\n```\n\nBrowse `packages/` in this repo for the full source layout.\n\n## Example Apps\n\nRunnable 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.\n\n```bash\ngit clone https://github.com/forinda/kickjs-examples-archive\n```\n\nThe fastest way to start a real project is still `kick new \u003cname\u003e` — `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.\n\n## CLI\n\n```bash\n# Project lifecycle\nkick new my-api                      # Scaffold project (rest | ddd | cqrs | minimal)\nkick dev                             # Vite HMR dev server (~200ms reload)\nkick build \u0026\u0026 kick start             # Production build + run\n\n# Code generation\nkick g module users                  # Full DDD module\nkick g module users --repo prisma    # …with a Prisma repository\nkick g module users --repo drizzle   # …with a Drizzle repository\nkick g scaffold post title:string body:text:optional  # CRUD from field defs\nkick g controller users              # Single @Controller class\nkick g service payment               # Single @Service class\nkick g adapter websocket             # AppAdapter — every hook stubbed + JSDoc\nkick g plugin analytics              # KickPlugin — every hook stubbed + JSDoc\nkick g job / dto / guard / middleware / test  # one-file scaffolds\n\n# AI agent docs (regenerate from upstream templates after framework upgrades)\nkick g agents                        # CLAUDE.md (root) + .agents/{AGENTS,GEMINI,COPILOT}.md + .agents/skills/*/SKILL.md\nkick g agents --only skills -f       # Just the per-skill SKILL.md files\nkick g agents --only gemini -f       # Just .agents/GEMINI.md\n\n# Package management\nkick add swagger drizzle             # Install KickJS packages with peer deps\nkick add --list                      # Show all available packages\n\n# Introspection\nkick info                            # System + framework version\nkick inspect                         # Inspect a running KickJS app\nkick tinker                          # Interactive REPL with full DI graph\n```\n\n## Technical Decisions\n\n| Area       | Choice                 | Why                                                                  |\n| ---------- | ---------------------- | -------------------------------------------------------------------- |\n| Runtime    | Node.js 20+            | LTS with native ESM                                                  |\n| HTTP       | Express / Fastify / h3 | Pluggable runtime — pick the engine at bootstrap                     |\n| Validation | Zod                    | Runtime + static types, doubles as OpenAPI schema                    |\n| Build      | Vite 8                 | Unified toolchain — library builds, HMR, SSR                         |\n| Test       | Vitest 4               | ESM-native, fast, Vite-compatible                                    |\n| Logging    | console (pluggable)    | Zero-dep default; swap for Pino / Winston via `Logger.setProvider()` |\n| Monorepo   | pnpm + Turborepo       | Efficient deps, build caching                                        |\n\n## Runtime Compatibility\n\n| Feature         | Node 20+ | Node 22+ | Node 24+ | Bun          | Deno |\n| --------------- | -------- | -------- | -------- | ------------ | ---- |\n| Production      | Yes      | Yes      | Yes      | Experimental | No   |\n| Dev Mode (HMR)  | Yes      | Yes      | Yes      | No           | No   |\n| Tests (Vitest)  | Yes      | Yes      | Yes      | Partial      | No   |\n| CLI (`kick`)    | Yes      | Yes      | Yes      | Experimental | No   |\n| Pure ESM Import | Yes      | Yes      | Yes      | Yes          | Yes  |\n\n\u003e **Node 20** is the minimum supported version (LTS with native ESM).\n\u003e\n\u003e **Bun**: core DI and decorators work; full HTTP pipeline is experimental.\n\u003e\n\u003e **Deno**: blocked by `reflect-metadata`. The default logger is `console`-based (zero deps), so logging is not a blocker.\n\n## Documentation\n\n**[forinda.github.io/kick-js](https://forinda.github.io/kick-js/)**\n\nNew 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.\n\n## Contributing\n\n```bash\ngit clone https://github.com/forinda/kick-js.git\ncd kick-js\npnpm install \u0026\u0026 pnpm build \u0026\u0026 pnpm test\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.\n\n## License\n\nMIT — see [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforinda%2Fkick-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforinda%2Fkick-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforinda%2Fkick-js/lists"}