New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

seneca-context

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

seneca-context - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

.editorconfig

25

example/server.js
'use strict';
var seneca = require('seneca')();
var senecaContext = require('../index');
var app = require('express')();

@@ -12,21 +11,21 @@ var bodyParser = require('body-parser');

seneca.add('role:api,path:work', function (message, done) {
debug('role:api,path:work', message.tx$, message.context$);
this.act('role:worker,cmd:work', done);
debug('role:api,path:work', message.tx$, message.context$);
this.act('role:worker,cmd:work', done);
});
seneca.add('role:worker2,cmd:wait', function (message, done) {
debug('role:worker2,cmd:wait', message.tx$, message.context$);
done(null, message.context$);
debug('role:worker2,cmd:wait', message.tx$, message.context$);
done(null, message.context$);
});
seneca.use(senecaContext.setContextPlugin);
seneca.use(senecaContext.getContextPlugin, {pin: 'role:worker2'});
seneca.use('../plugins/setContext');
seneca.use('../plugins/getContext', {pin: 'role:worker2'});
seneca.act('role:web', {
use: {
prefix: '/api',
pin: 'role:api,path:*',
map: {
work: {GET: true}
}
use: {
prefix: '/api',
pin: 'role:api,path:*',
map: {
work: {GET: true}
}
}
});

@@ -33,0 +32,0 @@

@@ -9,4 +9,4 @@ 'use strict';

seneca.add('role:worker,cmd:work', function (message, done) {
debug('role:worker,cmd:work', message.tx$, message.context$);
this.act('role:worker2,cmd:wait', done);
debug('role:worker,cmd:work', message.tx$, message.context$);
this.act('role:worker2,cmd:wait', done);
});

@@ -13,0 +13,0 @@

@@ -7,61 +7,7 @@ 'use strict';

module.exports = {
setContextPlugin: setContextPlugin,
getContextPlugin: getContextPlugin,
getContext: getContext
getContext: getContext,
setContext: setContext
};
/**
* A seneca plugin, which automatically saves the context for all HTTP requests.
*
* @param {{
* // A function which creates a context based on the HTTP request and response.
* // It is used by the `setContextPlugin`.
* // The `defaultContext` is `{requestId: req.headers[options.contextHeader]}`.
* // Default is noop.
* createContext: function (request, response, defaultContext, function(error, context))
*
* // The name of the HTTP request header containing the request context.
* // Default is 'x-request-id'.
* contextHeader: string
* }} options
*/
function setContextPlugin(options) {
var seneca = this;
var plugin = 'save-context';
options = seneca.util.deepextend({
createContext: createContext,
contextHeader: 'x-request-id'
}, options);
seneca.act({
role: 'web',
plugin: plugin,
use: processRequest.bind(null, options)
});
return {name: plugin};
}
/**
* A seneca plugin, which automatically exposes the context as a property of the incoming message.
*
* @param {{
* pin: string|Object // a seneca pattern to which this plugin should be applied
* }} options
*/
function getContextPlugin(options) {
var seneca = this;
var plugin = 'load-context';
seneca.wrap(options.pin, function (message, done) {
var seneca = this;
message.context$ = getContext(seneca);
seneca.prior(message, done);
});
return {name: plugin};
}
/**
* Loads the context from the seneca transaction ID.

@@ -73,13 +19,18 @@ *

function getContext(seneca) {
var transactionId = seneca.fixedargs.tx$;
var context = seneca.fixedargs.context$;
var transactionId = seneca.fixedargs.tx$;
var context = seneca.fixedargs.context$;
if (!context) {
context = seneca.fixedargs.context$ = JSON.parse(URLSafeBase64.decode(transactionId).toString('utf8'));
debug('context loaded from tx$ and cached in context$', transactionId, context);
} else {
debug('context loaded from context$', transactionId, context);
if (typeof context === 'undefined') {
try {
context = seneca.fixedargs.context$ = JSON.parse(URLSafeBase64.decode(transactionId).toString('utf8'));
debug('context loaded from tx$ and cached in context$', transactionId, context);
} catch (error) {
context = null;
debug('context cannot be loaded from tx$', transactionId, error);
}
} else {
debug('context loaded from context$', transactionId, context);
}
return context;
return context;
}

@@ -94,44 +45,5 @@

function setContext(seneca, context) {
seneca.fixedargs.tx$ = URLSafeBase64.encode(new Buffer(JSON.stringify(context)));
seneca.fixedargs.context$ = context;
debug('context saved', seneca.fixedargs.tx$, context);
seneca.fixedargs.tx$ = URLSafeBase64.encode(new Buffer(JSON.stringify(context)));
seneca.fixedargs.context$ = context;
debug('context saved', seneca.fixedargs.tx$, context);
}
/**
* Derives a context from an HTTP request and
* ensures that it is available to all seneca actions in this transaction.
*/
function processRequest(options, req, res, next) {
debug('processing HTTP request');
var seneca = req.seneca;
options.createContext(req, res, createDefaultContext(options, req), function (error, context) {
if (error) {
next(error);
} else {
setContext(seneca, context);
next();
}
});
}
/**
* Creates a context based on the value of the `options.contextHeader` header, or the original value of seneca tx$.
*/
function createDefaultContext(options, req) {
var context = {
requestId: req.headers[options.contextHeader] || req.seneca.fixedargs.tx$
};
debug('created default context', context);
return context;
}
/**
* Default implementation of createContext, which responds with the default context.
*/
function createContext(req, res, context, done) {
debug('default createContext - does nothing', context);
process.nextTick(done.bind(null, null, context));
}
{
"name": "seneca-context",
"version": "0.3.0",
"version": "0.4.0",
"description": "Generate a context object based on an HTTP request and easily access it any seneca services involved in processing that request.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -17,27 +17,26 @@ # seneca-context

var seneca = require('seneca')();
var senecaContext = require('seneca-context');
seneca.add('role:api,path:work', function (message, done) {
// context is implicitly propagated to the next seneca action
this.act('role:worker,cmd:work', done);
// context is implicitly propagated to the next seneca action
this.act('role:worker,cmd:work', done);
});
seneca.add('role:worker,cmd:work', function (message, done) {
// context is accessible at the `context$` property of the message
done(null, message.context$);
// context is accessible at the `context$` property of the message
done(null, message.context$);
});
// Creates the context from HTTP requests and propagates it to all actions within the transaction.
seneca.use(senecaContext.setContextPlugin);
seneca.use('seneca-context/plugins/setContext');
// Adds the `context$` property to the incoming messages matching the `pin`.
seneca.use(senecaContext.getContextPlugin, {pin: 'role:worker'});
seneca.use('seneca-context/plugins/getContext', {pin: 'role:worker'});
seneca.act('role:web', {
use: {
prefix: '/api',
pin: 'role:api,path:*',
map: {
work: {GET: true}
}
use: {
prefix: '/api',
pin: 'role:api,path:*',
map: {
work: {GET: true}
}
}
});

@@ -44,0 +43,0 @@

@@ -9,2 +9,31 @@ var createSeneca = require('seneca');

describe('seneca-context', function () {
describe('basic getContext and setContext', function () {
it('should get and set context', function (testDone) {
var seneca = createSeneca();
var context = {a: {b: {c: 1}}, d: [2, 3, 4]};
var context2 = {test: 'data'};
seneca.add('role:test,cmd:run', function (msg, done) {
expect(senecaContext.getContext(this)).to.be.null;
senecaContext.setContext(this, context);
expect(senecaContext.getContext(this)).to.deep.equal(context);
this.act({role: 'test', cmd: 'run2'}, done);
});
seneca.add('role:test,cmd:run2', function (msg, done) {
expect(senecaContext.getContext(this)).to.deep.equal(context);
senecaContext.setContext(this, context2);
expect(senecaContext.getContext(this)).to.deep.equal(context2);
// If possible, a cached context from context$ property is returned.
// Check, if it can be recreated from tx$.
expect(this.fixedargs.context$).to.deep.equal(context2);
delete this.fixedargs.context$;
expect(senecaContext.getContext(this)).to.deep.equal(context2);
expect(this.fixedargs.context$).to.deep.equal(context2);
done();
});
seneca.act({role: 'test', cmd: 'run'}, testDone);
});
});
describe('plugins and propagating context through a socket', function () {
var app, server, seneca1, seneca2;

@@ -15,118 +44,119 @@ var requestId = 'test-request-id-1';

afterEach(function (done) {
vasync.parallel({
funcs: [
server.close.bind(server),
seneca1.close.bind(seneca1),
seneca2.close.bind(seneca2)
]
}, done);
vasync.parallel({
funcs: [
server.close.bind(server),
seneca1.close.bind(seneca1),
seneca2.close.bind(seneca2)
]
}, done);
});
it('should propagate and eventually return the request context', function (done) {
// set up seneca1
// --------------
seneca1 = createSeneca();
seneca1.add('role:seneca1,cmd:task1', function task1(message, done) {
// message.context$ is automatically populated on the first action called by seneca-web
message.context$.should.deep.equal(expectedContext);
// set up seneca1
// --------------
seneca1 = createSeneca();
seneca1.add('role:seneca1,cmd:task1', function task1(message, done) {
// message.context$ is automatically populated on the first action called by seneca-web
message.context$.should.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(message.context$).and.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(message.context$).and.deep.equal(expectedContext);
this.act('role:seneca2,cmd:task2', {trace: message.trace + '1'}, done);
});
seneca1.add('role:seneca1,cmd:task3', function task3(message, done) {
// message.context$ is populated here by `senecaContext.getContextPlugin`
message.context$.should.deep.equal(expectedContext);
this.act('role:seneca2,cmd:task2', {trace: message.trace + '1'}, done);
});
seneca1.add('role:seneca1,cmd:task3', function task3(message, done) {
// message.context$ is populated here by `getContext` plugin
message.context$.should.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(message.context$).and.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(message.context$).and.deep.equal(expectedContext);
done(null, {trace: message.trace + '3', context: message.context$});
});
seneca1.use(senecaContext.setContextPlugin, {
createContext: function (req, res, context, done) {
process.nextTick(done.bind(null, null, seneca1.util.deepextend({test: 'abc'}, context)));
},
contextHeader: 'x-context'
});
seneca1.use(senecaContext.getContextPlugin, {pin: 'role:seneca1,cmd:task3'});
seneca1.act('role:web', {
use: {
prefix: '/',
pin: 'role:seneca1,cmd:*',
map: {
task1: {GET: true}
}
}
});
seneca1.client({port: 9011});
seneca1.listen({port: 9010});
done(null, {trace: message.trace + '3', context: message.context$});
});
seneca1.use('../plugins/setContext', {
createContext: function (req, res, context, done) {
process.nextTick(done.bind(null, null, seneca1.util.deepextend({test: 'abc'}, context)));
},
contextHeader: 'x-context'
});
seneca1.use('../plugins/getContext', {pin: 'role:seneca1,cmd:task3'});
seneca1.act('role:web', {
use: {
prefix: '/',
pin: 'role:seneca1,cmd:*',
map: {
task1: {GET: true}
}
}
});
seneca1.client({port: 9011});
seneca1.listen({port: 9010});
// set up seneca2
// --------------
seneca2 = createSeneca();
seneca2.add('role:seneca2,cmd:task2', function task2(message, done) {
expect(message.context$).to.be.undefined;
// set up seneca2
// --------------
seneca2 = createSeneca();
seneca2.add('role:seneca2,cmd:task2', function task2(message, done) {
expect(message.context$).to.be.undefined;
// load context from tx$
var context = senecaContext.getContext(this);
context.should.deep.equal(expectedContext);
// load context from tx$
var context = senecaContext.getContext(this);
context.should.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(context).and.deep.equal(expectedContext);
// load cached context
senecaContext.getContext(this).should.equal(context).and.deep.equal(expectedContext);
// message should not be modified
expect(message.context$).to.be.undefined;
// message should not be modified
expect(message.context$).to.be.undefined;
this.act('role:seneca1,cmd:task3', {trace: message.trace + '2'}, done);
});
seneca2.client({port: 9010});
seneca2.listen({port: 9011});
this.act('role:seneca1,cmd:task3', {trace: message.trace + '2'}, done);
});
seneca2.client({port: 9010});
seneca2.listen({port: 9011});
// set up express
// --------------
app = express();
app.use(bodyParser.json());
app.use(seneca1.export('web'));
// set up express
// --------------
app = express();
app.use(bodyParser.json());
app.use(seneca1.export('web'));
// wait for seneca and express to start
vasync.parallel({
funcs: [
function (onExpressReady) {
server = app.listen(3010, onExpressReady);
},
seneca1.ready.bind(seneca1),
seneca2.ready.bind(seneca2)
]
}, function (error) {
if (error) {
return done(error);
// wait for seneca and express to start
vasync.parallel({
funcs: [
function (onExpressReady) {
server = app.listen(3010, onExpressReady);
},
seneca1.ready.bind(seneca1),
seneca2.ready.bind(seneca2)
]
}, function (error) {
if (error) {
return done(error);
}
// send an HTTP request
http.get({
hostname: '127.0.0.1',
port: 3010,
path: '/task1?trace=request',
headers: {
'X-Context': requestId
}
}, function (res) {
var responseText = '';
res.on('data', function (data) {
responseText += data;
});
res.on('end', function () {
try {
var response = JSON.parse(responseText);
response.should.deep.equal({context: expectedContext, trace: 'request123'});
done();
} catch (error) {
done(error);
}
// send an HTTP request
http.get({
hostname: '127.0.0.1',
port: 3010,
path: '/task1?trace=request',
headers: {
'X-Context': requestId
}
}, function (res) {
var responseText = '';
res.on('data', function (data) {
responseText += data;
});
res.on('end', function () {
try {
var response = JSON.parse(responseText);
response.should.deep.equal({context: expectedContext, trace: 'request123'});
done();
} catch (error) {
done(error);
}
});
});
});
});
});
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc