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

@rhino-ai/orchard9-expresstsx

v0.3.0

Published

A zero-configuration, production-ready server framework for TypeScript services

Downloads

5

Readme

🌲 Orchard9 Express TSX

A zero-configuration, production-ready server framework for TypeScript services.

npm version TypeScript License: MIT

Features

  • Zero-config startup - Just provide routes and go!
  • Batteries included - Database, Redis, WebSockets, Config, Logging - all ready to use
  • Production ready - Kubernetes health checks, metrics, and security best practices built-in
  • Fully typed - Complete TypeScript support with intelligent autocomplete
  • Extensible - Easily add custom middleware, routes, and services

Installation

npm install @rhino-ai/orchard9-expresstsx

Docker Installation

You can also use Docker to run the framework:

# Clone the repository

# Start development environment
npm run docker:dev

# Or build and start
npm run docker:dev:build

Quick Start

Create an app.ts file:

import { createApp } from '@rhino-ai/orchard9-expresstsx';
import userRoutes from './routes/users';

// That's it - everything is automatically configured from your config files!
const app = createApp({
  routes: [
    {
      path: '/api/users',
      router: userRoutes
    }
  ]
});

app.start().then(() => {
  app.logger.info('🚀 Application started successfully!');
});

Create a route in routes/users.ts:

import { Router, Request, Response } from '@rhino-ai/orchard9-expresstsx';

const router = Router();

router.get('/', async (req: Request, res: Response) => {
  const users = await req.db('users').select('*');
  return res.json(users);
});

export default router;

Create a default configuration in config/default.yaml:

app:
  name: my-awesome-service
  port: 3000

database:
  host: localhost
  port: 5432
  user: postgres
  password: postgres
  database: my_app

redis:
  host: localhost
  port: 6379

Start your application:

ts-node app.ts

Project Structure

We recommend the following project structure:

my-service/
├── config/
│   ├── default.yaml     # Default configuration
│   ├── development.yaml # Development overrides
│   └── production.yaml  # Production overrides
├── src/
│   ├── routes/          # Express route definitions
│   │   └── users.ts
│   ├── services/        # Business logic
│   │   └── user-service.ts
│   ├── websocket/       # WebSocket handlers
│   │   └── chat-handler.ts
│   ├── types/           # TypeScript type definitions
│   │   └── index.ts
│   └── app.ts           # Main application entry point
├── package.json
└── tsconfig.json

Core Concepts

The App Instance

The app instance provides unified access to all underlying services:

const app = createApp();

// Access database directly
const users = await app.db('users').select('*');

// Access Redis
await app.redis.set('key', 'value');

// Access logger
app.logger.info('Something happened');

// Access WebSocket server
app.websocket.broadcast('event', { data: 'message' });

// Access config
const dbConfig = app.config.get('database');

Request Extensions

Every request is automatically extended with core services:

router.get('/profile', async (req, res) => {
  // Request-scoped logger with request ID
  req.logger.info('Fetching profile');
  
  // Database access
  const user = await req.db('users').where('id', req.params.id).first();
  
  // Validation helpers
  const { valid, data, errors } = req.validate(user, userSchema);
  
  return res.json(user);
});

WebSockets

WebSocket support is built-in and easy to use:

import { createApp } from '@rhino-ai/orchard9-expresstsx';

const app = createApp({
  websocket: {
    handlers: [
      {
        event: 'chat.message',
        handler: (message, socket, metadata) => {
          // Handle the message
          app.websocket.broadcastToRoom('chat', 'chat.message', message.payload);
        }
      }
    ]
  }
});

// Client connection handler
app.websocket.onConnection((socket, req, metadata) => {
  app.logger.info(`Client connected: ${metadata.clientId}`);
  app.websocket.joinRoom('chat', metadata.clientId, socket, metadata);
});

Configuration

Configuration is automatically loaded from the config/ directory:

// Access configuration
const dbConfig = app.config.get('database');
const appName = app.config.get('app.name');

// Watch for configuration changes
app.config.onChange('database', (newValue, oldValue) => {
  app.logger.info('Database configuration changed');
});

Protobuf Support

Protocol Buffers are fully supported:

import { createApp } from '@rhino-ai/orchard9-expresstsx';

const app = createApp({
  protobuf: {
    schemaPath: './proto',
    handlers: [
      {
        messageType: 'UserMessage',
        handler: async (data, context) => {
          // Handle the protobuf message
          return { status: 'success' };
        }
      }
    ]
  }
});

