No description
Find a file
2026-03-24 22:56:18 +01:00
scripts updating from ts-lib emplate version 0.2.7 2026-03-10 23:11:14 +01:00
src Fixed destinationPath resolution in cli.ts to use the full resolved path instead of just the basename. 2026-03-13 20:48:12 +01:00
template version 0.2.0 2026-03-24 22:27:53 +01:00
tests add tests back 2026-03-14 00:02:47 +01:00
.gitignore for now 2026-03-11 22:09:50 +01:00
CHANGELOG.md version 0.2.0 2026-03-24 22:27:53 +01:00
LICENSE updated generated package for use as a package template 2026-03-06 14:22:38 +01:00
package.json version 0.2.0 2026-03-24 22:27:53 +01:00
README.md cleanup 2026-03-22 12:16:56 +01:00
tsconfig.build.json creatd package from ts-lib template v0.2.4 2026-03-06 14:14:09 +01:00
tsconfig.json version 0.2.0 2026-03-24 22:27:53 +01:00

Introduction

A template for Bun HTTP servers built with Hono. Provides an opinionated HTTP middleware pipeline, structured request logging, OpenAPI documentation with Scalar UI, and a Bun server host with graceful shutdown. Designed to be used standalone or as the backend in a monorepo alongside one or more @temir.ra/create-hono-spa SPA packages mounted as route groups.

Table of Contents

  1. Quick Start
  2. AI Assistant Context
  3. Documentation
    1. template/
    2. Architecture
    3. src/app-host.ts
      1. AppEnv
    4. src/server-host.ts
    5. src/middleware/logging/
  4. DevOps
    1. Change Management
    2. Publish
      1. npmjs.org
      2. Custom registry

Quick Start

bun create caches the template package - a newer published version will not be picked up automatically. Pin the version or clear the cache to use the latest.

# placeholder:
    # <NEW_PACKAGE: <NEW_PACKAGE>
    # <@_VERSION: <@_VERSION>

# identify the latest version of the template package as <@_VERSION.
bun info "@temir.ra/create-hono-server" version
# create a new library from the template version
bun create --no-install --no-git "@temir.ra/hono-server<@_VERSION>" <NEW_PACKAGE>

# or

# clear package manager cache to ensure the latest template version is used
bun pm cache rm
# create a new library from the latest template version
bun create --no-install --no-git "@temir.ra/hono-server" <NEW_PACKAGE>

# dependencies must be installed manually
cd <NEW_PACKAGE>
bun install

AI Assistant Context

To generate an AI coding assistant context file for this project:

Generate an AI coding assistant context file. Analyze the project structure and source files, using this README as the primary reference for architecture and conventions. Give particular attention to: the three-layer architecture (main → createAppHost → startServerHost) and the separation of concerns between app host and server host, AppEnv and how it is extended to carry custom variables through the Hono context, the middleware pipeline and the scoped logging system, and endpointGroups as the primary extension and integration point for sub-apps.

Documentation

The following sections explain the configurations and conventions baked into the generated package.

template/

The files in template/ were created from the @temir.ra/ts-lib@0.5.0 template and then updated to fit the needs of a Hono server template.

bun create --no-install --no-git --force "@temir.ra/ts-lib@0.5.0" "template/"

Official documentation provided by the Hono team is a great resource.

Architecture

The generated server is organized around three roles:

main.ts  →  createAppHost()  →  startServerHost()

main.ts is the entry point and orchestrator. It calls createAppHost() to configure the Hono application, then passes the result to startServerHost(), which hands it to Bun.serve() and manages the process lifecycle.

  • App host (app-host.ts) - owns the application: what middleware runs, which routes and endpoint groups are mounted, what the API looks like.
  • Server host (server-host.ts) - owns the server: which port it listens on, how it shuts down on process signals.
  • main.ts - wires them together; the natural place to compose the application.
// main.ts
const appHost = createAppHost<AppEnv>({
    basePath: 'api/',
    endpointGroups: [myRoutes],
});

startServerHost({ appHost });

src/app-host.ts

createAppHost(options) constructs and returns a configured Hono<AppEnv> instance.

Built-in middleware pipeline (applied in this order):

Middleware Purpose
Logging Attaches a scoped, leveled log function factory to c.var.getLogFunction
requestId Attaches a unique request ID to c.var.requestId
RequestLogger Logs method and path at TRACE level using the request scope
compress Gzip/Brotli response compression
secureHeaders Adds security response headers

Built-in endpoints:

Path Description
/health Returns ok with status 200
/buildinfo Returns the contents of buildinfo.txt
/<openApiPath> OpenAPI JSON spec (default path: openapi)
/<openApiUiPath> Scalar API reference UI (default path: scalar)

