Skip to content

KosmoJS

the composable meta-framework Multiple source folders. Directory-based routing. Cascading middleware. Nested layouts. End-to-end validation. Fetch clients. OpenAPI spec. Koa, Hono, SolidJS, React, Vue and more.

Validation

Define types in TypeScript. Get runtime validation, type-safe clients, and OpenAPI specs for free. No schema DSLs. Just pure TypeScript with superpowers. One source of truth, zero maintenance overhead.
Details ➜
api/users/[id]/{activity}/index.ts
ts
import { defineRoute } from "_/front/api";

export default defineRoute<
  "users/[id]/{activity}",
  [
    // validate id param as number
    number,
    // activity, if given, should be one of
    "posts" | "comments" | "likes",
  ]
>(({ GET }) => [
  GET((ctx) => {
    // ctx.validated.params is typed and validated at runtime
    const { id, activity } = ctx.validated.params
  })
]);

Payload Validation

Validation targets provides control over what gets validated.
Body targets: json / form / raw.
Metadata targets: query, headers, cookies.
Use VRefine to specify JSON Schema constraints.
Details ➜
api/users/index.ts
ts
import { defineRoute } from "_/admin/api";

type Payload = {
  email: VRefine<string, { format: "email" }>;
  password: VRefine<string, { pattern: "^(?=.*[a-zA-Z0-9])$" }>;
  name: VRefine<string, { minLength: 5; maxLength: 50 }>;
  dateOfBirth: VRefine<string, { format: "date" }>;
  agreeToTerms: boolean;
  marketingOptIn?: boolean;
}

export default defineRoute<"users">(({ POST }) => [
  POST<{
    json: Payload, 
  }>((ctx) => {
    // ctx.validated.json is typed and validated at runtime
    const { email } = ctx.validated.json;
  })
]);

Response Validation

Just as you validate incoming request data, you can validate outgoing response data by providing a tuple with status code, content type and expected schema.
Also an union of tuples can be used to specify multiple variants.
Enabled by default on dev, disabled in production.
Details ➜
api/pages/[id]/index.ts
ts
import { defineRoute } from "_/admin/api";

type Page = {
  id: VRefine<string, { format: "uuid" }>;
  title: VRefine<string, { minLength: 1; maxLength: 255 }>;
  content: string;
  tags: string[];
  status: "draft" | "published" | "scheduled";
}

export default defineRoute<"pages/[id]">(({ GET }) => [
  GET<{
    response: [200, "json", Page], 
  }>(async (ctx) => {
    // response should match defined schema
  })
]);

Composable Middleware

Global middleware added to api/use.ts will run on every route. Routes can use slot option to override global middleware.
Custom slots like logger should be added to api/env.d.ts file.
Details ➜
ts
import { use } from "_/admin/api";

export default [
  use(
    (ctx, next) => {
      // global logger
      return next();
    },
    { slot: "logger", }, 
  ),
];
ts
import { defineRoute } from "_/front/api";

export default defineRoute<"example">(({ use, GET }) => [
  use(
    async (ctx, next) => {
      // custom logger
      return next();
    },
    { slot: "logger", }, 
  ),

  GET(async (ctx) => {
    // ...
  }),
]);
ts
export declare module "@kosmojs/api" {
  interface UseSlots {
    logger: string; 
  }
}

Cascading Middleware

Create a use.ts file in any folder, and its default exported middleware automatically wraps all routes in that folder and its subfolders - no imports or manual wiring required.
Details ➜
api/users/use.ts
ts
import { use } from "_/front/api";

export default [
  use(async (ctx, next) => {
    // any route inside users/ folder and its subfolders
    // will wire this middleware automatically
    return next();
  })
];

🎯 What is KosmoJS? ​

KosmoJS is a composable meta-framework that integrates TypeScript, Vite, Koa/Hono, and your frontend framework into a clear organizational pattern. Separation of concerns isn't something you have to remember - it's built into the structure.

No proprietary abstractions. No new paradigms. Just thoughtful structure around tools you already know.

πŸ“˜ Learn more


πŸ’‘ Why Source Folders? ​

Applications often include multiple distinct concerns - each with different routing, auth, and config:

πŸ”Ή Public marketing site at /
πŸ”Ή Customer application at /app
πŸ”Ή Admin dashboard at /admin

Each lives in its own source folder with independent api/ and pages/ directories, sharing types and validation logic across a single project. The directory structure enforces boundaries that code review can't.

πŸ“˜ Getting started Β· Directory-based routing


πŸ›‘οΈ One Source of Truth ​

KosmoJS converts your TypeScript types into runtime validators, typed fetch clients, client-side validation, and OpenAPI schemas - all from the same definitions. No duplication, no drift.

πŸ“˜ Type safety Β· Validation Β· Fetch clients


βš™οΈ API Development ​

Build APIs inside Vite's dev server with hot-reload. Slot-based middleware gives you fine-grained control - override globals per-route or per-subtree, compose request handling precisely. What you build locally is what deploys.

πŸ“˜ Dev workflow Β· Middleware


πŸš€ Production Ready ​

pnpm build produces a bundled API server, optimized frontend assets, and an optional SSR bundle. Deploy to Node.js, Deno, Bun, containers, serverless, or edge.

πŸ“˜ Production build


🧠 Philosophy ​

Structure without constraints.

Opinionated about organization, unopinionated about implementation. You choose your frontend framework, state management, styling, database - everything else. The structure scales; your choices remain free.

πŸ“˜ About KosmoJS Β· Features


Released under the MIT License.