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

athlete-core

v0.8.0

Published

Lightweight DI container for js/ts

Readme

Athlete

A minimal, security-first dependency injection framework.

Zero dependencies. No decorators. No string tokens. Fully auditable.

npm version License: MIT

Why Athlete?

Modern frameworks come with hundreds of dependencies, creating security risks through supply chain attacks. Athlete takes a different approach:

  • 🔒 Zero Dependencies - No hidden vulnerabilities in your dependency tree
  • 📦 Minimal Size - ~300 lines of code, easily auditable in 10 minutes
  • 🚫 No Magic - No decorators, no reflection, no string tokens
  • ✅ Type-Safe - Full TypeScript support without compromises
  • 🔍 Transparent - Every line of code can be reviewed and understood

Perfect for security-critical projects where code transparency matters: tools for journalists, platforms for activists, applications for NGOs.

Installation

npm install athlete-core

Quick Start

import { Athlete } from "athlete-core";

class UserService {
  getUser(id: string) {
    return { id, name: "Alice" };
  }
}

class AuthService {
  constructor(private userService: UserService) {}

  authenticate(userId: string) {
    const user = this.userService.getUser(userId);
    return { user, token: "..." };
  }
}

const container = Athlete().inject(UserService).inject(AuthService, [UserService]).buildContainer();

const auth = container.resolveInstance(AuthService);

Core Concepts

Dependency Injection Without Decorators

Unlike NestJS or InversifyJS, Athlete doesn't use decorators or metadata. Dependencies are explicit:

// ❌ Other frameworks - hidden dependencies via decorators
@Injectable()
class Service {
  constructor(@Inject("TOKEN") private dep: Dependency) {}
}

// ✅ Athlete - explicit, type-safe dependencies
class Service {
  constructor(readonly dep: Dependency) {}
}

Athlete().inject(Service, [Dependency]);

Framework API

interface IFramework {
  inject<T>(token: Token<T, []>): IFramework;
  inject<T, A extends any[]>(token: Token<T, A>, dependencies: Dependencies<A>): IFramework;
  injectFactory<T>(token: Token<T, []>): IFramework;
  injectFactory<T, A extends any[]>(token: Token<T, A>, dependencies: Dependencies<A>): IFramework;
  injectModule<T extends IModule>(token: Token<T, []>): IFramework;
  injectModule<T extends IModule, A extends any[]>(token: Token<T, A>, dependencies: Dependencies<A>): IFramework;
  buildContainer(): IСontainer;
}

Container API

interface IСontainer {
  resolveInstance<T>(token: Token<T>): T;
  executeCommand<T extends ICommand>(token: Token<T, []>): IСontainer;
  executeCommand<T extends ICommand, A extends any[]>(token: Token<T, A>, dependencies: Dependencies<A>): IСontainer;
  getInfo(): IInfo;
}

Usage Examples

Singleton Injection

class DatabaseConnection {}
class UserRepository {
  constructor(readonly db: DatabaseConnection) {}
}

const container = Athlete().inject(DatabaseConnection).inject(UserRepository, [DatabaseConnection]).buildContainer();

const repo = container.resolveInstance(UserRepository);

Factory Injection

Create new instances for each injection:

class Logger {
  log(message: string) {
    console.log(`[${new Date().toISOString()}] ${message}`);
  }
}

class ServiceA {
  constructor(readonly logger: Logger) {}
}

class ServiceB {
  constructor(readonly logger: Logger) {}
}

Athlete()
  .inject(ServiceA, [Logger])
  .inject(ServiceB, [Logger])
  .injectFactory(Logger) // New Logger instance for each service
  .buildContainer();

Modular Architecture

import type { IModule } from "athlete-core";
...

class DatabaseModule implements IModule {
  readonly DB_TOKEN = DatabaseConnection;
  readonly REPO_TOKEN = UserRepository;

  export(framework: IFramework): void {
    framework.inject(this.DB_TOKEN).inject(this.REPO_TOKEN, [this.DB_TOKEN]);
  }
}

class AuthModule implements IModule {
  constructor(readonly dbModule: DatabaseModule) {}

  readonly AUTH_TOKEN = AuthService;

  export(framework: IFramework): void {
    framework.inject(this.AUTH_TOKEN, [this.dbModule.REPO_TOKEN]);
  }
}

const container = Athlete().injectModule(DatabaseModule).injectModule(AuthModule, [DatabaseModule]).buildContainer();

Primitive Values

Inject configuration or primitives:

class ApiClient {
  constructor(readonly baseUrl: string, readonly timeout: number, readonly config: object) {}
}

Athlete().inject(ApiClient, [
  ["https://api.example.com"], // Wrap primitives in tuples
  [5000],
  [{ retries: 3 }],
]);

Container Injection

Inject the container itself for dynamic resolution:

import { CONTAINER_TOKEN } from "athlete-core";

class ServiceFactory {
  constructor(readonly container: IСontainer) {}

  createService(type: string) {
    switch (type) {
      case "user":
        return this.container.resolveInstance(UserService);
      case "auth":
        return this.container.resolveInstance(AuthService);
    }
  }
}

Athlete().inject(ServiceFactory, [CONTAINER_TOKEN]);

Commands

Execute initialization logic after container creation:

import type { ICommand } from "athlete-core";
...

class StartServer implements ICommand {
  constructor(readonly app: Application) {}

  execute(container: IСontainer): void {
    this.app.listen(3000);
    console.log("Server started");
  }
}

Athlete().inject(Application).buildContainer().executeCommand(StartServer, [Application]);

Security Audit Guide

Athlete's simplicity makes security auditing straightforward:

  1. Review the source - ~300 lines
  2. Check dependencies - package.json has ZERO runtime dependencies
  3. Verify types - All dependencies are explicitly declared
  4. Test isolation - No global state, no prototype pollution

Time required: ~10 minutes for a complete audit.

Compare to:

  • Express: 500+ transitive dependencies
  • NestJS: 1000+ transitive dependencies
  • Athlete: 0 dependencies

Comparison

| Feature | Athlete | NestJS | InversifyJS | | ------------------- | ------- | ------ | ----------- | | Dependencies | 0 | 1000+ | 50+ | | Bundle Size | ~5KB | ~1MB | ~100KB | | Decorators Required | ❌ | ✅ | ✅ | | Reflect Metadata | ❌ | ✅ | ✅ | | Type Safety | ✅ | ✅ | ✅ | | Audit Time | 10 min | Days | Hours |

Ecosystem

Athlete is designed to be the foundation of a larger ecosystem:

  • athlete-core - DI framework (this package)
  • athlete-json-validation - Runtime validation
  • athlete-http - HTTP server (coming soon)
  • athlete-router - Routing for HTTP/WebSocket (coming soon)
  • athlete-plugins - Middleware alternative (coming soon)

Philosophy

  1. Security through simplicity - Fewer lines = fewer bugs
  2. Transparency over magic - Explicit is better than implicit
  3. No hidden dependencies - Supply chain security matters
  4. Framework, not library - Opinionated but flexible

Use Cases

Athlete is ideal for:

  • 🔐 Security-critical applications - Financial services, healthcare, government
  • 📰 Journalism tools - Secure communication platforms
  • 🎯 Activist platforms - Privacy-focused applications
  • 🏢 NGO projects - Resource-constrained organizations
  • 🎓 Educational projects - Learning DI without complexity

Contributing

Contributions welcome! Please read our contributing guidelines first.

License

MIT © Denis Ardyshev

Links


Enjoy programming without the bloat! 🚀