Options:

type AppHostOptions<E extends Env> = {
    basePath?: string;                   // base path prefix for all routes
    middleware?: MiddlewareHandler<E>[];  // additional middleware, applied after built-ins
    endpointGroups?: Hono<E>[];          // Hono sub-apps mounted at '/'
    openApi?: {
        path?: string;                   // OpenAPI spec path (default: 'openapi')
        uiPath?: string;                 // Scalar UI path (default: 'scalar')
        title?: string;
        description?: string;
    };
}

AppEnv

export interface AppEnv extends Env {
    Variables: LoggingVariables
}

Extends Hono's Env with LoggingVariables, making c.var.getLogFunction and c.var.requestId available throughout. Exported to be extended when additional context variables are needed:

interface MyEnv extends AppEnv {
    Variables: AppEnv['Variables'] & {
        user: User;
    }
}

const appHost = createAppHost<MyEnv>({ ... });

const myRoutes = new Hono<MyEnv>();
myRoutes.get('/profile', (c) => c.json(c.var.user));

Adding endpoints

const myRoutes = new Hono<AppEnv>();
myRoutes.get('/items', (c) => c.json({ items: [] }));

const appHost = createAppHost<AppEnv>({
    endpointGroups: [myRoutes],
});

Mounting a SPA

Pass a createSpa() result directly as an endpoint group. See @temir.ra/create-hono-spa for details.

import { createSpa } from '@scope/my-spa/spa';

const appHost = createAppHost<AppEnv>({
    basePath: 'api/',
    endpointGroups: [createSpa({ basePath: 'api' })],
});

src/server-host.ts

startServerHost(options) wraps Bun.serve() and registers SIGINT/SIGTERM handlers for graceful shutdown.

type ServerHostOptions = {
    port?: string | number;                              // default: 7200
    appHost: Hono<AppEnv>;
    stopCallback?: (server: Bun.Server<undefined>) => void;
}

On SIGINT or SIGTERM: calls stopCallback (if provided), stops the Bun server, then exits with code 0.

src/middleware/logging/

Logging(options)

Attaches a getLogFunction(scope?) factory to the request context as c.var.getLogFunction. Call it in any handler or middleware to get a scoped log function:

const log = c.var.getLogFunction('my-scope');
log(LogLevel.INFO, 'Processing request', { id });

Log output format: [<ISO timestamp>] [<requestId>] [<scope>] [<LEVEL>] <message>

Options:

type LoggingOptions = {
    logLevel: LogLevel;                          // global default level
    logLevelPerScope?: Record<string, LogLevel>; // per-scope overrides
}

LogLevel enum: NONE | ERROR | WARNING | INFO | TRACE

The template configures WARNING globally and TRACE for the request scope.

RequestLogger()

Logs <METHOD> <path>[?<query>] at TRACE level using the request scope. Applied after requestId and Logging so all three are available.

DevOps

# remove dist/ and tsconfig.build.tsbuildinfo
bun run clean

# remove dist/ only
bun run clean:dist

# remove tsconfig.build.tsbuildinfo only
bun run clean:tsbuildinfo

# compile + bundle
bun run build

# create a new test hono server in example/
bun run dist/cli.bundle.js -- example

Publish - see Publish.

Change Management

  1. Create a new branch for the change.
  2. Make the changes and commit.
  3. Bump the version in package.json.
  4. Add an entry for the new version in CHANGELOG.md.
  5. Pull request the branch.
  6. After merge, run bun run build - ensures artifacts are current before publish.
  7. Publish.

Publish

See the following sources to configure the target registry and authentication.

⚠️ Package Scope and the authentication for the target registry must be aligned.

npmjs.org

Publish to the public npm registry.

# authenticate
npm login
# publish
bun publish --registry https://registry.npmjs.org/ --access public

Custom registry

# placeholder:
    # <SCOPE_WITHOUT_AT: <SCOPE_WITHOUT_AT>
    # <REGISTRY_URL: <REGISTRY_URL>
    # <BUN_PUBLISH_AUTH_TOKEN: <BUN_PUBLISH_AUTH_TOKEN>

~/.bunfig.toml or bunfig.toml:

[install.scopes]
"<SCOPE_WITHOUT_AT>" = { url = "<REGISTRY_URL>", token = "$BUN_PUBLISH_AUTH_TOKEN" }
# authenticate
$env:BUN_PUBLISH_AUTH_TOKEN = "<BUN_PUBLISH_AUTH_TOKEN>"
# publish
bun publish