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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@reono/node-server

v1.0.9

Published

A Node.js server adapter for **Reono** that enables you to run your JSX-defined API routes on Node.js HTTP servers. This package provides a simple interface to convert Reono applications into Node.js HTTP handlers.

Readme

@reono/node-server

A Node.js server adapter for Reono that enables you to run your JSX-defined API routes on Node.js HTTP servers. This package provides a simple interface to convert Reono applications into Node.js HTTP handlers.

Overview

The @reono/node-server package:

  • Node.js Integration: Converts Node.js IncomingMessage to Web API Request objects
  • Response Handling: Transforms Web API Response objects back to Node.js HTTP responses
  • Simple API: Provides a clean, minimal interface for serving Reono applications
  • Error Handling: Built-in error handling for unhandled exceptions
  • Streaming Support: Handles request/response streaming efficiently

Installation

npm install @reono/node-server reono
# or
pnpm add @reono/node-server reono
# or
yarn add @reono/node-server reono

Basic Usage

import { createApp } from "@reono/node-server";

const App = () => (
  <router path="api">
    <get path="hello" handler={(c) => c.json({ message: "Hello, World!" })} />
    <get path="users/:id" handler={(c) => c.json({ id: c.params.id })} />
  </router>
);

const app = createApp();

// Register your Reono JSX app
app.serve(<App />);

// Start the HTTP server
app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

API Reference

createApp()

Creates a new Reono application instance for Node.js.

const app = createApp();

Returns: An application instance with the following methods:

app.serve(element: JSXElement)

Registers a Reono JSX element tree as the application handler.

app.serve(<App />);

Parameters:

  • element: JSXElement - The root JSX element of your Reono application

Note: This method must be called before listen().

app.listen(port: number, callback?: () => void)

Starts the HTTP server on the specified port.

app.listen(3000, () => {
  console.log("Server started!");
});

Parameters:

  • port: number - The port number to listen on
  • callback?: () => void - Optional callback executed when the server starts

Throws: Error if serve() hasn't been called first.

app.close(callback?: (err?: Error) => void)

Stops the HTTP server.

app.close((err) => {
  if (err) console.error("Error closing server:", err);
  else console.log("Server closed");
});

Parameters:

  • callback?: (err?: Error) => void - Optional callback executed when the server closes

Complete Example

// server.tsx
import { createApp } from "@reono/node-server";
import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});

// Mock data store
let users = [
  { id: 1, name: "Alice", email: "[email protected]" },
  { id: 2, name: "Bob", email: "[email protected]" },
];

const logger = (c, next) => {
  console.log(`${new Date().toISOString()} ${c.req.method} ${c.req.url}`);
  return next();
};

const App = () => (
  <use handler={logger}>
    <router path="api/v1">
      <router path="users">
        {/* GET /api/v1/users */}
        <get path="" handler={(c) => c.json(users)} />

        {/* POST /api/v1/users */}
        <post
          path=""
          validate={{ body: userSchema }}
          handler={(c) => {
            const newUser = { id: Date.now(), ...c.body };
            users.push(newUser);
            return c.json(newUser, 201);
          }}
        />

        {/* GET /api/v1/users/:id */}
        <get
          path=":id"
          validate={{ params: z.object({ id: z.coerce.number() }) }}
          handler={(c) => {
            const user = users.find((u) => u.id === c.params.id);
            if (!user) {
              return new Response("User not found", { status: 404 });
            }
            return c.json(user);
          }}
        />

        {/* PUT /api/v1/users/:id */}
        <put
          path=":id"
          validate={{
            params: z.object({ id: z.coerce.number() }),
            body: userSchema,
          }}
          handler={(c) => {
            const index = users.findIndex((u) => u.id === c.params.id);
            if (index === -1) {
              return new Response("User not found", { status: 404 });
            }
            users[index] = { id: c.params.id, ...c.body };
            return c.json(users[index]);
          }}
        />

        {/* DELETE /api/v1/users/:id */}
        <delete
          path=":id"
          validate={{ params: z.object({ id: z.coerce.number() }) }}
          handler={(c) => {
            const index = users.findIndex((u) => u.id === c.params.id);
            if (index === -1) {
              return new Response("User not found", { status: 404 });
            }
            users.splice(index, 1);
            return new Response("", { status: 204 });
          }}
        />
      </router>
    </router>
  </use>
);

const app = createApp();
app.serve(<App />);

const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;

app.listen(PORT, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}`);
  console.log(`📚 API available at http://localhost:${PORT}/api/v1/users`);
});

// Graceful shutdown
process.on("SIGINT", () => {
  console.log("\n🛑 Shutting down server...");
  app.close(() => {
    console.log("✅ Server closed");
    process.exit(0);
  });
});

Environment Setup

TypeScript Configuration

Make sure your tsconfig.json is configured for Reono:

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "jsx": "react-jsx",
    "jsxImportSource": "reono",
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Package.json Scripts

{
  "scripts": {
    "dev": "tsx watch src/server.tsx",
    "start": "node dist/server.js",
    "build": "tsc && node dist/server.js"
  },
  "dependencies": {
    "@reono/node-server": "^1.0.0",
    "reono": "^1.0.0"
  },
  "devDependencies": {
    "tsx": "^4.0.0",
    "typescript": "^5.0.0"
  }
}

Development vs Production

Development

Use tsx for development with hot reloading:

npx tsx watch src/server.tsx

Production

Compile TypeScript and run the compiled JavaScript:

tsc
node dist/server.js

Error Handling

The node-server package includes built-in error handling:

  • Unhandled Errors: Automatically caught and converted to 500 responses
  • Request Processing: Errors during request/response conversion are handled gracefully
  • Validation Errors: Reono's validation errors are properly formatted as 400 responses

For custom error handling, implement it in your route handlers or middleware:

const errorHandler = async (c, next) => {
  try {
    return await next();
  } catch (error) {
    console.error("Route error:", error);
    return c.json({ error: "Something went wrong" }, 500);
  }
};

const App = () => <use handler={errorHandler}>{/* Your routes */}</use>;

Request/Response Conversion

The package handles conversion between Node.js and Web API standards:

Request Conversion

  • Converts Node.js IncomingMessage to Web API Request
  • Handles headers, method, URL, and body streaming
  • Supports both HTTP and HTTPS
  • Automatically detects protocol from socket encryption

Response Conversion

  • Converts Web API Response to Node.js HTTP response
  • Transfers status, headers, and body
  • Handles streaming and buffering appropriately
  • Sets appropriate Content-Length headers

Performance Considerations

  • Streaming: Request bodies are streamed using Node.js streams converted to Web streams
  • Memory: Response bodies are currently buffered for simplicity (streaming support planned)
  • Headers: Efficient header conversion between Node.js and Web API formats
  • Error Handling: Minimal performance impact from error boundaries

Compatibility

  • Node.js: Requires Node.js 18+ (for Web API support)
  • TypeScript: Full TypeScript support with comprehensive type definitions
  • ESM/CJS: Supports both ES modules and CommonJS
  • Reono: Compatible with all Reono core features

Deployment

Docker

FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY dist/ ./dist/
EXPOSE 3000

CMD ["node", "dist/server.js"]

Environment Variables

PORT=3000
NODE_ENV=production

License

ISC

Contributing

This package is part of the experimental Reono ecosystem. Contributions and feedback are welcome!