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

@rolster/invertly

v4.3.1

Published

Invertly is a package that allows you to implement class mapping to identify and inject their dependencies.

Readme

Rolster Invertly

Invertly is a package that allows you to implement class mapping to identify and inject their dependencies.

Installation

npm i @rolster/invertly

Configuration

You must install the @rolster/types to define package data types, which are configured by adding them to the files property of the tsconfig.json file. Decorators require the emitDecoratorMetadata and experimentalDecorators compiler options.

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  },
  "files": ["node_modules/@rolster/types/index.d.ts"]
}

Overview

Invertly is a lightweight dependency injection container. You mark classes as injectable, and Invertly builds them for you — resolving each constructor argument automatically from TypeScript's emitted type metadata. It supports three instance lifetimes, binding abstractions to implementations, per-request contexts, and fully isolated containers.

Import reflect-metadata once at your application entry point, before any decorated class is loaded.

Declaring injectables

Decorate a class with @Injectable() to register it. Constructor dependencies are resolved by their declared type — no extra wiring needed for concrete classes:

import 'reflect-metadata';
import { Injectable, invertly } from '@rolster/invertly';

@Injectable()
class Logger {
  log(message: string): void {
    console.log(message);
  }
}

@Injectable({ singleton: true })
class UserService {
  constructor(private readonly logger: Logger) {}

  create(name: string): void {
    this.logger.log(`User created: ${name}`);
  }
}

// Resolve the whole dependency tree
const service = invertly(UserService);
service.create('Daniel'); // "User created: Daniel"

@Injectable(options?) accepts:

| Option | Default | Meaning | | ------------- | ------- | -------------------------------------------------------- | | singleton | false | A single instance shared across the whole container. | | scopeable | false | A single instance shared within one resolution tree. |

When neither is set, a brand-new instance is created on every resolution.

Resolving instances

| Function | Use | | ------------------------------------- | --------------------------------------------------------- | | invertly(token, container?) | Resolve an injectable by token. | | createFromInvertly({ token, context? }, container?) | Resolve, optionally passing a Context. |

const service = invertly(UserService);

Injection lifetimes per parameter

When you need to control the lifetime of a specific dependency (or inject by a token that isn't its concrete type), use the parameter decorators:

import { Injectable, Singleton, Scope, Factory } from '@rolster/invertly';

@Injectable()
class OrderController {
  constructor(
    @Singleton(Database) private readonly db: Database, // shared everywhere
    @Scope(UnitOfWork) private readonly uow: UnitOfWork, // shared per request
    @Factory(Clock) private readonly clock: Clock // new every time
  ) {}
}

| Decorator | Lifetime | | -------------------- | ----------------------------------------------------- | | @Singleton(token) | One instance for the entire container. | | @Scope(token) | One instance per resolution tree (request scope). | | @Factory(token) | A fresh instance for each injection. |

Binding abstractions to implementations

The locator maps an abstract token (an abstract class, string or symbol) to a concrete useClass. This lets you depend on an abstraction and swap the implementation in one place:

import { Injectable, saveInLocator, invertly } from '@rolster/invertly';

abstract class UserRepository {
  abstract findAll(): User[];
}

@Injectable()
class SqlUserRepository extends UserRepository {
  findAll(): User[] {
    return [];
  }
}

// Bind the abstraction to its implementation (as a singleton)
saveInLocator([
  { token: UserRepository, useClass: SqlUserRepository, singleton: true }
]);

@Injectable({ singleton: true })
class UserService {
  // Resolves to SqlUserRepository through the locator
  constructor(private readonly repository: UserRepository) {}
}

invertly(UserService);

Helpers: saveInLocator(options[]) registers several bindings at once, pushInLocator(token, useClass) adds a single one, and findInLocator(token) looks one up. A LocatorOptions is { token, useClass, scopeable?, singleton? }.

Per-request context

Context is a key/value bag you can hand to the resolver and have injected into any constructor. It's the basis for per-request state in server frameworks (e.g. @rolster/coopplins-server, @rolster/messenger-service).

import { Injectable, Context, createFromInvertly } from '@rolster/invertly';

@Injectable()
class RequestHandler {
  constructor(private readonly context: Context) {}

  currentUser(): string {
    return this.context.findByKey('userId');
  }
}

const context = new Context();
context.save('userId', '42');

const handler = createFromInvertly({ token: RequestHandler, context });
handler.currentUser(); // '42'

Context API: save(key, value), findByKey(key), findOrNullByKey(key), contain(key).

Isolated containers

By default everything lives in a global container. Create an InvertlyContainer to get a fully isolated registry (useful for tests or multi-tenant setups):

import { InvertlyContainer, invertly } from '@rolster/invertly';

const container = new InvertlyContainer();

container.registerInjectable({
  token: UserService,
  singleton: true,
  scopeable: false
});

const service = container.createInjectable({ token: UserService });
// or: invertly(UserService, container);

Programmatic registration

When you can't (or don't want to) use decorators, register everything by hand:

import { registerDependency } from '@rolster/invertly';

registerDependency(UserService, {
  singleton: true,
  injects: [{ token: Logger }] // constructor dependencies, in order
});

Lower-level primitives registerInjectable(options, container?) and registerInject(options, container?) are also exported (they back both the decorators and registerDependency).

Contributing

  • Daniel Andrés Castillo Pedroza :rocket: