Security News
pnpm 10.0.0 Blocks Lifecycle Scripts by Default
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
An experimental dependency injection module that:
Please read the origin of the name section before proceeding.
###lib/database.js (async module):
module.exports = function (config, db, callback) {
// init db connection etc, this module will be "ready" only when the callback is invoked
db.connect(config.connectionString, callback)
}
###lib/config.js:
module.exports = function(rc) {
return rc('di-example', { httpPort: 1234, connectionString: 'some://thing' })
}
###index.js:
require('darkmagic').inject(function(http, database, config) {
// do application stuff
http.createServer(function(request, response) {
database.query('select * from moo', function(err, results) {
response.end(results)
})
}).listen(config.httpPort)
})
index.js would typically look like this:
var http = require('http')
var database = require('./lib/database')
var config = require('./lib/config')
database(function(err, connection) {
http.createServer(function(request, response) {
connection.query('select * from moo', function(err, results) {
response.end(results)
})
}).listen(config.httpPort)
})
The framework eliminates the need for these declarations by inferring the dependencies from the parameters of a function (it does that using esprima)
Assuming we want to test a module called loadData that looks like this:
var fs = require('fs')
module.exports = function(filename, callback) {
fs.readFile(filename, callback)
}
If we are writing a test that involves this module we are basically stuck with actually writing a test file to the disk. Of course there are several modules and technics out there to solve this problem. Darkmagic's take on this is described below.
Here is a darkmagic version of this module:
module.exports = function (fs) {
return function loadData(filename, callback) {
fs.readFile(filename, callback)
}
}
looks very similar except that now it is quite easy to inject a mock fs object that will return a result we want in our testing. Lets add a crypto dependency too:
module.exports = function (fs, crypto) {
return function loadData(filename, callback) {
fs.readFile(filename, function (err, data) {
if (err) return callback(err)
// this is not a working example...
var decipher = crypto.createDecipher('aesFoo', 'shhhhhhh')
var result = decipher.update(data)
result += decipher.final()
callbackk(null, result)
})
}
}
Now when testing this code we could do this:
var mockFs = { readFile: ... }
var loadData = require('../lib/loadData')(mockFs, require('crypto'))
... test code here
or we could use darkmagic again, just to replace the fs dependency with a mock:
var mockFs = { readFile: ... }
require('darkmagic').inject(function (loadData) {
.. test code here
}, { fs: mockFs })
####simple.js:
module.exports = function (http, fs) {
http.createServer(function(request, response) {
fs.createReadStream('moo').pipe(response)
}).listen(8080)
}
####index.js
require('darkmagic').inject(function(simple) {
// simple server is started but we dont know when its ready
})
module.exports = function (fs, callback) {
fs.readFile('moo', callback)
}
module.exports = function (http, mooFile, callback) {
var server = http.createServer(function(request, response) {
response.write(mooFile)
})
server.on('listening', function() {
callback(null, server)
})
server.listen(8080)
}
require('darkmagic').inject(function(http, server) {
http.get('http://localhost:8080', function(err, response) {
// response content should be equal to our moo file
})
})
module.exports = { port: 8080 }
require('darkmagic').inject(function(http, config) {
http.createServer(...).listen(config.port)
})
this will not work for local files though
var overrides = {
'fooBar': 'MyCrazyNodeModule__name',
'barFoo': '/home/moo/lib/1.js'
}
require('darkmagic').inject(function(fooBar, barFoo) {
}, overrides)
var injector = require('darkmagic').inject(function(smurf) {
})
injector.on('new dependency', function (dependency, artifact) {
// dependency metadata
// artifact is require('smurf') before injection
})
this will not work for local files though
require('darkmagic').inject(function(findPort) {
// same as require('find-port')
})
require('darkmagic').inject(function($injector) {
$injector.addSearchPath('/a/path/to/somewhere') // add this path as first location to search in
$injector.inject(function(moo, pie, foo, bar) {
})
})
By default errors that occur during the dependency resolution process are simply thrown. Specifying a second callback to the inject method will prevent that and the error handler will be called instead
require('darkmagic').inject(function(foo) {
}, function(err) {
})
This framework uses a lot of "dark magic" (hence its name) tricks that many will view as dangerous. These people are probably right and you should listen to them!
####This module:
parses function signature and uses the parameters, literally to load modules, first attempting to require them as they are and then by attaching them to various predefined search paths in your local file system
Attempt to inject and invoke recursively EVERY module that exports a function and override the module system cache with the result of the invocation for that module. This behavior is customizable and is turned off by default for external modules (core/node_modules)
dashify camelCase (camel-case) parameters when trying to find non local node modules
infer that an exported function is async if the last paramter is called "callback"
relies heavily on the module system, it does not cache the dependencies you create ** as a result, one injector is use for one process. You can create more injectors but they will share the same underlying require cache.
####Fine print if all else fails you can do
require('darkmagic').inject(main, {
a: {},
b: {},
c: {}
})
function main(a, b, c) {
}
these dependencies will not be cached using the module system but in the injector
TODO:
FAQs
A dependency injection framework
The npm package darkmagic receives a total of 3 weekly downloads. As such, darkmagic popularity was classified as not popular.
We found that darkmagic demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 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
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
Product
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Research
Security News
Socket researchers have discovered multiple malicious npm packages targeting Solana private keys, abusing Gmail to exfiltrate the data and drain Solana wallets.