Skip to content

CHOModular applications, on every runtime

A tiny decorator-based framework for HTTP and command-line applications. Standard decorators, no reflection, the same code on Deno, Node.js, Bun and the edge.

CHO

A quick look ​

An HTTP application:

ts
import {
  ChoWeb,
  type ChoWebContext,
  Controller,
  Get,
  Injectable,
  Module,
} from "@chojs/web";
import { HonoLinker } from "@chojs/vendor-hono";

@Injectable()
class UserStore {
  find(id: string) {
    return { id, name: "Ada" };
  }
}

@Controller({ route: "users", dependencies: [UserStore] })
class UsersController {
  constructor(readonly store: UserStore) {}

  @Get(":id") // GET /users/42
  get(ctx: ChoWebContext) {
    return this.store.find(ctx.params.id!); // sent as JSON
  }
}

@Module({ providers: [UserStore], controllers: [UsersController] })
class App {}

const app = await ChoWeb.create(App, { linker: new HonoLinker() });

Then serve app.handler with whatever the runtime has:

ts
Deno.serve(app.handler);
ts
Bun.serve({ fetch: app.handler });
ts
import { serve } from "@hono/node-server";

serve({ fetch: app.handler, port: 3000 });

A command-line application, with the same modules, controllers and providers:

ts
import {
  Action,
  ChoCommand,
  type ChoCommandContext,
  Controller,
  Help,
  Module,
} from "@chojs/command";

@Controller()
class Greeter {
  @Help("Say hello")
  @Action("hello", { string: ["name"] })
  hello(ctx: ChoCommandContext) {
    console.log(`Hello, ${ctx.args.name ?? "world"}!`);
  }
}

@Module({ controllers: [Greeter] })
class App {}

const app = ChoCommand.create(App, { name: "greet" });
const code = await app.run(Deno.args); // Node.js, Bun: process.argv.slice(2)

Released under the MIT License.