
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
state-porter
Advanced tools
Better state management for JavaScript objects.
npm install state-porter or yarn add state-porter.
Require Porter into your project:
const Porter = require('state-porter');
There are no explicit dependencies, except development dependencies for testing. If you want to contribute, install the development dependencies.
Porter works best within the "privacy" of closures in Javascript functions, and especially constructor functions.
In order for Porter to provide help with an object's private state, you'll need create a new instance of Porter inside of your constructor function. Simply never set the Porter instance on the object constructed and it will not be accessible outside of that closure. See more about this pattern here.
Effectively, this means that the Porter instance is available only to the object created by the constructor.
const Porter = require('Porter');
let Person = function(name) {
let porter = new Porter({
props: {
// Short syntax
name: String,
// Long syntax
location: {
type: Object,
default: {
lat: "",
long: ""
}
},
}, {
freeze: true, // default
strictTypes: true // default
});
porter.name = name;
this.getName = function() {
return porter.name;
};
this.setLocation = function(location) {
porter.location = location;
}
this.getLocation = function() {
return porter.location;
}
}
let jane = new Person('jane');
let bob = new Person('bob');
jane.getName(); // jane
bob.setLocation({lat: 12.345, long: -12.3459}); // success
jane.setLocation('nowhere'); // throws type error since location expects an object not string
These can be declared in the following manner:
let porter = new Porter({
props: {
string: String,
number: Number,
boolean: Boolean,
object: Object,
function: Function,
internalClass: Date,
customClass: MyCustomClass,
anyType: null
}
});
let porter = new Porter({
props: {
name: String,
age: Number
}
}, {
// default settings:
freeze: true,
strictTypes: true
});
There are two ways to bypass type checking of properties:
null type for in the property declaration{strictTypes: false} in the optionsBy default, the Porter instance is frozen so that no properties can be added after initialization. This behavior can be disabled by passing {freeze: false} in the options.
Computed properties are recalculated every time one of their dependent properties changes.
let porter = new Porter({
props: {
name: {
type: String,
default: ""
}
},
computed: {
greeting: {
type: String,
deps: ['name'],
calc: function() {
return `Hi, ${this.name}!`;
}
}
}
});
porter.name = 'Bob';
console.log(porter.greeting); // Hi, Bob!
porter.name = 'Jane';
console.log(porter.greeting); // Hi, Jane!
It is best to declare dependent properties with default values, otherwise the property may be undefined if not set. This may change so that properties are initialized with default values in all cases.
The method is bound to the Porter object, so it can access properties easily with this.propName.
Computed properties can depend on other computed properties as long as it does not create a circular dependency which will produce an infinite loop of callbacks.
Subscribe to property changes:
porter.subscribe('propName', (newValue, oldValue) => {
// handle update
});
// Removes subscription
porter.unsubscribe('propName');
Example:
let porter = new Porter({
props: {
name: {
type: String,
default: ''
}
}
});
porter.subscribe('name', (newName, oldName) => {
// update logic
});
porter.name = 'New name'; // fires subscribe handler
Only one subscribe handler is supported for each property. Adding a new subscribe handler will replace the previous one.
let porter = new Porter({
props: {
// Short property declaration
userId: Number,
name: String,
// Long declaration
activeUser: {
type: Boolean,
default: true
}
},
computed: {
greeting: {
type: String,
deps: 'name', // single property
calc: function() {
return `Hi ${this.name}`;
}
},
userName: {
type: String,
deps: ['name', 'userId'], // multiple properties
calc: function() {
return `${this.name}_${this.userId`;
}
},
lastUpdated: {
type: Date,
deps: "*", // all non-computed properties
calc: function() {
return new Date();
}
}
}
}, {
freeze: true,
strictTypes: true
});
porter.subscribe('propName', (newVal, oldVal) => { });: Subscribe to property updatesporter.unsubscribe('propName';: Remove property subscriptionYes, of course. Porter adds some overhead to getting and setting properties, but the payoff is better state-management.
You will have to decide if Porter's overhead is an acceptable cost. In some applications, especially applications where state-management is not that complicated, Porter may not be necessary. However, in complex applications, it becomes increasingly critical to manage state in ways that are easy to reason about.
If you're already doing a lot of type checking and enforcing setter methods in your objects, then Porter takes a lot of this pain away so that you can focus on creating and not on boilerplate.
You can decide if Porter is right for your application.
To profile your machine, install Porter and run npm run porter-profile (must have Node and npm installed).
Install the development dependencies before running tests. Tests are powered by Mocha.
npm run test
FAQs
Better state management for JavaScript objects
The npm package state-porter receives a total of 2 weekly downloads. As such, state-porter popularity was classified as not popular.
We found that state-porter 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.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.