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

sonya

v0.0.21

Published

Super simple dependency injection for Node

Readme

Sonya

Very simple dependency injection for Node, inspired largely by AngularJS.

By design, Sonya is not meant to take over your application. This distinguishes it from other frameworks that use dependency injection but also have a lot of opinions on how you should organize or write your code.

Sonya isn't like that. It isn't a framework at all. It's simply a tool that registers dependencies, resolves the relationships between them, and injects functions with the newly resolved depenencies.

That's it. Nothing complicated. Sonya uses simple functions as modules and can infer dependency names from function arguments just like Angular can.

With Sonya, you can do this:

var sonya = require("sonya");

function one(){
    return "one";
}

function two(one){
    return one + " and two.";
}

function three(one){
    return one + " and three.";
}

function numbers(one, two, three){
    this.one = one;
    this.two = two;
    this.three = three;
}

sonya.Provide
  .factory("one", one)
  .factory("two", two)
  .factory("three", three)
  .service("numbers", numbers)
  ;


sonya.Injector.invoke(function(one, two, three, numbers){
    expect(one).toBe("one");
    expect(two).toBe("one and two.");
    expect(three).toBe("one and three.");
    expect(numbers.one).toBe("one");
    expect(numbers.two).toBe("one and two.");
    expect(numbers.three).toBe("one and three.");
});

As simple as it is, Sonya is extensible. New providers can be easily added to extend its capabilities. For an example, see my sonya-from-directory module.

Provider API

The Provider API is simple:

  var sonya = require("sonya");
  sonya.Provide.factory("nameOfFactory", someFactoryFunction); //provides a factory
  sonya.Provide.service("nameOfService", someServiceFunction); //provides a service
  sonya.Provide.value("someValue", "I am a value"); //provides a value

This will register the factory or the service under the given name. That name can then be used to inject the factory into other functions. The difference between Provide.factory and Provide.service is that the resolved value of the factory function (the value actually injected) will be whatever is returned from the factory function. With Provide.service, the service function will be invoked with the new keyword, and the new object will be injected as the resolved value.

It's important to note that factories and services are resolved only ONCE. If a factory or service is injected into different functions, each of these functions receive the same copy of the factory or service. This is how dependency injection is supposed to work.

Injector API

The Injector has several methods. The most useful one is probably Injector.invoke(). This method takes up to three arguments: a function, an object, and a map of local dependencies. The method injects dependencies into the function and executes it with the object (the second argument) as this. The localArgs map can be used to supply additional dependencies. Only the first argument is required.

Injector.bind() takes the same arguments as invoke, but does not execute the function immediately. Instead, it returns a new function with the dependencies pre-bound to it. This new function can then be executed at a later point, and additional arguments can be provided.

   sonya.Provide.factory("someFactory", function(){
     return "factory";
   });

   var fn = sonya.Injector.bind(function(someFactory, someOtherValue){
    expect(someFactory).toBe("factory");
    expect(someOtherValue).toBe("someValue");
   });

   fn("someValue);

There are also invokeSync() and bindSync() methods. These methods are for situations where factories (typically) will be returning promises. The function passed to invokeSync() will only be executed when all promises are resolved, and the resolved values will be injected.

bindSync() will return a version of the function passed to it that, when executed, will not proceed until all promises are resolved.

Finally, the Injector has a new feature for the latest version (this applies to all invoke, bind, etc.) If a dependency is not registered, rather than immediately throwing an error, the Injector will try to require it with Node's require function. Thus, you can now inject standard Node modules into your functions.

Why Sonya?

I started writing Sonya when I realized my client-side JavaScript was cleaner than my server-side JavaScript. And it wasn't just me. Working on a team, I found the server code was almost always harder to understand, and quite a bit messier. After reading Robert Martin's clean code book, I realized cleanliness was an obligation -- and that I had to make it happen on the server as well as the client.

Why was the client code cleaner? One reason was Angular. JavaScript is a highly expressive language, but that expressiveness can have a downside. Client-side, Angular, and specifically its implementation of dependency injection, tames some of JavaScript's inherent wildness. I wondered if I could tame server side JavaScript that way. But I didn't want to "re-create" Angular on the server. Instead, I sought to distill the Angular approach into two simple tools, a Provide module and an Injector module.

Tests

You must have grunt installed. In module directory, just run "grunt".