
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
A lightweight, extensible dependency injection container for JavaScript powered by Aurelia's dependency-injection and aurelia-property-injection.
This is a bundled version for our needs and is fully compatible with Babel and it's legacy decorators.
$ npm install iocify --save
Note: You may need to install also babel-polyfill.
Currently we are supporting two types of injection - constructor & property injection.
class Logger {}
class Service {}
@inject(Logger, Service)
class App {
constructor(logger, service) {
this.logger = logger;
this.service = service;
}
}
let container = new Container();
let app = container.get(App);
// app.logger instanceof Logger -> true
// app.service instanceof Service -> true
class Logger {}
class Service {}
class App {
@inject(Logger)
logger = null;
@inject(Service)
service = null;
}
let container = new Container();
let app = container.get(App);
// app.logger instanceof Logger -> true
// app.service instanceof Service -> true
Each object created by the dependency injection container has a "lifetime". There are three lifetime behaviors that are typical:
A, is instantiated when it is first needed by the DI container. The container then holds a reference to class A's instance so that even if no other objects reference it, the container will keep it in memory. When any other class needs to inject A, the container will return the exact same instance. Thus, the instance of A has its lifetime connected to the container instance. It will not be garbage collected until the container itself is disposed and no other classes hold a reference to it.Any class can be registered in a container as singleton or transient. What does this process look like? Let's look at a couple of examples to see how things work in practice.
Imagine that we have a single instance of Container called root. If a developer invokes root.get(A) to resolve an instance of A, the root will first check to see if it has a Resolver for A. If one is found, the Resolver is used to get the instance, which is then returned to the developer. If one is not found, the container will auto-register a Resolver for A. This resolver is configured with a singleton lifetime behavior. Immediately after auto-registration, the Resolver is used to get the instance of A which is returned to the developer. Subsequent calls to root.get(A) will now immediately find a Resolver for A which will return the singleton instance.
Now, imagine that we have a Container named root and we call root.createChild() to create a child container named child. Then, we invoke child.get(A) to resolve an instance of A. What will happen? First, child checks for a Resolver for A. If none is found, then it calls get(A) on its parent which is the root container from which it was created. root then checks to see if it has a Resolver. If not, it auto-registers A in root and then immediately calls the Resolver to get an instance of A.
Let's start with an instance of Container named root. We will then call root.createChild() to create a child container named child. Next we will call child.createChild() to create a grandchild container from it named grandchild. Finally, we'll call child.registerSingleton(A, A). What happens when we call grandchild.get(A)? First, grandchild checks for a Resolver. Since it doesn't find one, it delegates to its parent which is the child from which it was created. child then checks for a Resolver. Since child.registerSingleton(A, A) was called on child this means that child will have a Resolver for A. At this point child's resolver is used to get an instance of A which is returned to the developer.
As you can see from these examples, the Container basically walks its hierarchy until it either finds a Resolver or reaches the root. If no Resolver is found in the root, it auto-registers the class as a singleton in the root. This means that all auto-registered classes are application-wide singletons, unless they are overriden by a child container.
For the most part, DI will do what you want with object lifetime. However, you may desire to change the behavior of individual classes for the specific needs of your application. This is easy to do by either directly using the Container API or by decorating your class with a Registration.
The usual way to configure a class's lifetime is to use the Container API directly. Typically, you will want to do this configuration up-front in your application's main configure method.
Here's a survey of the registration APIs you have available through a Container instance:
container.registerSingleton(key: any, fn?: Function): void - This method allows you to register a class as a singleton. This is the default, as discussed above, so there's rarely a reason to call this method. It is provided in the API for completeness. When calling, provide the key that will be used to look up the singleton and the class which should be used. It's common for the key and class to be the same. If they are the same, then only the key needs to be provided. Here are some examples:
container.registerSingleton(History, BrowserHistory);container.registerSingleton(HttpClient);container.registerTransient(key: any, fn?: Function): void - This method allows you to register a class as transient. This means that every time the container is asked for the key, it will return a brand new instance of the class. As with the singleton behavior, the key is requried but the class is optional. If left off, the key will be treated as the class to be instantiated. Here's an example of using transient registration:
container.registerTransient(LinkHandler, DefaultLinkHandler);container.registerInstance(key: any, instance?: any): void - If you already have an existing instance, you can add that to the container with this method. You just need to pick a key that the instance will be retrievable by. If no key is provided then the key becomes the instance.container.registerHandler(key: any, handler: (container?: Container, key?: any, resolver?: Resolver) => any): void - In addition to simply declaring behaviors, you can also provide a custom function (a handler) that will respond any time the container is queried for the key. This custom handler has access to the container instance, the key and the internal resolver which stores the handler. This enables just about any sort of custom lifetime to be implemented by supplying a custom function. Here's an example:
container.registerHandler('Foo', () => new Bar());Info: Registration Keys All registration APIs take a
key. This key is typically the class itself (for convenience). However, the key can be any type, including strings and objects. This is possible because DI implementation uses aMapobject to correlate a key to aResolver. When using class-oriented registration APIs, if the key is not a class, you must provide the class to be created as the second argument to the API call.
As an alternative to explicitly registering types with the container, you can rely on auto-registration, but specify the auto-registration behavior you desire, overriding the default container-root-singleton behavior. To provide auto-registration behavior, you simply decorate your type with an auto-registration decorator. What follows is a basic explanation of built-in registration decorators:
transient() - Simply decorate your class with transient() and when it's requested from the container, a new instance will be created for each request.singleton(overrideChild?:boolean) - Normally, types are auto-registered as singletons in the root container. So, why do we provide this decorator? This decorator allows you to specify true as an argument to indicate that the singleton should be registered not in the root container, but in the immediate container to which the initial request was issued.Warning: Registration Decorator Usage At present, the Decorators spec allows for decorators to use parens or not depending on whether or not the decorator requires arguments. This means that decorator invocation is dependent on how the decorator was implemented internally, which can be confusing from time to time. As a result of the way that the registration decorators are implemented, you must use them with parens.
As mentioned above, the DI container uses Resolvers internally to provide all instances. When explicitly configuring the container, you are actually specifying what Resolver should be associated with a particular lookup key.
You can define the type of Resolver via the following decorators:
injct(key)lazy(key)optional(key)Inject the dependency from the container.
Specifies the dependency should be lazy loaded. It will inject a method that returns the desired instance.
class Logger {}
class App {
@lazy(Logger)
getLogger = null;
}
let container = new Container();
let app = container.get(App);
// app.getLogger() instanceof Logger -> true
Specifies the dependency as optional. Tries to find the desired instance in your container and returns it when found. Otherwise null will be used as the value.
class Logger {}
class Service {}
class App {
@optional(Logger)
logger = null;
@optional(Service)
service = null;
}
let container = new Container();
constainer.registerSingleton(Logger);
let app = container.get(App);
// app.logger instanceof Logger -> true
// app.service === null -> true
MIT
FAQs
Inversion of Control for JS
The npm package iocify receives a total of 2 weekly downloads. As such, iocify popularity was classified as not popular.
We found that iocify demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.