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

@path-ioc/container

v0.1.8

Published

High-level Container extensions, demand proxy and turbo mode for Path-IoC

Readme

⚠️ Historical Evolution Experimental Package / Not Recommended for Production
@path-ioc/container was developed as an experimental proof-of-concept and benchmark package to evaluate synchronous getter-based lazy loading against traditional JS IoC frameworks (such as InversifyJS). Due to strict sequential mutex constraints on property resolution, it is not recommended for standard production applications and has no active iteration roadmap.
For production systems, please use @path-ioc/core and @path-ioc/unplugin with createModularContainer.


Architectural Philosophy: Physical Separation & Subgraph Slicing

1. Canonical Static Topology vs. Extended On-Demand Proxying

In enterprise production (similar to Java Spring's default eager-singleton), full DAG topological preheating at boot time remains the gold standard for system stability, dependency integrity, and runtime throughput:

  • Canonical Core (@path-ioc/core): Strictly rigorous—static graph compilation, DFS Fail-Fast cyclic dependency rejection, and native async/await DAG concurrency. Rejects implicit cycle-breaking that masks architectural design flaws;
  • Extended Container (@path-ioc/container): Exploratory—wraps high-order proxy containers to decompose "Loading Scope (eager | demand)" and "Execution Engine (async | turbo)" into a 2-dimensional orthogonal matrix, evaluating traditional on-demand IoC patterns.

2. The Irreconcilable Physical Law: async vs. turbo

In the JavaScript single-threaded execution model, "Asynchronous Initialization" and "Dynamic Runtime Dependency Sensing" are physically irreconcilable:

  • Physical Reason: JavaScript's Proxy dynamic getter (container.foo) is purely synchronous; it cannot suspend execution mid-flight to await an asynchronous microtask.
    • If a module requires asynchronous setup (async main), its dependencies must be statically declared beforehand so the DAG scheduler can orchestrate topological await execution;
    • If dynamic sensing without declared dependencies were permitted during async execution, accessing an unready node would inevitably yield unhandled dangling Promises or deadlock the event loop.

Path-IoC resolves this via physical separation:

  • async mode (Supports async, requires declared dependencies): Explicit dependencies -> Compiled static DAG -> 100% Native Reactive Topological Concurrency (cascaded asynchronously via Promise.all);
  • turbo mode (Pure synchronous pass-through, supports omitting dependencies): Strictly forbids asynchronous main factories (throws [Turbo Mode] Async module is not supported if a Promise is returned). Because the synchronous call stack never suspends, modules can completely omit dependencies, relying on Proxy Dynamic Getters to synchronously traverse and hydrate dependencies on demand; calling-phase mutual references avoid deadlocks naturally, while initialization-phase circular deadlocks trigger a call stack overflow or are caught by static DFS Fail-Fast interception.

4 Scheduling Paradigms Matrix

@path-ioc/container combines strategy (eager | demand) $\times$ mode (async | turbo) into 4 physical paradigms:

                    ┌─────────────────────────┬─────────────────────────┐
                    │      mode: "async"      │      mode: "turbo"      │
                    │  (Reactive DAG Engine)  │  (Zero-Promise Sync)    │
┌───────────────────┼─────────────────────────┼─────────────────────────┤
│ strategy: "eager" │  ① Full Async Preheat   │  ② Sync Preheat + Direct│
│ (Full Load)       │  (Mounts $ready handle) │  (Fast sync utilities)  │
├───────────────────┼─────────────────────────┼─────────────────────────┤
│ strategy: "demand"│  ③ Subgraph On-Demand   │  ④ Direct Sync Pass-thru│
│ (Instant Slice)   │  (Strict Mutex Guard)   │  (Ultra-fast CLI / Test)│
└───────────────────┴─────────────────────────┴─────────────────────────┘

| Paradigm (strategy $\times$ mode) | Trigger Mechanism | Key Characteristics | Intended Scenario | | :------------------------------------ | :------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------- | | eager + async | Container creation | Full DAG topological concurrency preheat; non-enumerable container.$ready handle | Asynchronous pre-warming experiments | | eager + turbo | Container creation | Synchronously evaluates modules in topological order; throws if an async module is encountered | Synchronous utility test suites | | demand + async | Property access (container.UserPage) | Traverses forward dependency tree to extract minimum slice. Warning: Mutex-guarded; sequential await is required, and concurrent accesses (e.g. Promise.all([container.a, container.b])) will throw a mutex conflict error | Demand-driven async slicing tests | | demand + turbo | Property access (container.foo) | Instant synchronous evaluation without await; strictly intercepts dependency cycles via DFS Fail-Fast | Synchronous batch pipelines, unit test isolation |


Selection Matrix

| Dimension | NestJS | InversifyJS | Awilix | @path-ioc/core (Standard) | @path-ioc/container (Experimental) | | :------------------- | :------------------------------- | :--------------------------- | :-------------------------- | :-------------------------------------------------------- | :-------------------------------------------------- | | Core Contract | @Injectable() + Decorators | @injectable() + Decorators | Regex .toString() + Proxy | Physical Path Contract + Pure Closures + Static Graph | Physical Path Contract + High-Order Proxy | | Code Intrusion | High | High | Low | Zero (Pure ES functions) | Zero (Pure ES functions) | | On-Demand / Lazy | LazyModuleLoader | @lazyInject | Proxy on-demand (sync only) | Static DAG Preheating | Forward Subgraph Slicing (extractSubModules) | | Cycle Resolution | forwardRef() (breaks on async) | @lazyInject() | Dynamic Proxy Getter (sync) | DFS Fail-Fast Cycle Interception | DFS Fail-Fast (No dynamic async cycle breaking) | | Production Ready | Yes | Yes | Yes | Recommended for Production | ⚠️ Experimental / Not Recommended |


Core Mechanism: Subgraph Slice Extraction

In demand mode, when accessing container.UserPage for the first time, the container does not pull the entire registry. Instead, it calls extractSubModules(graph, 'UserPage'):

  1. Forward Traversal: Starting from UserPage, performs depth-first recursion over resolvedDepsMap;
  2. Deterministic Isolation: Strictly collects UserPage and its downstream transitive dependencies, pruning unrelated branches;
  3. Local Compilation: Compiles the minimal extracted subset into a sub-graph and executes it immediately.
Access container.UserPage
       │
       ▼
 [ Entrypoint Identified ] ───► extractSubModules(graph, "UserPage")
                                      │
                                      ├── 1. Recursively extract forward dependencies (UserService, UserApi...)
                                      └── 2. Compile and instantiate local slice immediately

(Note: extractSubModules is an internal private algorithm function, not exported publicly; it is dispatched automatically by the Proxy Getter in demand mode).


API Reference

createContainer(graph, options)

export interface CreateContainerOptions {
  /**
   * Loading Strategy:
   * - "eager": Full preheat (initializes all modules upon container creation)
   * - "demand": On-demand slicing (initializes modules when properties are accessed)
   */
  strategy: "eager" | "demand";

  /**
   * Execution Engine:
   * - "async": Reactive asynchronous DAG topological concurrency
   * - "turbo": Pure synchronous pass-through zero-promise engine
   */
  mode: "async" | "turbo";
}

export const createContainer: (
  graph: CompiledModuleGraph,
  options: CreateContainerOptions,
) => Record<string, unknown>;

(Note: In eager + async mode, a non-enumerable $ready: Promise<void> is attached to the returned object).


License

Released under the MIT License.
Copyright © 2026-present Path-IoC Organization & Lian HanLin.