
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
Just another juicy state manager lib for your js apps.
Heavily inspired by redux obviously.
Add your library features here.
# npm
npm i diddi
# yarn
yarn add diddi
// ./state/index.ts
import { create } from 'diddi';
import mydomain from './mydomain';
export const state = create({
mydomain,
});
// ./state/mydomain/index.ts
import { domain } from 'diddi';
interface IState {
value: number;
}
function initialstate(): IState {
return {
value: 0,
};
}
function actions() {
return {
decrement,
increment,
set,
setAsync,
}
}
function decrement(state: IState) {
return {
value: state.value - 1,
}
}
function increment(state: IState) {
return {
value: state.value + 1,
}
}
function set(state: IState, value: number) {
return { value };
}
async function setAsync(state: IState, value: number) {
// becase reasons
return new Promise(resolve =>
setTimeout(
() => resolve({ value }),
100
)
);
}
export default domain(initialstate, actions);;
// ./app.ts
import { state } from './state';
const { get, actions } = state;
await actions.mydomain.set(10)
await actions.mydomain.decrement()
await actions.mydomain.decrement()
await actions.mydomain.increment()
get() // { mydomain: { value: 9 } }
Since an action is a function, you can compose them as you want.
import { domain } from 'diddi';
import * as api from './api';
interface IState {
content: string;
title: string;
wordcount: number;
}
function actions() {
return {
load,
setWordCount,
}
}
function initialstate() {
return {
content: '',
title: '',
wordcount: 0,
};
}
const myblogpost = domain(initialstate, actions);
async function load(state: IState) {
const newstate = await api.load();
return setWordCount({... state, ...newstate});
}
function setWordCount(state: IState) {
return {
... state,
wordcount: state.content.match(/\S+/g),
}
}
You could sometimes have a particular scenario where you want some actions to be run in parallels or in waterfall.
To control actions flow, you have to simply create a new function which will await single actions
Parallel actions could lead to wrong state merging. To prevent this behaviour, you will have to merge domain's state by excluding properties which will be updated in parallel
// state/index.ts
import { create, domain } from 'diddi';
interface IState {
userscount: number;
rolescount: number;
loading: boolean;
users: IUser[];
roles: IRole[];
}
function initialstate(): IState {
return {
loading: false,
roles: [],
rolescount: 0,
users: [],
userscount: 0,
};
}
function actions() {
return {
loadroles,
loadusers,
setloading,
}
}
async function loadusers(state: IState) {
const users = await api.loadusers();
const userscount = users.length;
// done this in order to avoid overriding of roles and rolescount
const { loading } = state;
return {
loading,
users,
userscount,
};
}
async function loadroles(state: IState) {
const roles = await api.loadroles();
const rolescount = roles.length;
// done this in order to avoid overriding of users and userscount
const { loading } = state;
return {
loading,
roles,
rolescount,
};
}
function setloading(state: IState, loading: boolean) {
return {
... state,
loading,
};
}
const mydomain = domain(initialstate, actions);
export default create({ mydomain });
// ./otherfile.ts
import state from './state';
export async function loadseries() {
const { mydomain } = state.actions;
await mydomain.setloading(true);
await mydomain.loadusers();
await mydomain.loadroles();
await mydomain.setloading(false);
}
export async function loadparallel() {
const { mydomain } = state.actions;
await mydomain.setloading(true);
Promise.all([ mydomain.loadusers(), mydomain.loadroles() ]);
await mydomain.setloading(false);
}
import { build, MiddlewareFn } from 'diddi';
import mydomain from './mydomain';
function logger(): MiddlewareFn {
return message => {
const {
action,
domain,
state,
} = message;
console.log(
`[${domain}][${action}]`,
'previous', state.prev,
'next', state.next,
);
return nextstate;
}
}
const state = build({ mydomain }, logger);
state.actions.mydomain.set(10) // logs: [update][mydomain][set] previous { value: 0 } next { value: 10 }
Predefined scripts:
The create function simply creates a new state.
It accepts one parameter which is an object of key/value pairs, where keys are domain names and values are domains
A created state, returns an object with one property and two functions:
const state = create({ mydomain });
state.subscribe(message => console.log(message.domain, message.state));
state.actions.mydomain.set(10) // logs: 'mydomain', { value: 10 }
To create domain use it's related function.
This function accepts two functions, one which returns the initial domain state and the other which returns an object containing actions
import { domain } from 'diddi';
// domain's state interface
interface IDomainState { }
function initialstate(): IDomainState {
return { }
}
function actions() {
return { }
}
export default domain(initialstate, actions);
Every contribution is really welcome!
If you feel that something can be improved or should be fixed, feel free to open an issue with the feature or the bug found.
If you want to fork and open a pull request (adding features or fixes), feel free to do it. Remember only to use the master branch as a base.
If you plan adding a new feature, please prefix the branch with the feat/branchname.
If you plan fixing something, please prefix the branch with the fix/branchname.
If you plan refactoring something, please prefix the branch with the refactor/branchname.
If you adding something which does not involve the runtime behavious, please prefix the branch with the chore/branchname.
Read the contributing guidelines
Read the licence
FAQs
Just another juicy state manager lib for your js apps.
We found that diddi 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
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.