npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@t8n/kit

v0.0.3

Published

The standard decorator extension for TitanPL

Downloads

37

Readme

@t8n/kit

The standard decorator extension for TitanPL, built to bring a NestJS-like developer experience to TitanPL apps, with routes now and more decorators coming soon.

@t8n/kit lets you define TitanPL routes with TypeScript classes and route decorators, then writes the matching route entries into your app/app.ts file automatically.

This package is currently in 0.0.1-alfa.

Important:

  • This is an early testing release.
  • Only route decorators are available right now.
  • Not all decorators are implemented yet.
  • The goal is to make TitanPL feel more like a decorator-first framework similar to NestJS.
  • More decorator-based features are coming soon.
  • APIs and behavior may change at any time while the package is being tested.
  • If you try it and hit any issue, please report it at https://github.com/t8nlab/kit.

Current Features

  • @Controller() to group routes under a shared base path
  • @Get()
  • @Post()
  • @Put()
  • @Delete()
  • "action" routes for TitanPL actions
  • "reply" routes for direct static replies
  • Helpers exported from @t8n/kit/lib for low-level route writing:
    • normalizePath()
    • joinPath()
    • writeRoute()
    • removeRoute()

Installation

First, create a TitanPL app by following the official docs:

https://titanpl.vercel.app/docs

After your TitanPL app is ready, install the extension:

npm i @t8n/kit

Recommended flow:

  1. Create your TitanPL app or server from the TitanPL docs.
  2. Install @t8n/kit.
  3. Add controllers and route decorators.
  4. Run npm run dev in your TitanPL server once to let everything wire up and verify routes.

Project Setup

Your TitanPL app will have an app/app.ts entry file. @t8n/kit writes route lines into that file.

Minimal example:

import t from "@titanpl/route";

t.start(5100, "Titan Running!");

When your decorated controller files are imported, @t8n/kit can insert lines like:

t.post("/user/login").action("login");

TypeScript Notes

Because this package is decorator-based, your TypeScript app should enable decorators.

Add in tsconfig.json at compilerOptions:

"experimentalDecorators": true,
"emitDecoratorMetadata": true,
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

How It Works

  1. You create controller classes and decorate methods with route decorators.
  2. You import those controller files somewhere in your app or action files.
  3. @t8n/kit collects the route metadata.
  4. It writes matching TitanPL route definitions into app/app.ts.

Build And Production Behavior

@t8n/kit is based on route generation logic, not live runtime route mutation in production.

  • In development, when your decorated files are loaded, the route lines are written into app/app.ts.
  • During build, TitanPL uses the generated route file output that already exists.
  • In production, the server does not keep creating or changing routes after the app has been built.
  • This is similar to TitanPL actions: after build, if you add new actions or new decorated routes, you need to rebuild the app for those changes to be included.

Recommended check:

npm run dev

Run that once in your TitanPL server after adding or changing decorators so the route output can be checked during development.

Route Decorators

@Controller(basePath)

Adds a shared base path to every decorated route in the class.

import { Controller, Post } from "@t8n/kit";

@Controller("/user")
class UserController {
  @Post("/login", "action", "login")
  login() {}
}

This becomes:

t.post("/user/login").action("login");

You can also use @Controller without a base path:

import { Controller, Get } from "@t8n/kit";

@Controller
class PublicController {
  @Get("/health", "reply", "ok")
  health() {}
}

HTTP method decorators

Available decorators:

  • Get(path, type, value)
  • Post(path, type, value)
  • Put(path, type, value)
  • Delete(path, type, value)

Supported route types:

  • "action": maps the route to a TitanPL action name
  • "reply": returns a direct reply value

Usage Examples

Action route

import { Controller, Post } from "@t8n/kit";

@Controller("/auth")
class AuthController {
  @Post("/login", "action", "login")
  login() {}
}

Generated route:

t.post("/auth/login").action("login");

Reply route

import { Get } from "@t8n/kit";

class PublicRoutes {
  @Get("/health", "reply", "ok")
  health() {}
}

Generated route:

t.get("/health").reply("ok");

reply with objects

import { Get } from "@t8n/kit";

class MetaController {
  @Get("/meta", "reply", { name: "kit", ready: true })
  meta() {}
}

Generated route:

t.get("/meta").reply({ "name": "kit", "ready": true });

Full controller example

import { Controller, Delete, Get, Post, Put } from "@t8n/kit";

@Controller("/users")
class UsersController {
  @Get("/", "action", "getUsers")
  list() {}

  @Get("/:id", "action", "getUser")
  get() {}

  @Post("/", "action", "createUser")
  create() {}

  @Put("/:id", "action", "updateUser")
  update() {}

  @Delete("/:id", "action", "deleteUser")
  remove() {}
}

Real Example

Based on test/app/controllers/user.ts](https://github.com/t8nlab/kit/blob/main/test/app/controllers/user.ts), this controller:

import { Controller, Post } from "@t8n/kit";

@Controller("/user")
class UserController {
  @Post("/login", "action", "login")
  login(req: any) {
    return { ok: true };
  }
}

produces this route entry in test/app/app.ts:

t.post("/user/login").action("login");

The action implementation can then call the controller method, like in test/app/actions/login.ts:

import { defineAction } from "@titanpl/native";
import UserController from "app/controllers/user";

export default defineAction((req) => {
  const controller = new UserController();
  return controller.login(req);
});

Also note just imports the controller file so route decorators can run multi time import never make bugs:

import "app/controllers/user";

Recommended Usage Pattern

For the current release, this pattern works best:

  1. Create controllers in app/controllers.
  2. Decorate methods with @Get, @Post, @Put, or @Delete.
  3. Import the controller file from an action file or another loaded module.
  4. Keep app/app.ts present in your TitanPL app.
  5. Let @t8n/kit write the route entries there.

API Reference

Controller

Controller(target: Function): void
Controller(basePath: string): ClassDecorator

Method decorators

Get(path: string, type: "action", actionName: string)
Get(path: string, type: "reply", replyValue?: unknown)

Post(path: string, type: "action", actionName: string)
Post(path: string, type: "reply", replyValue?: unknown)

Put(path: string, type: "action", actionName: string)
Put(path: string, type: "reply", replyValue?: unknown)

Delete(path: string, type: "action", actionName: string)
Delete(path: string, type: "reply", replyValue?: unknown)

Low-level helpers

import { joinPath, normalizePath, removeRoute, writeRoute } from "@t8n/kit/lib";

Example:

writeRoute({
  method: "GET",
  path: "/hello",
  type: "reply",
  value: "world",
});

Notes And Limitations

  • Only route decorators are implemented right now.
  • Decorators run when the file is imported.
  • Route generation is intended for development/build flow, not post-build production mutation.
  • Early APIs may change without notice between test releases.

Example App Structure

app/
  actions/
    login.ts
    getuser.ts
  controllers/
    user.ts
  app.ts

Import Patterns

Import a controller for side effects

Useful when you only want decorators to register routes:

import "app/controllers/user";

Import a controller class directly

Useful when an action wants to call controller methods:

import UserController from "app/controllers/user";

const controller = new UserController();

Stability Notice

@t8n/[email protected] is experimental.

  • Only the route decorator layer exists today.
  • The package is designed as the base for a broader TitanPL decorator system.
  • More decorators may be added later.
  • Existing APIs may be renamed, expanded, or removed.
  • Use it for testing and feedback, not for assuming final stable behavior.

Issues And Feedback

If you find a bug, unexpected route output, or decorator issue, please open an issue in the repo:

https://github.com/t8nlab/kit/issues

Repository:

https://github.com/t8nlab/kit

License

MIT