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

fount

v1.2.0

Published

A source from which dependencies flow

Readme

Fount

Fount provides synchronous and asynchronous dependency injection with automatic deferred resolution.

Getting Started

npm i fount
import { fount } from 'fount';

Key Features

  • Deferred Resolution: When resolving dependencies that haven't been registered yet, fount will wait until they become available rather than throwing an error.
  • Multiple Containers: Organize dependencies into namespaced containers.
  • Scoped Resolution: Cache factory results per scope for memoization.
  • Flexible Registration: Register values, factories, or npm modules.

Dependency Identification Styles

Fount supports two styles of identifying dependencies:

// By argument name - each argument is looked up by name in fount's store
fount().inject((one, two, three) => {
  // your code here
});

// By string array - dependencies are looked up and passed in order
fount().inject(['one', 'two', 'three'], (one, two, three) => {
  // your code here
});

The string array approach is recommended for production code as minifiers will rename function arguments and break name-based resolution.

Multiple Containers

Fount supports multiple dependency containers identified by namespace. If you don't specify one, it uses the default namespace.

You can use a non-default namespace in two ways:

  • Pass the namespace in parenthesis before making the call
  • Use period-delimited namespaces in your key names
// Using the default namespace
const value = await fount().resolve('myKey');

// Using a named namespace
const value = await fount('myContainer').resolve('myKey');

// Using period-delimited keys to access other namespaces
const value = await fount().resolve('myContainer.myKey');

Scopes

Scopes work with factory dependencies to provide memoization. The first time a scoped factory is resolved within a scope, the result is cached. Subsequent resolutions within the same scope return the cached value.

// Register a scoped factory
fount().registerFactory('timestamp', () => Date.now(), 'scoped');

// First call computes the value
const t1 = await fount().resolve('timestamp', 'myScope');

// Second call returns cached value
const t2 = await fount().resolve('timestamp', 'myScope');

console.log(t1 === t2); // true

Purging Scopes

// Purge a specific scope from the default namespace
fount().purgeScope('myScope');

// Purge all scopes from the default namespace
fount().purgeScopes();

// Purge a specific scope from a named namespace
fount('example').purgeScope('myScope');

// Purge all scopes from a named namespace
fount('example').purgeScopes();

Registering Dependencies

Values

Register static values that fount returns as-is:

fount().register('port', 8080);
fount().register('config', { debug: true, maxRetries: 3 });
fount('custom').register('apiKey', 'secret-key');

Factories

Register functions that fount invokes during resolution:

// Simple factory
fount().registerFactory('timestamp', () => Date.now());

// Factory with dependencies
fount().registerFactory('connection', ['host', 'port'], (host, port) => {
  return createConnection(host, port);
});

// Dependencies inferred from argument names
fount().registerFactory('connection', (host, port) => {
  return createConnection(host, port);
});

Factory Lifecycles

Factories support three lifecycles:

  • factory (default): Invoked on every resolution
  • static: Invoked once, result is cached permanently
  • scoped: Invoked once per scope, result is cached per scope
// Factory lifecycle - new instance every time
fount().registerFactory('id', () => generateId(), 'factory');

// Static lifecycle - computed once, cached forever
fount().registerFactory('startTime', () => Date.now(), 'static');

// Scoped lifecycle - computed once per scope
fount().registerFactory('requestId', () => generateId(), 'scoped');

NPM Modules

Register npm modules directly:

fount().registerModule('lodash');

// Later, resolve it
const _ = await fount().resolve('lodash');

If the module exports a function that fount cannot resolve dependencies for, it provides the function as-is.

Asynchronous Methods

These methods return promises and support deferred resolution - if a dependency isn't registered yet, fount waits until it becomes available.

resolve

Resolve a single dependency:

const port = await fount().resolve('port');

// With scope
const value = await fount().resolve('config', 'myScope');

resolveAll

Resolve multiple dependencies at once:

const { host, port } = await fount().resolveAll(['host', 'port']);

// Across namespaces
const results = await fount().resolveAll(['db.host', 'cache.host']);

inject

Resolve dependencies and pass them to a function:

// With explicit dependency list
const result = await fount().inject(['host', 'port'], (host, port) => {
  return `${host}:${port}`;
});

// With inferred dependencies
const result = await fount().inject((host, port) => {
  return `${host}:${port}`;
});

// With scope
const result = await fount().inject(['config'], (config) => {
  return config.value;
}, 'myScope');

Deferred Resolution

A key feature of fount is that async methods wait for dependencies to be registered:

// Start resolving before the dependency exists
const valuePromise = fount().resolve('laterValue');

// Register the dependency later
setTimeout(() => {
  fount().register('laterValue', 42);
}, 1000);

// The promise resolves once the dependency is registered
const value = await valuePromise; // 42

This also works with dependency chains:

// Register factories that depend on unregistered values
fount().registerFactory('doubled', ['base'], (base) => base * 2);
fount().registerFactory('result', ['doubled'], (doubled) => doubled + 10);

// Start resolution
const resultPromise = fount().resolve('result');

// Register the base value later
setTimeout(() => {
  fount().register('base', 5);
}, 100);

const result = await resultPromise; // 20 (5 * 2 + 10)

Synchronous Methods

These methods return values immediately and assume no promises in the dependency chain.

Warning: If a promise is encountered in the dependency chain, synchronous methods will not resolve it properly.

get

Get a dependency value synchronously:

const port = fount().get('port');

// With scope
const value = fount().get('config', 'myScope');

// Multiple values
const { host, port } = fount().getAll(['host', 'port']);

invoke

Invoke a function with resolved dependencies synchronously:

const result = fount().invoke(['host', 'port'], (host, port) => {
  return `${host}:${port}`;
});

// With inferred dependencies
const result = fount().invoke((host, port) => {
  return `${host}:${port}`;
});

Checking Resolution

Use canResolve to check if dependencies can be resolved without waiting:

if (fount().canResolve('myKey')) {
  const value = fount().get('myKey');
}

// Check multiple keys
if (fount().canResolve(['key1', 'key2'])) {
  const values = fount().getAll(['key1', 'key2']);
}

Configuration

Configure multiple containers and values at once:

fount({
  default: {
    host: 'localhost',
    port: 8080
  },
  database: {
    host: 'db.example.com',
    port: 5432,
    pool: {
      factory: () => createPool()
    }
  },
  cache: {
    ttl: 3600,
    maxSize: {
      scoped: () => calculateMaxSize()
    }
  }
});

Values can be:

  • Plain values (registered as static)
  • Objects with factory key (registered as factory lifecycle)
  • Objects with scoped key (registered as scoped lifecycle)
  • Objects with static key (registered as static lifecycle)

Utility Methods

Key Lists

// All keys across all namespaces
const allKeys = fount.allKeys();

// Keys in a specific namespace
const keys = fount('myNamespace').keys();

Namespaces

const namespaces = fount.namespaces();

Purging

// Remove everything
fount.purgeAll();

// Remove all keys from the default namespace
fount().purge();

// Remove all keys from a specific namespace
fount('myNamespace').purge();

Diagnostics

// Log the current state of all containers
fount.log();

TypeScript Support

Fount is written in TypeScript and exports its types:

import { fount, Fount, ContainerApi } from 'fount';

// The main fount export
const f: Fount = fount;

// Container API returned when calling fount()
const container: ContainerApi = fount();

Testing

# Run tests once
npm test

# Run tests in watch mode
npm run test:watch