SkillAgentSearch skills...

Odin

On-demand dependency injection for JavaScript.

Install / Use

/learn @philips-software/Odin
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

odin

ci codecov npm license

Stands for on-demand dependency injection, enables a lazy loading pattern in JavaScript.

Dependency injection is a technique used to reduce concern about object creation and lifecycle. When delegating resource management to a dependency injection engine, it's possible to build a flexible coupling among resources.

Resources are only instantiated when necessary. When a class is instantiated, not necessarily its dependencies will. By providing dependencies at the last possible moment, it's possible to save computational resources, improving performance and decreasing memory footprint.

Disclaimers

Decorators

Since v3, odin uses the new stage 3 decorators released with TypeScript v5. Ensure your build tool outputs code in a modern version of ECMAScript that supports this version of decorators.

See:

  • https://arai-a.github.io/ecma262-compare/?pr=2417
  • https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#decorators

In v1 and v2 (legacy versions), odin used the experimental stage 2 decorators proposal from TC39. Since that implementation of decorators is not natively supported by browsers or node, projects using odin had to rely on babel and its decorators polyfill (in legacy mode).

See:

  • https://tc39.es/proposal-decorators
  • https://www.typescriptlang.org/docs/handbook/decorators
  • https://babeljs.io
  • https://babeljs.io/docs/en/babel-plugin-proposal-decorators

Roadmap

Breaking changes planned for future major versions

Documentation

Installation

npm i --save @philips-software/odin

Getting started

Declare an injectable:

import { Injectable } from '@philips-software/odin';

@Injectable
class InjectableExample {
  sayHi() {
    console.log('We rode here in their minds, and we took root.');
  }
}

Inject the injectable into another injectable:

import { Inject, Injectable } from '@philips-software/odin';

@Injectable
class UsageExample {

  @Inject({ name: InjectableExample.name })
  injectableExample;

  run() {
    this.injectableExample.sayHi();
  }
}

Use odin to instantiate the injectable, which will inject its dependencies automagically:

import { odin } from '@philips-software/odin';

// creates a container based on the root bundle
// the container provides instances and dependencies
const container = odin.container();

// provides an instance of UsageExample
const usageExample = container.provide(UsageExample.name, true);

// uses the provided instance, which will inject and use its dependency 
usageExample.run(); // We rode here in their minds, and we took root.

API

The exported odin core instance works like a facade object that exposes methods that can be used to manage injectables using bundles, and to provide/resolve injectables using containers.

This instance holds the root bundle, which is managed by odin itself. This instance a unique singleton, so everything that is registered using it will be available to the entire application.

Domain

The domain is used to identify bundles within a hierarchy.

Domains are useful to reduce coupling among different parts of the application by splitting it into smaller parts, making each part of application responsible for managing its own context-bound injectables. Injectables registered within a domain will only be available within the domain itself and its child domains, and not by parent or sibling domains.

Check the Resolution lifecycle.

A domain is a string that represents a chain of bundles, hierarchically organized, with just a single level, or multiple levels separated by forward slashes (/).

Bundle

The bundle is used to manage the registration of injectables, working like a hierarchy of dictionaries. Injectables registered within a bundle will only be available within the bundle itself and its child bundles, and not by parent or sibling bundles.

When using Odin's Injectable decorator, the injectables are registered into the bundles automatically.

This snippet shows how to register an injectable manually:

import { odin } from '@philips-software/odin';

class Injectable { }

// gets odin's root bundle
const bundle = odin.bundle(); // accepts a domain

// registers the injectable
bundle.register(Injectable, { name: 'Injectable' });

Container

The container is used to provide dependencies and/or values by resolving injectables registered into a bundle or one of its parents or custom providers.

By default, odin containers can only provide instances of class, so the values provided by the containers are typically instances of those classes. However, odin also offers the possibility of implementing a CustomProvider to handle specific scenarios, when injecting another type of value is required, for example.

This snippet shows how to create/obtain a container:

import { odin } from '@philips-software/odin';

class Injectable { }

// gets odin's root bundle
const bundle = odin.bundle(); // accepts a domain

// registers the injectable
bundle.register(Injectable, { name: 'Injectable' });

// creates a new container based on odin's root bundle
const container = odin.container(); // accepts a domain

provide(nameOrIdentifier: string, resolve: boolean): Instance | Resolver | undefined

This method provides an instance of the injectable matching the nameOrIdentifier argument, or a resolver for it, depending on the resolve argument. Each time it's called, a new resolver is created, but a new instance will only be created if the injectable is not a singleton (or if the singleton hasn't yet been created or has already been discarded).

When a new instance is created, its dependencies (declared using the @Inject decorator) will be bound to an accessor that will provide their value upon their first access (lazy inject by default). If a dependency is declared as eager, it will be bound to its provided value during instantiation.

See: Provisioning lifecycle.

This snippet shows how to provide an instance of a previously registered injectable using the container:

// provides an instance of the previously registered injectable
container.provide(Injectable.name, true); // returns instance of Injectable

CustomProvider

The CustomProvider is used to provide values for injects that are not provided by the container. Resolvers can be registered into the `CustomPro

View on GitHub
GitHub Stars19
CategoryDevelopment
Updated28d ago
Forks4

Languages

TypeScript

Security Score

90/100

Audited on Mar 9, 2026

No findings