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

@veren/di

v0.0.0

Published

A starter for creating a TypeScript package.

Readme

@veren/di

@veren/di is a small dependency injection container with:

  • InjectionToken for non-class dependencies
  • @Injectable() for auto-provided classes
  • Injector and EnvironmentInjector for provider resolution and lifecycle
  • inject() and runInInjectionContext() for functional injection
  • reflect-metadata based constructor type inference for class dependencies
  • forwardRef() for deferred token references
  • @Inject(), @Optional(), @Self(), @SkipSelf(), and @Host() parameter metadata helpers

Install

vp add @veren/di

Quick Start

import {
  EnvironmentInjector,
  Inject,
  Injectable,
  InjectionToken,
  Injector,
  inject,
  runInInjectionContext,
} from "@veren/di";

const API_URL = new InjectionToken<string>("API_URL", {
  factory: () => "https://example.com/api",
});

class HttpClient {
  constructor(@Inject(API_URL) readonly baseUrl: string) {}
}

@Injectable({ providedIn: "root" })
class UserService {
  readonly apiUrl = inject(API_URL);

  constructor(@Inject(HttpClient) readonly http: HttpClient) {}
}

const injector = Injector.create({
  providers: [HttpClient],
});

const userService = injector.get(UserService);
const apiUrl = runInInjectionContext(injector as EnvironmentInjector, () => inject(API_URL));

Core Concepts

Tokens

Classes can be used directly as tokens. For non-class dependencies, prefer InjectionToken<T>:

const CONFIG = new InjectionToken<{ baseUrl: string }>("CONFIG");

An InjectionToken can also declare a default factory:

const REQUEST_ID = new InjectionToken("REQUEST_ID", {
  providedIn: "any",
  factory: () => crypto.randomUUID(),
});

Injectable

@Injectable() registers an InjectableDef so the container can auto-create the class:

@Injectable({ providedIn: "root" })
class Logger {}

Supported providedIn values:

  • "root": one shared instance from the root injector
  • "platform": currently behaves the same as "root"
  • "any": one cached instance per injector
  • null or omitted: not auto-provided, must be registered manually

Providers

Supported provider forms:

Injector.create({
  providers: [
    ServiceClass,
    { provide: TOKEN, useValue: 123 },
    { provide: TOKEN, useExisting: OTHER_TOKEN },
    { provide: TOKEN, useFactory: () => createValue(), deps: [DepA, DepB] },
    { provide: TOKEN, useClass: ServiceImpl, deps: [DepA] },
    { provide: ServiceClass, deps: [DepA, DepB] },
    { provide: HOOKS, useValue: "a", multi: true },
    { provide: HOOKS, useValue: "b", multi: true },
  ],
});

multi: true aggregates all providers for the same token into an array.

Constructor Injection

Class dependencies can be inferred from runtime metadata when the class is decorated and TypeScript emits design:paramtypes:

@Injectable()
class Logger {}

@Injectable()
class ApiClient {
  constructor(readonly logger: Logger) {}
}

@Inject(...) still has higher priority and should be used for non-class dependencies, primitives, interfaces, or when you want to override reflected types:

class ApiClient {
  constructor(@Inject(API_URL) readonly url: string) {}
}

You can also skip class metadata and declare deps on the provider directly:

{
  provide: ApiClient,
  useClass: ApiClient,
  deps: [API_URL],
}

Resolution Flags

Both parameter decorators and deps arrays support these flags:

  • Optional: return null when the dependency is missing
  • Self: only search the current injector
  • SkipSelf: start searching from the parent injector
  • Host: currently recorded as a flag, with no special resolution behavior

Example with deps markers:

{
  provide: TOKEN,
  useFactory: (local, parent, fallback) => ({ local, parent, fallback }),
  deps: [
    [LOCAL_TOKEN, Self],
    [PARENT_TOKEN, SkipSelf],
    [MISSING_TOKEN, Optional],
  ],
}

Functional Injection

Use inject() inside an active injection context:

const injector = Injector.create({ providers: [] });

const value = runInInjectionContext(injector as EnvironmentInjector, () => inject(API_URL));

Calling inject() outside an injection context throws. assertInInjectionContext() can be used for explicit guards.

forwardRef

Use forwardRef() when a token must be resolved later:

class A {
  constructor(@Inject(forwardRef(() => B)) readonly b: B) {}
}

class B {
  constructor(@Inject(forwardRef(() => A)) readonly a: A) {}
}

TypeScript Config

Decorator syntax and runtime constructor inference rely on legacy TypeScript decorators:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

reflect-metadata is bundled as a runtime dependency by this package.

Lifecycle

The injector tracks instances that implement either of these hooks and calls them during destroy():

  • ngOnDestroy()
  • dispose()

EnvironmentInjector.destroy() also destroys child injectors recursively.

Errors

Common error messages:

  • missing provider: No provider for ...
  • circular dependency: Circular dependency detected for ...
  • missing constructor token metadata: Missing injection token for parameter ...
  • inject() outside a context: inject() must be called from an injection context.

Development

vp test
vp check