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

@venizia/ignis-inversion

v0.4.0

Published

Lightweight, high-performance Dependency Injection and Inversion of Control container for TypeScript (~350 lines). Features decorator-based constructor and property injection, fluent Binding API, singleton/transient scoping, namespace auto-tagging, Provid

Readme

@venizia/ignis-inversion

The dependency injection container under IGNIS, and the error type every IGNIS package throws. It depends on no other IGNIS package, so you can install it alone to get LoopBack 4-style bindings without the framework.

Install

bun add @venizia/ignis-inversion

reflect-metadata comes as a dependency, and the package entry imports it. Your tsconfig.json must declare experimentalDecorators: true itself (see Decorators).

Use it

Bind values and classes under string keys, then ask the container for a key.

import { BindingScopes, Container, inject } from '@venizia/ignis-inversion';

class GreetingService {
  constructor(
    @inject({ key: 'config.prefix' }) private readonly prefix: string,
    @inject({ key: 'config.locale', isOptional: true }) private readonly locale?: string,
  ) {}

  greet(name: string) {
    return `${this.prefix} ${name} (${this.locale ?? 'en'})`;
  }
}

const container = new Container();

container.bind({ key: 'config.prefix' }).toValue('Hello');
container
  .bind({ key: 'services.GreetingService' })
  .toClass(GreetingService)
  .setScope(BindingScopes.SINGLETON);

const service = container.get<GreetingService>({ key: 'services.GreetingService' });
console.log(service.greet('IGNIS')); // Hello IGNIS (en)

// The first segment of a dotted key becomes a tag.
container.findByTag({ tag: 'services' }); // [the 'services.GreetingService' binding]

Notice that config.locale is never bound. isOptional: true makes it resolve to undefined instead of throwing.

API

Every method takes an options object: container.get({ key }), never container.get(key).

| Container member | What it does | | :--- | :--- | | bind<T>({ key }) | Creates and registers a Binding, returned for chaining | | get<T>({ key, isOptional }) | Resolves a key. Throws when the key is unbound, unless isOptional is true. key may also be { namespace, key } | | gets({ bindings }) | Resolves several keys; every entry is optional | | getBinding({ key }), isBound({ key }), unbind({ key }), set({ binding }) | Read, test, remove, or register a Binding | | instantiate(cls) / resolve(cls) | Builds a class from its @inject metadata without binding it | | findByTag({ tag, exclude }) | Every binding with a tag; exclude takes an array or a Set of keys | | clear() / reset() | Drops cached singletons / drops every binding | | startResolutionCounting(), getResolutionCounts(), stopResolutionCounting() | Counts how often each key is resolved, off by default |

| Binding member | What it does | | :--- | :--- | | toValue(value) | Returns the value as-is | | toClass(Class) | Instantiates the class through the container | | toProvider(factory) | Calls (container) => T, or instantiates a class with a value(container) method | | setScope(scope) | BindingScopes.TRANSIENT (default) or BindingScopes.SINGLETON | | setTags(...tags), hasTag(tag), getTags() | Tags for findByTag | | clearCache() | Discards the cached singleton |

AbstractContainer (the contract) and BaseContainer (the storage) are exported for custom containers. BindingKeys.build({ namespace, key }) joins a namespace and a key with a dot.

Decorators

@inject marks a constructor parameter or a property. Pass a key, or a target class to resolve through the key that class was registered under.

| Option | Type | Meaning | | :--- | :--- | :--- | | key | string \| symbol | The binding key to resolve | | target | class, or a function returning one | Resolve the class's recorded key. The function form survives an import cycle | | isOptional | boolean | Resolve an unbound key to undefined instead of throwing |

Constructor parameters resolve before construction. Properties are assigned after it.

[!IMPORTANT] Declare experimentalDecorators: true in your own tsconfig.json, not only through extends. Bun can miss an inherited flag when it runs source, and then drops parameter decorators with no error. emitDecoratorMetadata is not needed: @inject records the parameter index itself.

Decorate every constructor parameter of a class the container builds. An undecorated parameter before a decorated one is refused with Constructor parameter N has no @inject. An undecorated trailing parameter receives undefined.

Errors

The package also holds the error type the whole framework throws.

import { getError, isApplicationError } from '@venizia/ignis-inversion';

try {
  throw getError({
    message: { text: 'User not found', code: 'user.not_found', args: { id: 42 } },
    statusCode: 404,
  });
} catch (error) {
  if (isApplicationError(error)) {
    console.log(error.statusCode, error.normalized); // 404 { text, code, args }
  }
}

getError returns an ApplicationError, an Error subclass. It carries statusCode (default 400), normalized ({ text, code, args }) and an optional extra bag. A bare string message becomes text. A missing code becomes MessageCode.DEFAULT (core.system_error). Unknown top-level keys go into extra.

Test with isApplicationError(error), not instanceof ApplicationError. A CommonJS copy and an ES module copy of the package can both be loaded, and instanceof fails across them.

Entry points

| Entry point | What it gives | Extra peers | | :--- | :--- | :--- | | @venizia/ignis-inversion | Everything: container, bindings, @inject, MetadataRegistry, errors | none |

The package ships both CommonJS (dist/cjs) and ES modules (dist/esm). import resolves the ES build, require the CommonJS one. The ES build is what a browser bundle takes.

Where it sits

Depends on nothing in IGNIS. Used by filter, helpers and kernel: dev-configs -> inversion -> {filter, helpers} -> {boot, kernel} -> connectors -> {core-worker, core-server}.

Links

MIT licensed - see LICENSE.md.