Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@travetto/di
Advanced tools
Install: primary
$ npm install @travetto/di
Dependency injection
is a framework primitive. When used in conjunction with automatic file scanning, it provides for handling of application dependency wiring. Due to the nature of typescript
and type erasure of interfaces, dependency injection only supports class
es as type signafiers. The primary goal of dependency injection is to allow for separation of concerns of object creation and it's usage.
The @Injectable
and @InjectableFactory
decorators provide the registration of dependencies. Dependency declaration revolves around exposing class
es and subtypes thereof to provide necessary functionality. Additionally, the framework will utilize dependencies to satisfy contracts with various backends (e.g. ModelMongoSource
provides itself as an injectable candidate for ModelSource
).
Code: Example @Injectable
@Injectable()
class CustomService {
async coolOperation() {
... work ...
}
}
When declaring a dependency, you can also provide a token to allow for multiple instances of the dependency to be defined. This can be used in many situations:
Code: Example @Injectable with multiple targets
@Injectable()
class CustomService {
async coolOperation() {
... work ...
}
}
const CUSTOM2 = Symbol('custom2');
@Injectable({ target: CustomService, symbol: CUSTOM2 })
class CustomService2 extends CustomService {
async coolOperation() {
await super.coolOperation();
// Do some additional work
}
}
As you can see, the target
field is also set, which indicates to the dependency registration process what class
the injectable is compatible with. Additionally, when using abstract
classes, the parent class
is always considered as a valid candidate type.
Code: Example @Injectable with target via abstract class
abstract class BaseService {
abstract work():Promise<void>;
}
@Injectable()
class SpecificService extends BaseService {
async work() {
// Do some additional work
}
}
In this scenario, SpecificService
is a valid candidate for BaseService
due to the abstract inheritance. Sometimes, you may want to provide a slight variation to a dependency without extending a class. To this end, the @InjectableFactory
decorator denotes a static
class method that produces an @Injectable
.
Code: Example @InjectableFactory, return type defines target class
class Config {
@InjectableFactory()
static initService(): CoolService {
return new CoolService();
}
}
Given the static
method initService
, the function will be provided as a valid candidate for CoolService
. Instead of calling the constructor of the type directly, this function will work as a factory for producing the injectable.
NOTE Due to the lack of typechecker in the Compiler
for performance reasons, the return type on the factory method is mandatory. Without it, the code will not know what the expected target type should be.
NOTE Other modules are able to provide aliases to @Injectable
that also provide additional functionality. For example, the @Config
or the @Controller
decorator registers the associated class as an injectable element.
Once all of your necessary dependencies are defined, now is the time to provide those @Injectable
instances to your code. There are three primary methods for injection:
The @Inject
decorator, which denotes a desire to inject a value directly. These will be set post construction.
Code: Example @Injectable with dependencies as @Inject fields
@Injectable()
class CustomService {
@Inject()
private dependentService: DependentService;
async coolOperation() {
await this.dependentService.doWork();
}
}
The @Injectable
constructor params, which will be provided as the instance is being constructed.
Code: Example @Injectable with dependencies in constructor
@Injectable()
class CustomService {
constructor (private dependentService: DependentService) {}
async coolOperation() {
await this.dependentService.doWork();
}
}
Via @InjectableFactory
params, which are comparable to constructor params
Code: Example @InjectableFactory with parameters as dependencies
class Config {
@InjectableFactory()
static initService(dependentService: DependentService): CustomService {
return new CustomService(dependentService);
}
}
Some times you will need to lookup a dependency dynamically, or you want to control the injection process at a more granular level. To achieve that you will need to directly access the DependencyRegistry
. The registry allows for requesting a dependency by class reference:
Code: Example of manual lookup
@Injectable()
class Complex {}
class ManualLookup {
async invoke() {
const complex = await DependencyRegistry.getInstance(Complex);
}
}
Given that dependency injection is generally a pre-requisite for application execution, it stands as the primary entrypoint for application invocation. The Base
provides a simplistic bootstrap to allow for the application to run, but that is not sufficient for more complex applications.
The module provides a decorator, @Application
who's job is to register entry points into the application. For example:
Code: Example of @Application target
import { Application, Inject, Injectable } from '../';
@Injectable()
class Server {
name = 'roger';
async launch() {
...
}
}
@Application('simple')
class SimpleApp {
@Inject()
server: Server
async run() {
return this.server.launch();
}
}
Will expose an entrypoint named 'simple'. This additionally allows for other entry points to be named for handling specific use cases. An additional entry point could look like:
Code: Example of multiple @Application support
import { Application, Inject, Injectable } from '../';
@Injectable()
class Server {
name = 'roger';
config = { ... };
async launch() {
...
}
}
@Application('config')
class ConfigApp {
@Inject()
server: Server
async run() {
console.log(server.configuration);
}
}
FAQs
Dependency registration/management and injection support.
The npm package @travetto/di receives a total of 365 weekly downloads. As such, @travetto/di popularity was classified as not popular.
We found that @travetto/di demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers 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.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.