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 🙏

© 2024 – Pkg Stats / Ryan Hefner

serverstruct

v0.2.0

Published

Type safe and modular servers with Hono

Downloads

10

Readme

Serverstruct

⚡️ Typesafe and modular servers with Hono.

Serverstruct is a simple tool for building fast, modular and typesafe server applications.

It provides structure to your Hono application without any limitations. It also supports dependency injection using Hollywood DI.

Installation

Serverstruct requires you to install hono.

npm i serverstruct hono

To make use of dependency injection provided by serverstruct, also install hollywood-di.

npm i serverstruct hono hollywood-di

Usage

A simple app

import { createRoute } from "serverstruct";

const app = createRoute()
  .route((app) => {
    return app.get("/", (c) => c.text("Hello world!"));
  })
  .app();

export default app;

An app with subroutes

import { createRoute } from "serverstruct";

// users routes
const users = createRoute().route((app) => {
  return app.get("/", (c) => c.text("users"));
});

// posts routes
const posts = createRoute().route((app) => {
  return app.get("/", (c) => c.text("posts"));
});

const app = createRoute()
  .subroutes({ users, posts })
  .route((app, container, routes) => {
    return app
      .get("/", (c) => c.text("Hello world!"))
      .route("/users", routes.users)
      .route("/posts", routes.posts);
  })
  .app();

export default app;

Route

A route returns a new Hono app and may compose other routes with subroutes<{ ... }>(). If you intend to utilize dependency injection, a route can require it's dependencies with use<{ ... }>() and provide new dependencies with provide({ ... }). A route with dependencies can only be added as a subroute to another route if that route satisfies it's dependencies.

const auth = createRoute().route((app) => {
  return app; // chain route handlers here
});

const users = createRoute().route((app) => {
  return app; // chain route handlers here
});

const posts = createRoute().route((app) => {
  return app; // chain route handlers here
});

const app = createRoute()
  .subroutes({ auth, users, posts })
  .route((app, container, routes) => {
    return app
      .route("/auth", routes.auth)
      .route("/users", routes.users)
      .route("/posts", routes.posts);
  })
  .app();

Subroutes are not automatically registered. You will have to manually add the route for the desired path. This also allows for Hono's type inference through method chaining.

Dependency Injection

Serverstruct is designed to work with Hollywood DI. Routes can define their dependencies using use, and also register new tokens using provide which creates a child container.

A root container can also be passed to the route. If no container is explicitly provided the first call to provide creates a root container and futher calls to provide will inherit from it.

Use

Define route dependencies. The route can then only be used in a context that satisfies it's dependencies.

You can only call use once and only before calling provide.

interface Counter {
  count: number;
  increment(): void;
}

const route = createRoute()
  .use<{ counter: Counter }>()
  .route((app, container) => {
    return app.get("/", (c) => {
      container.counter.increment();
      return c.text(`Count is: ${container.counter.count}`);
    });
  });

class LinearCounter {
  public count = 0;
  public increment() {
    this.count++;
  }
}

// as a subroute
const app = createRoute()
  .provide({ counter: LinearCounter }) // the main app provides the dependency
  .subroutes({ countRoute: route })
  .route((app, _, routes) => {
    return app.route("/count", routes.countRoute);
  })
  .app();

// or as the main app
const container = Hollywood.create({ counter: LinearCounter }); // the container provides the dependency
const app = route.app(container);

Calling Route.app() returns the Hono instance from the route, therefore if the route has dependencies (by calling use), a container that satisfies those dependencies must be provided as seen in the example above.

Provide

Provide creates a new child container. Registered tokens can then be used in the route and in futher calls to provide. See more about register tokens in Hollywood DI.

import { defineInit } from "hollywood-di";
import { createRoute } from "serverstruct";

class Foo {}
class Bar {
  public static init = defineInit(Bar).args("foo");

  constructor(public foo: Foo) {}
}

const route = createRoute()
  .provide({
    foo: Foo,
    bar: Bar,
  })
  .route((app, container) => {
    return app;
  });

Incremental Adoption

Serverstruct can be added to an existing Hono app.

// routes/posts.ts
export const postsRoute = createRoute().route((app) => {
  return app.get("/", (c) => {
    return c.text("posts");
  });
});

import { Hono } from "hono";
import { createRoute } from "serverstruct";
import { postsRoute } from "./routes/posts";

const app = new Hono();

app.get("/", (c) => c.text("Hello world!"));
app.route("/posts", postsRoute.app());

export default app;