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

unlayer

v2.0.4

Published

A type-safe dependency injection container inspired by Effect.ts Layer system.

Readme

unlayer

A type-safe dependency injection container inspired by Effect.ts Layer system.

Features

  • Compile-time type safety - container.get() only allows services that registered in the container
  • Layer-based - Compose your application with layers
  • Scoped services - Singleton (default) or transient scope
  • Resource disposal - Automatic cleanup with dispose callbacks
  • Lightweight - No dependencies

Type Safety

The core feature is compile-time type safety - you cannot use services that aren't registered in the container:

import { tag, Layer, createContainer } from 'unlayer'

interface Database {
  find(id: string): Promise<User | null>
}

const DatabaseTag = tag<Database>('Database')
const LoggerTag = tag<{ log(msg: string): void }>('Logger')

const container = createContainer(
  Layer.value(DatabaseTag, new Database())
)

// ✅ Works - Database is in the container
const db = container.get(DatabaseTag)

// ❌ Compile-time error - Logger is NOT in the container
// const logger = container.get(LoggerTag)
// Error: Argument of type 'Tag<{ log(msg: string): void }>' is not assignable to parameter of type 'Tag<Database>'

Installation

npm install unlayer
pnpm add unlayer
yarn add unlayer

Quick Start

import { tag, Layer, createContainer } from 'unlayer'

// Define service interfaces
interface Database {
  find(id: string): Promise<User | null>
}

interface Logger {
  log(msg: string): void
}

// Create type-safe tags
const DatabaseTag = tag<Database>('Database')
const LoggerTag = tag<Logger>('Logger')

// Define layers
const DatabaseLive = Layer.value(DatabaseTag, new Database())

const LoggerLive = Layer.factory(
  LoggerTag,
  [DatabaseTag], // dependencies
  (db) => ({
    log(msg: string) {
      const user = db.find('1')
      console.log(`[${msg}]`, user)
    }
  })
)

// Create container and use services
const container = createContainer(
  Layer.merge(DatabaseLive, LoggerLive)
)

const logger = container.get(LoggerTag)
logger.log('Starting application')

// Clean up
await container.dispose()

Documentation

Creating Tags

import { tag } from 'unlayer'

const ConfigTag = tag<{ apiUrl: string; timeout: number }>('Config')

Layer Types

Value Layer - Pre-built values:

const ConfigLive = Layer.value(ConfigTag, {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
})

Factory Layer - Lazy initialization:

// No dependencies
const LoggerLive = Layer.factory(LoggerTag, () => ({
  log: (message: string) => console.log(message),
}))

// With dependencies
const ServiceLive = Layer.factory(
  ServiceTag,
  [DatabaseTag, CacheTag], // dependency array
  (db, cache) => ({
    async getData(id: string) {
      const cached = cache.get(id)
      if (cached) return cached
      return db.find(id)
    }
  })
)

Scope

Singleton (default) - Same instance every time:

const SingletonLive = Layer.factory(ServiceTag, () => ({ /* ... */ }))
// or explicitly
const SingletonLive = Layer.factory(ServiceTag, () => ({ /* ... */ }), {
  scope: 'singleton',
})

Transient - New instance every time:

const TransientLive = Layer.factory(ServiceTag, () => ({ /* ... */ }), {
  scope: 'transient',
})

Resource Disposal

const DatabaseLive = Layer.factory(
  DatabaseTag,
  () => ({ /* ... */ }),
  {
    dispose: async (db) => {
      await db.close()
    },
  }
)

Merging Layers

// Spread syntax
const MainLayer = Layer.merge(
  ConfigLive,
  DatabaseLive,
  LoggerLive,
)

// Array syntax
const MainLayer = Layer.merge([
  ConfigLive,
  DatabaseLive,
  LoggerLive,
])

// With options
const MainLayer = Layer.merge(layers, {
  allowDuplicates: true,
})

Duplicate Tags

By default, merging layers with the same tag will throw an error. Use allowDuplicates: true to allow the last layer to win:

const DatabaseTag = tag<Database>('Database')

const db1 = Layer.value(DatabaseTag, dbInstance1)
const db2 = Layer.value(DatabaseTag, dbInstance2)

// ❌ Throws: Duplicate tag detected: Database
Layer.merge(db1, db2)

// ✅ Allows duplicates - db2 wins
const MainLayer = Layer.merge(db1, db2, {
  allowDuplicates: true,
})

Note: When using allowDuplicates, type information is lost (Layer<never, never>) since duplicate tags cannot be statically tracked.

Examples

See the examples directory for more usage patterns:

Run examples with:

node examples/basic.ts

License

MIT