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

@ambrosia-unce/core

v1.0.1

Published

Lightweight decorator-based Dependency Injection container for TypeScript and Bun

Readme

@ambrosia-unce/core

A powerful and flexible Dependency Injection container for TypeScript applications, built for the Bun runtime.

Features

  • Constructor Injection -- automatic dependency resolution via constructor parameters
  • Property Injection -- inject dependencies into class properties with @Autowired()
  • InjectionToken -- type-safe tokens for interfaces and configuration objects
  • Multiple Scopes -- Singleton, Transient, and Request (via AsyncLocalStorage)
  • Factory Providers -- flexible dependency creation with factory functions
  • Auto-resolve Circular Dependencies -- automatic resolution using lazy proxies with console warnings
  • Pack System -- a module composition unit with providers, exports, imports, and lifecycle hooks
  • Plugin System -- hook into container lifecycle events (resolve, init, register) without modifying the core
  • TypeScript First -- full type safety throughout the API
  • Bun Native -- optimized for the Bun runtime

Installation

bun add @ambrosia-unce/core reflect-metadata

Quick Start

import "reflect-metadata";
import { Container, Injectable } from "@ambrosia-unce/core";

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

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

  getUser(id: number) {
    this.logger.log(`Getting user ${id}`);
    return { id, name: "John" };
  }
}

const container = new Container();
const userService = container.resolve(UserService);
userService.getUser(123);

Key Concepts

Constructor Injection

Dependencies are automatically resolved through constructor parameters:

@Injectable()
class Database {
  connect() { /* ... */ }
}

@Injectable()
class UserService {
  constructor(private db: Database) {}
  // Database is automatically injected!
}

Property Injection

Inject dependencies into class properties using @Autowired():

@Injectable()
class UserController {
  @Autowired()
  private logger!: Logger;

  @Autowired()
  @Optional()
  private cache?: CacheService;
}

InjectionToken

Type-safe tokens for interfaces and configuration objects:

interface AppConfig {
  port: number;
}

const CONFIG = new InjectionToken<AppConfig>("AppConfig");

container.registerValue(CONFIG, { port: 3000 });

@Injectable()
class ApiServer {
  constructor(@Inject(CONFIG) private config: AppConfig) {}
}

Scopes

Control the lifecycle of your dependencies:

// Singleton (default) -- one instance for the entire application
@Injectable({ scope: Scope.SINGLETON })
class Database {}

// Transient -- a new instance on every resolve call
@Injectable({ scope: Scope.TRANSIENT })
class RequestHandler {}

// Request -- one instance per HTTP request (via AsyncLocalStorage)
@Injectable({ scope: Scope.REQUEST })
class RequestContext {}

Factory Providers

Use factory functions for custom dependency creation logic:

container.registerFactory(
  CacheService,
  (c) => {
    const cache = new CacheService();
    cache.initialize();
    return cache;
  },
  Scope.SINGLETON
);

Pack System

Packs are the unit of composition in Ambrosia. A PackDefinition declares providers, exports (for encapsulation), imports, and lifecycle hooks:

import { definePack } from "@ambrosia-unce/core";

const LoggingPack = definePack({
  meta: { name: "logging", version: "1.0.0" },
  providers: [LoggingService],
  exports: [LoggingService],
});

const AppPack = definePack({
  meta: { name: "app" },
  imports: [LoggingPack],
  providers: [UserService, OrderService],
  exports: [UserService],
  async onInit(container) {
    const logger = container.resolve(LoggingService);
    logger.log("App pack initialized");
  },
  async onDestroy() {
    // Graceful cleanup on shutdown
  },
});

Packs support conditional and lazy imports for advanced scenarios:

const AppPack = definePack({
  imports: [
    CorePack,
    process.env.CACHE_ENABLED && CachePack, // conditional import
  ],
  lazyImports: () => [FeaturePack], // lazy import to break circular pack dependencies
});

Auto-resolve Circular Dependencies

Enable automatic resolution of circular dependencies using lazy proxies:

const container = new Container({ autoResolveCircular: true });

// Circular dependencies are now resolved automatically
// with a warning instead of an error

When a circular dependency is detected, the container:

  • Logs a warning to the console
  • Creates a lazy proxy for the circular dependency
  • Allows the application to continue running

API

Container

// Create a container
const container = new Container();
const containerWithAutoResolve = new Container({ autoResolveCircular: true });

// Register providers
container.register(UserService);
container.registerClass(AbstractService, ConcreteService);
container.registerValue(CONFIG, { port: 3000 });
container.registerFactory(Cache, (c) => new Cache());

// Resolve dependencies
const service = container.resolve(UserService);
const optional = container.resolveOptional(OptionalService);

// Async resolution
const asyncService = await container.resolveAsync(AsyncService);

Decorators

@Injectable({ scope: Scope.SINGLETON })  // Mark a class as injectable
@Inject(token)                           // Specify a token for a constructor parameter
@Autowired()                             // Inject into a property
@Optional()                              // Mark a dependency as optional
@Implements(AbstractClass)               // Bind an abstract class to its concrete implementation

Requirements

  • TypeScript >= 5.0
  • Bun >= 1.3.6 (or Node.js >= 18 with an appropriate bundler)
  • experimentalDecorators: true in tsconfig.json
  • emitDecoratorMetadata: true in tsconfig.json

License

MIT