// Later, serialize/deserialize messages
const userProto = await app.protobuf.loadSchema('user.proto');
const userType = app.protobuf.getType(userProto, 'User');
const buffer = app.protobuf.serialize(userType, { id: 1, name: 'John' });

API Reference

createApp(options?)

Creates and configures the application.

const app = createApp({
  // App configuration
  name: 'my-service',
  port: 3000,
  
  // Route configuration
  routes: [
    { path: '/api/users', router: userRoutes },
    { path: '/api/products', router: productRoutes }
  ],
  
  // Middleware configuration
  middleware: {
    before: [customMiddleware1, customMiddleware2],
    after: [customMiddleware3]
  },
  
  // WebSocket configuration
  websocket: {
    path: '/ws',
    handlers: [{
      event: 'message',
      handler: messageHandler
    }]
  },
  
  // Health check configuration
  health: {
    path: '/health',
    kubernetes: true,
    checks: [customHealthCheck]
  },
  
  // Protobuf configuration
  protobuf: {
    schemaPath: './proto',
    handlers: [{
      messageType: 'UserMessage',
      handler: userMessageHandler
    }]
  }
});

App Methods

  • app.start() - Starts the application
  • app.stop() - Gracefully stops the application
  • app.db - Access the database (Knex instance)
  • app.redis - Access the Redis client
  • app.logger - Access the logger
  • app.config - Access the configuration
  • app.websocket - Access the WebSocket server
  • app.events - Access the event bus
  • app.protobuf - Access the Protocol Buffers utilities
  • app.validation - Access the validation utilities

Examples

Complete Example with All Features

import { createApp, Router } from '@rhino-ai/orchard9-expresstsx';
import { z } from 'zod';

// Define routes
const userRouter = Router();

userRouter.get('/', async (req, res) => {
  const users = await req.db('users').select('*');
  return res.json(users);
});

userRouter.post('/', async (req, res) => {
  // Validation schema
  const userSchema = z.object({
    name: z.string().min(2),
    email: z.string().email()
  });
  
  // Validate request body
  const { valid, data, errors } = req.validate(req.body, userSchema);
  
  if (!valid) {
    return res.status(400).json({ errors });
  }
  
  // Insert into database with transaction
  const userId = await req.transaction(async (trx) => {
    const [id] = await trx('users').insert(data).returning('id');
    await trx('user_logs').insert({ user_id: id, action: 'created' });
    return id;
  });
  
  // Publish event
  req.events.publish('user.created', { id: userId, name: data.name });
  
  return res.status(201).json({ id: userId });
});

// WebSocket handlers
const chatHandler = (message, socket, metadata) => {
  req.logger.info({ userId: metadata.user?.id }, 'Chat message received');
  req.websocket.broadcastToRoom('chat', 'message', message.payload);
};

// Create the application
const app = createApp({
  name: 'example-service',
  port: 3000,
  
  // Mount routes
  routes: [
    { path: '/api/users', router: userRouter }
  ],
  
  // Configure WebSockets
  websocket: {
    path: '/ws',
    handlers: [
      { event: 'chat.message', handler: chatHandler }
    ]
  }
});

// Start the application
app.start().then(() => {
  app.logger.info(`🚀 ${app.config.get('app.name')} started on port ${app.config.get('app.port')}`);
});

Testing

For detailed information about testing, please see TESTING.md.

Docker Support

Orchard9 Express TSX comes with full Docker support for both development and production environments.

Development Environment

# Start development environment
npm run docker:dev

# Build and start development environment
npm run docker:dev:build

# Run all tests (uses Docker)
npm test

# Stop containers
npm run docker:down

# Remove containers and volumes
npm run docker:clean

The development environment includes:

  • Node.js application container with hot reloading
  • PostgreSQL database
  • Redis cache
  • pgAdmin for database management (http://localhost:5050)
  • Redis Commander for Redis inspection (http://localhost:8081)

Production Environment

# Build and start production environment
npm run docker:prod

# Build production Docker image
npm run docker:build

The production environment:

  • Uses multi-stage builds for smaller images
  • Includes health checks for all services
  • Configures resource limits for containers
  • Supports environment variable configuration
  • Implements security best practices

Environment Variables

You can customize the Docker environment by creating a .env file based on the provided .env.example:

# Copy example environment file
cp .env.example .env

# Edit environment variables
nano .env

# Start with custom environment
npm run docker:dev

License

MIT