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

ndulojs

v1.0.9

Published

A TypeScript backend framework that enforces good architecture from day one

Readme

ndulojs

An opinionated TypeScript backend framework built on Elysia.

NduloJS enforces Clean Architecture structurally — dependency injection, explicit error handling, and layered modules — so your codebase stays consistent as it grows.


Features

  • Result pattern — no try/catch. Errors are typed values: Result<T, AppError>
  • DI container — functional, type-safe, zero decorators
  • HTTP adapter — Elysia under the hood, abstracted behind a clean interface
  • Structured logger — three channels (app, http, error) with daily rotation
  • CLI — scaffold modules, submodules, and full projects in seconds

Install

# New project
npx ndulojs-cli create my-app
cd my-app && bun install && bun dev

# Existing project
bun add ndulojs

Quick start

import { createApp, createContainer, Ok, Err, ErrorFactory } from 'ndulojs';

const app = await createApp({ port: 3000 });

app.get('/health', () => Ok({ status: 'ok' }));

app.listen(3000);

Result pattern

Handlers return Ok(value) or Err(error). The framework maps errors to HTTP status codes automatically — no middleware needed.

app.get('/users/:id', async ({ params }) => {
  const user = await db.findById(params.id);
  if (!user) return Err(ErrorFactory.notFound('User not found', 'User', params.id));
  return Ok(user);
});

| Error type | Status | |---|---| | notFound | 404 | | unauthorized | 401 | | forbidden | 403 | | validation | 422 | | conflict | 409 | | business | 400 | | database | 500 | | externalService | 502 | | tooManyRequests | 429 |


Dependency injection

import { createContainer } from 'ndulojs';

const container = createContainer()
  .register('Config',         ()  => loadConfig())
  .register('Database',       (c) => createDatabase(c.resolve('Config')))
  .register('UserRepository', (c) => createUserRepository(c.resolve('Database')))
  .register('UserService',    (c) => createUserService(c.resolve('UserRepository')));

const userService = container.resolve('UserService');
  • Singleton by default
  • Scoped and transient scopes available
  • Circular dependency detection with a clear error message

CLI

# New project
npx ndulojs-cli create my-app

# Generate a module
ndulo generate module farms

# Generate a submodule
ndulo generate module farms --sub members

# Add a single file to an existing module
ndulo add controller farms
ndulo add service farms

generate module creates the full Clean Architecture structure:

src/modules/farms/
├── events/farm.events.ts
├── application/
│   ├── dtos/farm.dto.ts
│   ├── ports/farm.port.ts
│   └── services/farm.service.ts
└── infrastructure/
    ├── persistence/farm.repository.ts
    └── http/controllers/farm.controller.ts

Logger

import { createLogger } from 'ndulojs';

const logger = createLogger({ pretty: true });        // dev
const logger = createLogger({ dir: 'logs', retainDays: 30 }); // prod

logger.app.info('Server started');
logger.http.info({ method: 'GET', path: '/users', status: 200 }, 'Request');
logger.error.error({ err }, 'Unhandled exception');

// Per-request context
const log = logger.context({ requestId, userId });
log.app.info('Processing request');

Project structure

src/
├── modules/
│   └── {module}/
│       ├── events/
│       ├── application/
│       │   ├── dtos/
│       │   ├── ports/
│       │   └── services/
│       └── infrastructure/
│           ├── persistence/
│           └── http/controllers/
└── index.ts

Documentation


Contributing

See CONTRIBUTING.md.


License

MIT