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

@kayahr/cdi

v0.3.0

Published

Simple generic dependency injection library

Readme

CDI - Context and Dependency Injection

GitHub | NPM | API Doc

Simple generic dependency injection library written in TypeScript (but also works with plain JavaScript).

Some features:

  • Allows registering and injecting every kind of data, from simple strings to singleton services.
  • Supports injecting functions with a mix of dependency parameters and pass-through parameters.
  • Supports asynchronous dependency resolving.
  • Supports constructor and factory method/function injection.
  • Supports new proposed ECMAScript decorators but also works without decorators.
  • Supports sub dependency injection contexts.
  • Supports singleton and prototype injection scopes.
  • Supports dependency qualifiers to allow dependency resolving by name for interfaces or primitive values or for selecting the correct dependency when multiple compatible dependencies exist.
  • Very small footprint. Library has no dependencies and size of minimized code is around 3 KB.

There are some features which are intentionally not supported:

  • No support for legacy (experimental) TypeScript decorators. Even though these decorators are currently more powerful then the new standard decorators, they have no future so new software should not use them.
  • No support for property and setter method dependency injection. This kind of injection is a bad practice because it can create inconsistent object states.

Usage

Install the library as a dependency in your project:

npm install @kayahr/cdi

When using decorators then a typical simple use case can look like this:

import { Context, injectable } from "@kayahr/cdi";

@injectable
export class MathService {
    public add(a: number, b: number): number {
        return a + b;
    }
}

@injectable({ inject: [ MathService ] })
export class Component {
    public constructor(
        private readonly mathService: MathService
    ) {}

    public run(): void {
        console.log(this.mathService.add(1, 2));
    }
}

// Boot strap
const context = Context.getActive();
context.getSync(Component).run();

This registers a MathService singleton in the active dependency injection context and a Component class which depends on it. Then in the boot strap code it fetches the singleton instance of Component from the context and runs it.

Note that the types of dependencies must explicitly be specified in the injectable decorator (only if there are dependencies). This is because up to now the new ECMAScript decorators have no support for type reflection metadata or parameter decorators. As soon as this changes, the inject option will become optional.

You may wonder why context.getSync() is used instead of context.get(). This is because all dependencies can be asynchronous (more on that later), so get may return a Promise and the boot strap code would need to handle this. getSync on the other hand always returns a synchronous value and throws an error when an asynchronous dependency has been encountered. So when you know that all involved dependencies are synchronous then getSync is easier to use. There is also a getAsync method which always returns a promise, if you prefer this.

Usage without decorators

Instead of using decorators you can also fetch the active dependency injection context and add the classes manually:

import { Context } from "@kayahr/cdi";

const context = Context.getActive();

export class MathService {
    public add(a: number, b: number): number {
        return a + b;
    }
}
context.setClass(MathService);

export class Component {
    public constructor(
        private readonly mathService: MathService
    ) {}

    public run(): void {
        console.log(this.mathService.add(1, 2));
    }
}
context.setClass(Component, { inject: [ MathService ] });

// Boot strap
context.getSync(Component).run();

The injectable decorator internally uses the same methods which you can also use manually, like in this example, so the functionality is identical.

See also