Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
endpoint-pluto
Advanced tools
https://getpluto.win/ https://getpluto.win/doc/endpoint-pluto/1.1.0/ https://npmjs.com/endpoint-pluto
"JavaScript dependency injection that's so small, it almost doesn't count."
Branch | Status |
---|---|
Master | |
All |
Pluto is a JavaScript dependency injection tool.
Dependency injection is a spiffy way to assemble your applications. It decouples the various bits and makes your app testable. An introduction to dependency injection principles is currently beyond the scope of this guide.
Pluto is designed to be used with Node and NPM. From the root of a Node project, execute:
$ npm install pluto --save
A binder is the basic unit of Pluto's dependency injection. It maps names to objects you want.
Pluto's injection is done in a few steps:
.get(...)
. Pluto will give you the thing mapped to that name. Along the way, it will inject
parameters that match other names bound in the binder and resolve Promises as appropriate..bootstrap()
to run all your factory functions and constructors, and resolve all promises. This
is handy if you're trying to start up an application with a bunch of moving parts, and more common than
using .get(...)
for each part individually.There are three things you can bind to a name: an object instance, a constructor function and a factory function.
If you pass Pluto a promise, it will resolve it. If your factory or constructor function returns a promise, Pluto will resolve it before injecting the result into other components.
The simplest binding is to bind a name to an instance:
const anInstance = {} // can be any JavaScript object, or a Promise
const bind = pluto()
bind('myInstance').toInstance(anInstance)
// bind.get(...) gives us a Promise that resolves to our instance
bind.get('myInstance').then((myInstance) => {
t.is(myInstance, anInstance)
})
You can also bind to a constructor function (i.e., a function that is meant to be used with the new
keyword to create
a new object). When you call .get(...)
, Pluto will invoke the Constructor using new
and return the result. If the
constructor has any parameters, Pluto will consult its bindings and pass them into the constructor:
function Greeter(greeting, name) {
this.greeting = greeting
this.name = name
}
Greeter.prototype.greet = function () {
return `${this.greeting}, ${this.name}!`
}
const bind = pluto()
bind('greeting').toInstance('Hello')
bind('name').toInstance(Promise.resolve('World')) // A promise will work, too
bind('greeter').toConstructor(Greeter)
bind.get('greeter').then((myGreeter) => {
t.is(myGreeter.greet(), 'Hello, World!')
})
Similarly, you can bind to a factory function -- that is, a function that creates some other object. When you
call .get(...)
, Pluto will invoke the function and return the result. Just like with a constructor, if the factory
function has any parameters, Pluto will consult its bindings and pass them into the factory:
function greeterFactory(greeting, name) {
return function greet() {
return `${greeting}, ${name}!`
}
}
const bind = pluto()
bind('greeting').toInstance('Hello')
bind('name').toInstance(Promise.resolve('World')) // A promise will work, too
bind('greet').toFactory(greeterFactory)
bind.get('greet').then((greet) => {
t.is(greet(), 'Hello, World!')
})
Author's note: Factory functions a super useful. I find that I use them more than any other type of binding.
By default, Pluto will only create your objects lazily. That is, factory and constructor functions will only get called
when you ask for them with .get(...)
.
You may instead want them to be eagerly invoked to bootstrap your project. For instance, you may have factory functions which set up Express routes or which perform other application setup.
Invoke .bootstrap()
after creating your bindings to eagerly bootstrap your application. The result is a promise which
resolves to a Map
holding all bindings by name, fully resolved and injected.
function greeterFactory(greeting, name) {
return function greet() {
return `${greeting}, ${name}!`
}
}
const bind = pluto()
bind('greeting').toInstance('Hello')
bind('name').toInstance(Promise.resolve('World')) // A promise will work, too
bind('greet').toFactory(greeterFactory)
bind.bootstrap().then(app => {
const greet = app.get('greet') // Note: it's synchronous. Everything is ready.
t.is(greet(), 'Hello, World!')
})
Note that a factory function or constructor function is only called once. Each call to get(...)
will return the same
instance.
Remember that singletons are only singletons within a single binder, though. Different binders -- for instance, created for separate test methods -- will each have their own singleton instance.
There are times when you might not know exactly what you'll need until later in runtime, and when you might want to manage injection dynamically. Pluto can inject itself to give you extra control.
There are two ways to inject Pluto. Use plutoBinder
if you want the raw binder. Use plutoApp
when you want the fully
bootstapped, synchronous app.
The most direct -- and safe! -- way to self-inject Pluto is to ask for plutoBinder
. This will inject the same bind
function that you received when invoking pluto()
.
function fakeFactory(plutoBinder) {
return plutoBinder.get('data') // will return a promise
}
const bind = pluto() // `bind` is the same object as `plutoBinder`, above
bind('data').toInstance('test-data')
bind('factory').toFactory(fakeFactory)
const actual = yield bind.get('factory')
t.is(actual, 'test-data')
Note that the get(...)
and getAll(...)
functions are asynchronous and return a Promise
!
When using Pluto's bootstrapping capability, you can self-inject the fully bootstrapped application under the
name plutoApp
:
class Greeter {
constructor(plutoApp) {
// Note: the plutoApp Map may not be fully populated yet, since we could
// be at any indeterminate part of the bootstrapping process.
// Save it for later, but don't go using it yet.
this._plutoApp = plutoApp
}
greet() {
// By now, the app is fully bootstrapped and the plutoApp Map is safe
// to use.
const greeting = this._plutoApp.get('greeting')
return `${greeting}, World!`
}
}
const bind = pluto()
bind('greeting').toInstance('Bonjour')
bind('greeter').toConstructor(Greeter)
const app = yield bind.bootstrap()
const greeter = app.get('greeter')
const actual = greeter.greet()
t.is(actual, 'Bonjour, World!')
Warning!!!*
Under normal usage, this is pretty safe. There are a few corner cases to watch out for, however!
.bootstrap()
! If not, or if you try to get an instance before bootstrapping, the plutoApp
variable will not be defined.plutoApp
variable is guaranteed to exist, it may not be fully populated until
bootstrapping is completed. It will be safe to use during "normal" operation, however. Note: It would be easy to add
a Promise that resolves when bootstrapping is complete. If you need this feature, ask for it!FAQs
Dependency injection that's so small, it almost doesn't count.
The npm package endpoint-pluto receives a total of 5 weekly downloads. As such, endpoint-pluto popularity was classified as not popular.
We found that endpoint-pluto 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
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.