Socket
Socket
Sign inDemoInstall

overmind

Package Overview
Dependencies
Maintainers
4
Versions
886
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

overmind - npm Package Compare versions

Comparing version 27.0.0-1611398336423 to 27.0.0-1624124645626

es/operators.d.ts

4

es/config/config.test.js

@@ -53,4 +53,4 @@ import { __awaiter } from "tslib";

actions: {
loadConfigB: ({ effects }) => {
return effects.lazy.loadConfig('configB');
loadConfigB: ({ actions }) => {
return actions.lazy.loadConfig('configB');
},

@@ -57,0 +57,0 @@ },

@@ -5,3 +5,2 @@ import { SubType } from '../internalTypes';

[namespace: string]: () => Promise<{
onInitialize?: any;
state?: {};

@@ -14,3 +13,2 @@ effects?: {};

export declare function lazy<T extends LazyConfiguration>(configurations: T): {
onInitialize?: any;
state: SubType<{

@@ -25,7 +23,3 @@ [P in keyof T]?: ReturnType<T[P]> extends Promise<infer U> ? U extends {

} ? U['effects'] : never : never;
}, object> & {
lazy: {
loadConfig: (config: keyof T) => Promise<void>;
};
};
}, object>;
actions: SubType<{

@@ -37,3 +31,3 @@ [P in keyof T]?: ReturnType<T[P]> extends Promise<infer U> ? U extends {

lazy: {
loadConfig: IAction<any, keyof T>;
loadConfig: IAction<keyof T, any>;
};

@@ -40,0 +34,0 @@ };

@@ -1,35 +0,12 @@

import { __rest } from "tslib";
import { namespaced } from './namespaced';
import { processState } from '../utils';
export function lazy(configurations) {
let app;
return {
onInitialize(_, value) {
app = value;
},
effects: {
lazy: {
loadConfig(config) {
return app.actions.lazy.loadConfig(config);
},
},
},
actions: {
lazy: {
loadConfig(_a, key) {
var { state, execution } = _a, rest = __rest(_a, ["state", "execution"]);
loadConfig({ state, execution, addNamespace }, key) {
const configToLoad = configurations[key];
const namespacePath = execution.namespacePath.slice(0, execution.namespacePath.length - 1).concat(key);
const namespacePath = execution.namespacePath
.slice(0, execution.namespacePath.length - 1)
.concat(key);
return configToLoad().then((loadedConfig) => {
const newConfig = namespaced({
[key]: loadedConfig,
});
if (newConfig.state && newConfig.state[key])
state[key] = processState(newConfig.state[key]);
if (newConfig.effects && newConfig.effects[key])
app.effects[key] = newConfig.effects[key];
if (newConfig.actions && newConfig.actions[key])
app.actions[key] = app.getActions(newConfig.actions[key], namespacePath);
if (newConfig.onInitialize)
newConfig.onInitialize(Object.assign({ state, execution: Object.assign(Object.assign({}, execution), { namespacePath }) }, rest), app);
addNamespace(loadedConfig, namespacePath, state);
});

@@ -36,0 +13,0 @@ },

@@ -28,3 +28,2 @@ import isPlainObject from 'is-plain-obj';

export function merge(...configurations) {
const initializers = configurations.reduce((aggr, config) => config.onInitialize ? aggr.concat(config.onInitialize) : aggr, []);
const rootConfiguration = configurations.shift();

@@ -51,3 +50,2 @@ const reducedConfigurations = configurations.reduce((aggr, config) => {

return {
onInitialize: aggr.onInitialize,
state: copy(aggr.state, config.state || {}),

@@ -57,7 +55,5 @@ effects: Object.assign(Object.assign({}, aggr.effects), config.effects),

};
}, Object.assign(Object.assign({ state: {}, actions: {}, effects: {} }, rootConfiguration), { onInitialize: initializers.length
? (context, value) => Promise.all(initializers.map((cb) => cb(context, value)))
: undefined }));
}, Object.assign({ state: {}, actions: {}, effects: {} }, rootConfiguration));
return reducedConfigurations;
}
//# sourceMappingURL=merge.js.map
import { SubType } from '../internalTypes';
interface NamespacedConfiguration {
[namespace: string]: {
onInitialize?: any;
state?: {};

@@ -12,3 +11,2 @@ effects?: {};

export declare function namespaced<T extends NamespacedConfiguration>(namespaces: T): {
onInitialize?: any;
state: SubType<{

@@ -15,0 +13,0 @@ [P in keyof T]: T[P]['state'];

function parseNamespacedConfig(result, name, config) {
const { actions, effects, onInitialize, state } = config;
const { actions, effects, state } = config;
if (actions) {

@@ -12,5 +12,2 @@ result.actions[name] = actions;

}
if (onInitialize) {
result.initializers[name] = onInitialize;
}
}

@@ -31,5 +28,4 @@ export function namespaced(namespaces) {

state: result.state,
onInitialize: (context, app) => Promise.all(Object.keys(result.initializers).map((key) => result.initializers[key](Object.assign(Object.assign({}, context), { execution: Object.assign(Object.assign({}, context.execution), { namespacePath: context.execution.namespacePath.concat(key) }) }), app))),
});
}
//# sourceMappingURL=namespaced.js.map

@@ -20,3 +20,5 @@ import { IS_PROXY, TrackStateTree, } from 'proxy-state-tree';

runScope(tree, path) {
const parent = path.slice(0, path.length - 1).reduce((curr, key) => curr[key], tree.state);
const parent = path
.slice(0, path.length - 1)
.reduce((curr, key) => curr[key], tree.state);
return this.cb(parent, tree.state);

@@ -34,3 +36,3 @@ }

}
for (let mutationPath of paths) {
for (const mutationPath of paths) {
if (this.paths.has(mutationPath)) {

@@ -70,3 +72,3 @@ this.isDirty = true;

// is for nested derived
for (let path of this.paths) {
for (const path of this.paths) {
tree.addTrackingPath(path);

@@ -73,0 +75,0 @@ tree.trackPathListeners.forEach((cb) => cb(path));

@@ -26,15 +26,15 @@ import { __awaiter } from "tslib";

foo: 'bar',
upperFoo: derived((state) => state.foo.toUpperCase())
upperFoo: derived((state) => state.foo.toUpperCase()),
};
const actions = {
changeFoo,
removeDerived,
};
const config = {
state,
actions: {
changeFoo,
removeDerived
},
actions,
};
const app = new Overmind(config);
const trackStateTree = app.getTrackStateTree();
const onTrack = () => {
};
const onTrack = () => { };
function render() {

@@ -54,3 +54,3 @@ trackStateTree.track(onTrack);

// The dirty event is async
yield new Promise(resolve => setTimeout(resolve, 0));
yield new Promise((resolve) => setTimeout(resolve, 0));
expect(dirtyCount).toBe(1);

@@ -67,15 +67,15 @@ }));

foo: 'bar',
upperFoo: null
upperFoo: null,
};
const actions = {
changeFoo,
addDerived,
};
const config = {
state,
actions: {
changeFoo,
addDerived
},
actions,
};
const app = new Overmind(config);
const trackStateTree = app.getTrackStateTree();
const onTrack = () => {
};
const onTrack = () => { };
function render() {

@@ -103,7 +103,8 @@ trackStateTree.track(onTrack);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -132,7 +133,8 @@ const app = new Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -163,7 +165,8 @@ const app = new Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -183,7 +186,8 @@ const app = new Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -203,10 +207,11 @@ const app = new Overmind(config);

foo: 'bar',
upperFoo: derived((parent) => parent.foo.toUpperCase())
}
upperFoo: derived((parent) => parent.foo.toUpperCase()),
},
};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -238,3 +243,3 @@ const app = new Overmind(config);

const state = {
class: new SomeClass()
class: new SomeClass(),
};

@@ -241,0 +246,0 @@ const config = {

@@ -60,3 +60,7 @@ import { __awaiter } from "tslib";

});
this.name = typeof location !== 'undefined' && location.search.includes('OVERMIND_DEVTOOL') ? name + ' (Overmind Devtool)' : name;
this.name =
typeof location !== 'undefined' &&
location.search.includes('OVERMIND_DEVTOOL')
? name + ' (Overmind Devtool)'
: name;
}

@@ -81,3 +85,3 @@ reconnect(host, onMessage) {

name: value.constructor.name,
value
value,
};

@@ -94,3 +98,4 @@ }

circularReferenceCache.push(value);
if (!safeClassNames.has(value.constructor.name) && !unsafeClassNames.has(value.constructor.name)) {
if (!safeClassNames.has(value.constructor.name) &&
!unsafeClassNames.has(value.constructor.name)) {
try {

@@ -108,3 +113,3 @@ JSON.stringify(value);

name: value.constructor.name,
value
value,
};

@@ -111,0 +116,0 @@ }

@@ -1,114 +0,15 @@

import { EventEmitter } from 'betsy';
import { IFlushCallback, IMutation, IMutationCallback, IMutationTree, ITrackStateTree } from 'proxy-state-tree';
import { Devtools } from './Devtools';
import { DefaultMode, Events, NestedPartial, Options, ResolveActions, SSRMode, TestMode } from './internalTypes';
import { createMutationOperator, createOperator } from './operator';
import { IAction, IConfiguration, IContext, IOnInitialize, IOperator, IReaction } from './types';
import * as internalTypes from './internalTypes';
import { Overmind } from './Overmind';
import { IConfiguration } from './types';
export * from './types';
export { createOperator, createMutationOperator, ResolveActions };
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT } from './utils';
export * from './operators';
export { Overmind } from './Overmind';
export { ResolveAction, OperatorContextFunction, ContextFunction, } from './internalTypes';
export { createOperator, createMutationOperator } from './operator';
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT, json } from './utils';
export { SERIALIZE, rehydrate } from './rehydrate';
export { Statemachine, statemachine } from './statemachine';
export * from './OvermindMock';
export * from './OvermindSSR';
export declare const derived: <S extends object, R extends object, O>(cb: (state: S, rootState: R) => O) => O;
/** This type can be overwriten by app developers if they want to avoid
* typing and then they can import `Action`, `Operation` etc. directly from
* overmind.
*/
export interface Config {
}
export interface Context extends IContext<Config> {
}
export declare type RootState = Context['state'];
export interface Action<Value = void, ReturnValue = void> extends IAction<Config, Value, ReturnValue> {
}
export interface AsyncAction<Value = void, ReturnValue = void> extends IAction<Config, Value, Promise<ReturnValue>> {
}
export interface OnInitialize extends IOnInitialize<Config> {
}
export interface Reaction extends IReaction<Config> {
}
export { json } from './utils';
export interface OvermindSSR<Config extends IConfiguration> extends Overmind<Config> {
hydrate(): IMutation[];
}
export declare function createOvermindSSR<Config extends IConfiguration>(config: Config): OvermindSSR<Config>;
export interface OvermindMock<Config extends IConfiguration> extends Overmind<Config> {
onInitialize: () => Promise<IMutation[]>;
mutations: IMutation[];
}
export declare function createOvermindMock<Config extends IConfiguration>(config: Config): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, setInitialState: (state: Config['state']) => void): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, mockedEffects: NestedPartial<Config['effects']>): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, mockedEffects: NestedPartial<Config['effects']>, setInitialState: (state: Config['state']) => void): OvermindMock<Config>;
export declare function createOvermind<Config extends IConfiguration>(config: Config, options?: Options): Overmind<Config>;
export declare class Overmind<ThisConfig extends IConfiguration> implements IConfiguration {
private proxyStateTree;
private actionReferences;
private nextExecutionId;
private mode;
private reydrateMutationsForHotReloading;
private originalConfiguration;
private isStrict;
initialized: Promise<any>;
eventHub: EventEmitter<Events>;
devtools: Devtools;
actions: ResolveActions<ThisConfig['actions']>;
state: ThisConfig['state'];
effects: ThisConfig['effects'] & {};
delimiter: string;
constructor(configuration: ThisConfig, options?: Options, mode?: DefaultMode | TestMode | SSRMode);
private createProxyStateTree;
private createExecution;
private createContext;
private scopeValue;
private addExecutionMutation;
private createAction;
private trackEffects;
private initializeDevtools;
private getState;
private getActions;
private updateActions;
getTrackStateTree(): ITrackStateTree<any>;
getMutationTree(): IMutationTree<any>;
reaction: IReaction<ThisConfig>;
addMutationListener: (cb: IMutationCallback) => () => void;
addFlushListener: (cb: IFlushCallback) => () => IFlushCallback[];
reconfigure(configuration: IConfiguration): this;
}
export declare type Operator<Input = void, Output = Input> = IOperator<Config, Input, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, Output = B>(aOperator: IOperator<ThisConfig, A, B>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, Output = C>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, Output = D>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, Output = E>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, Output = F>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, Output = G>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, Output = H>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>): IOperator<ThisConfig, A, I extends never ? any : I>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I, J>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>, iOperator: IOperator<ThisConfig, I, J>): IOperator<ThisConfig, A, J extends never ? any : J>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I, J, K>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>, iOperator: IOperator<ThisConfig, I, J>, jOperator: IOperator<ThisConfig, J, K>): IOperator<ThisConfig, A, K extends never ? any : K>;
export declare function forEach<Input extends any[], ThisConfig extends IConfiguration = Config>(forEachItemOperator: IOperator<ThisConfig, Input extends Array<infer U> ? U : never>): IOperator<ThisConfig, Input, Input>;
export declare function parallel<Input, ThisConfig extends IConfiguration = Config>(...operators: IOperator<ThisConfig, Input>[]): IOperator<ThisConfig, Input, Input>;
export declare function map<Input, Output, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => Output): IOperator<ThisConfig, Input, Output extends Promise<infer U> ? U : Output>;
export declare function noop<Input, ThisConfig extends IConfiguration = Config>(): IOperator<ThisConfig, Input>;
export declare function filter<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => boolean): IOperator<ThisConfig, Input, Input>;
export declare function action<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function mutate<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function run<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function catchError<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Error) => Input): IOperator<ThisConfig, Input, Input>;
export declare function tryCatch<Input, ThisConfig extends IConfiguration = Config>(paths: {
try: IOperator<ThisConfig, Input>;
catch: IOperator<ThisConfig, Error>;
}): IOperator<ThisConfig, Input, Input>;
export declare function fork<Input, Paths extends {
[key: string]: IOperator<ThisConfig, any, any>;
}, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => keyof Paths, paths: Paths & {
[N in keyof Paths]: IOperator<ThisConfig, Input, any>;
}): IOperator<ThisConfig, Input, Input>;
export declare function when<Input, OutputA, OutputB, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => boolean, paths: {
true: IOperator<ThisConfig, Input, OutputA>;
false: IOperator<ThisConfig, Input, OutputB>;
}): IOperator<ThisConfig, Input, OutputA | OutputB>;
export declare function wait<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function debounce<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function throttle<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function waitUntil<Input, ThisConfig extends IConfiguration = Config>(operation: (state: ThisConfig['state']) => boolean): IOperator<ThisConfig, Input, Input>;
export declare function createOvermind<Config extends IConfiguration>(config: Config, options?: internalTypes.Options): Overmind<Config>;

@@ -1,16 +0,13 @@

import { EventEmitter } from 'betsy';
import isPlainObject from 'is-plain-obj';
import { IS_PROXY, PATH, ProxyStateTree, VALUE, } from 'proxy-state-tree';
import { Derived, IS_DERIVED, IS_DERIVED_CONSTRUCTOR } from './derived';
import { Devtools } from './Devtools';
import { EventType, } from './internalTypes';
import { createContext, createMutationOperator, createNextPath, createOperator, operatorStarted, operatorStopped, } from './operator';
import { proxifyEffects } from './proxyfyEffects';
import { rehydrate } from './rehydrate';
import { ENVIRONMENT, EXECUTION, IS_OPERATOR, IS_TEST, MODE_DEFAULT, MODE_SSR, MODE_TEST, MockedEventEmitter, createActionsProxy, deepCopy, getActionPaths, getChangeMutations, getFunctionName, isPromise, processState, } from './utils';
import { IS_DERIVED_CONSTRUCTOR } from './derived';
import { Overmind } from './Overmind';
import * as utils from './utils';
export * from './types';
export { createOperator, createMutationOperator };
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT } from './utils';
export * from './operators';
export { Overmind } from './Overmind';
export { createOperator, createMutationOperator } from './operator';
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT, json } from './utils';
export { SERIALIZE, rehydrate } from './rehydrate';
export { statemachine } from './statemachine';
export * from './OvermindMock';
export * from './OvermindSSR';
export const derived = (cb) => {

@@ -20,997 +17,5 @@ cb[IS_DERIVED_CONSTRUCTOR] = true;

};
export { json } from './utils';
export function createOvermindSSR(config) {
const ssr = new Overmind(config, {
devtools: false,
}, {
mode: MODE_SSR,
});
const mutationTree = ssr.proxyStateTree.getMutationTree();
ssr.state = mutationTree.state;
ssr.hydrate = () => {
return mutationTree.flush().mutations;
};
return ssr;
}
export function createOvermindMock(...args) {
const setState = typeof args[1] === 'function' ? args[1] : args[2];
const mockedEffects = typeof args[1] === 'function' ? undefined : args[1];
const state = deepCopy(args[0].state);
if (setState) {
;
setState(state);
}
const mock = new Overmind(Object.assign({}, args[0], {
state,
}), {
devtools: false,
}, {
mode: MODE_TEST,
options: {
effectsCallback: (effect) => {
const mockedEffect = (effect.name
? effect.name.split('.')
: []).reduce((aggr, key) => (aggr ? aggr[key] : aggr), mockedEffects);
if (!mockedEffect || (mockedEffect && !mockedEffect[effect.method])) {
throw new Error(`The effect "${effect.name}" with method ${effect.method} has not been mocked`);
}
return mockedEffect[effect.method](...effect.args);
},
},
});
const action = mock.createAction('onInitialize', args[0].onInitialize);
mock.onInitialize = () => action(mock);
mock.mutations = [];
return mock;
}
export function createOvermind(config, options) {
return new Overmind(config, options, { mode: MODE_DEFAULT });
return new Overmind(config, options, { mode: utils.MODE_DEFAULT });
}
const hotReloadingCache = {};
// We do not use IConfig<Config> directly to type the class in order to avoid
// the 'import(...)' function to be used in exported types.
export class Overmind {
constructor(configuration, options = {}, mode = {
mode: MODE_DEFAULT,
}) {
this.actionReferences = {};
this.nextExecutionId = 0;
this.reydrateMutationsForHotReloading = [];
this.isStrict = false;
this.reaction = (stateCallback, updateCallback, options = {}) => {
let disposer;
if (options.nested) {
const value = stateCallback(this.state);
if (!value || !value[IS_PROXY]) {
throw new Error('You have to return an object or array from the Overmind state when using a "nested" reaction');
}
const path = value[PATH];
disposer = this.addFlushListener((mutations) => {
mutations.forEach((mutation) => {
if (mutation.path.startsWith(path)) {
updateCallback(path
? path
.split(this.delimiter)
.reduce((aggr, key) => aggr[key], this.state)
: this.state);
}
});
});
}
else {
const tree = this.proxyStateTree.getTrackStateTree();
let returnValue;
const updateReaction = () => {
tree.trackScope(() => (returnValue = stateCallback(tree.state)), () => {
updateReaction();
updateCallback(returnValue);
});
};
updateReaction();
disposer = () => {
tree.dispose();
};
}
if (options.immediate) {
updateCallback(stateCallback(this.state));
}
return disposer;
};
this.addMutationListener = (cb) => {
return this.proxyStateTree.onMutation(cb);
};
this.addFlushListener = (cb) => {
return this.proxyStateTree.onFlush(cb);
};
const name = options.name || 'OvermindApp';
const devEnv = options.devEnv || 'development';
const isNode = process && process.title && process.title.includes('node');
this.delimiter = options.delimiter || '.';
this.isStrict = Boolean(options.strict);
if (ENVIRONMENT === devEnv &&
mode.mode === MODE_DEFAULT &&
options.hotReloading !== false &&
!isNode) {
if (hotReloadingCache[name]) {
return hotReloadingCache[name].reconfigure(configuration);
}
else {
hotReloadingCache[name] = this;
}
}
/*
Set up an eventHub to trigger information from derived, computed and reactions
*/
const eventHub = mode.mode === MODE_SSR
? new MockedEventEmitter()
: new EventEmitter();
/*
Create the proxy state tree instance with the state and a wrapper to expose
the eventHub
*/
const proxyStateTree = this.createProxyStateTree(configuration, eventHub, mode.mode === MODE_TEST || ENVIRONMENT === devEnv, mode.mode === MODE_SSR);
this.originalConfiguration = configuration;
this.state = proxyStateTree.state;
this.effects = configuration.effects || {};
this.proxyStateTree = proxyStateTree;
this.eventHub = eventHub;
this.mode = mode;
/*
Expose the created actions
*/
this.actions = this.getActions(configuration.actions);
if (mode.mode === MODE_SSR) {
return;
}
if (ENVIRONMENT === devEnv &&
mode.mode === MODE_DEFAULT &&
typeof window !== 'undefined') {
let warning = 'OVERMIND: You are running in DEVELOPMENT mode.';
if (options.logProxies !== true) {
const originalConsoleLog = console.log;
console.log = (...args) => originalConsoleLog.apply(console, args.map((arg) => (arg && arg[IS_PROXY] ? arg[VALUE] : arg)));
warning +=
'\n\n - To improve debugging experience "console.log" will NOT log proxies from Overmind, but the actual value. Please see docs to turn off this behaviour';
}
if (options.devtools ||
(typeof location !== 'undefined' &&
location.hostname === 'localhost' &&
options.devtools !== false)) {
const host = options.devtools === true ? 'localhost:3031' : options.devtools;
const name = options.name
? options.name
: typeof document === 'undefined'
? 'NoName'
: document.title || 'NoName';
this.initializeDevtools(host, name, eventHub, proxyStateTree.sourceState, configuration.actions);
}
else if (options.devtools !== false) {
warning +=
'\n\n - You are not running on localhost. You will have to manually define the devtools option to connect';
}
if (!IS_TEST) {
console.warn(warning);
}
}
if (ENVIRONMENT === 'production' && mode.mode === MODE_DEFAULT) {
eventHub.on(EventType.OPERATOR_ASYNC, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
proxyStateTree.getMutationTree().flush(true);
}
});
eventHub.on(EventType.ACTION_END, (execution) => {
if (!execution.parentExecution || !execution.parentExecution.isRunning)
proxyStateTree.getMutationTree().flush();
});
let nextTick;
const flushTree = () => {
proxyStateTree.getMutationTree().flush(true);
};
this.proxyStateTree.onMutation(() => {
nextTick && clearTimeout(nextTick);
nextTick = setTimeout(flushTree, 0);
});
}
else if (mode.mode === MODE_DEFAULT || mode.mode === MODE_TEST) {
if (ENVIRONMENT === 'test' ||
(this.devtools && options.hotReloading !== false)) {
eventHub.on(EventType.MUTATIONS, (execution) => {
this.reydrateMutationsForHotReloading = this.reydrateMutationsForHotReloading.concat(execution.mutations);
});
}
eventHub.on(EventType.OPERATOR_ASYNC, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
const flushData = execution.flush(true);
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign({}, execution), flushData),
});
}
}
});
eventHub.on(EventType.ACTION_END, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
const flushData = execution.flush();
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign({}, execution), flushData),
});
}
}
});
}
if (mode.mode === MODE_DEFAULT && configuration.onInitialize) {
const onInitialize = this.createAction('onInitialize', configuration.onInitialize);
this.initialized = Promise.resolve(onInitialize(this));
}
else {
this.initialized = Promise.resolve(null);
}
}
createProxyStateTree(configuration, eventHub, devmode, ssr) {
const proxyStateTree = new ProxyStateTree(this.getState(configuration), {
devmode,
ssr,
delimiter: this.delimiter,
onSetFunction: (tree, path, target, prop, func) => {
if (func[IS_DERIVED_CONSTRUCTOR]) {
return new Derived(func);
}
return func;
},
onGetFunction: (tree, path, target, prop) => {
let func = target[prop];
if (func[IS_DERIVED]) {
return func(eventHub, tree, proxyStateTree, path.split(this.delimiter));
}
if (func[IS_DERIVED_CONSTRUCTOR]) {
const derived = new Derived(func);
target[prop] = derived;
return derived(eventHub, tree, proxyStateTree, path.split(this.delimiter));
}
return func;
},
onGetter: devmode
? (path, value) => {
this.eventHub.emitAsync(EventType.GETTER, {
path,
value,
});
}
: undefined,
});
return proxyStateTree;
}
createExecution(name, action, parentExecution) {
const namespacePath = name.split('.');
namespacePath.pop();
if (ENVIRONMENT === 'production') {
return {
[EXECUTION]: true,
parentExecution,
namespacePath,
actionName: name,
getMutationTree: () => {
return this.proxyStateTree.getMutationTree();
},
getTrackStateTree: () => {
return this.proxyStateTree.getTrackStateTree();
},
emit: this.eventHub.emit.bind(this.eventHub),
};
}
const mutationTrees = [];
const execution = {
[EXECUTION]: true,
namespacePath,
actionId: name,
executionId: this.nextExecutionId++,
actionName: name,
operatorId: 0,
isRunning: true,
parentExecution,
path: [],
emit: this.eventHub.emit.bind(this.eventHub),
send: this.devtools ? this.devtools.send.bind(this.devtools) : () => { },
trackEffects: this.trackEffects.bind(this, this.effects),
getNextOperatorId: (() => {
let currentOperatorId = 0;
return () => ++currentOperatorId;
})(),
flush: parentExecution
? parentExecution.flush
: (isAsync) => {
return this.proxyStateTree.flush(mutationTrees, isAsync);
},
getMutationTree: parentExecution
? parentExecution.getMutationTree
: () => {
const mutationTree = this.proxyStateTree.getMutationTree();
mutationTrees.push(mutationTree);
return mutationTree;
},
getTrackStateTree: () => {
return this.proxyStateTree.getTrackStateTree();
},
onFlush: (cb) => {
return this.proxyStateTree.onFlush(cb);
},
scopeValue: (value, tree) => {
return this.scopeValue(value, tree);
},
};
return execution;
}
createContext(execution, tree) {
return {
state: tree.state,
actions: createActionsProxy(this.actions, (action) => {
return (value) => action(value, execution.isRunning ? execution : null);
}),
execution,
proxyStateTree: this.proxyStateTree,
effects: this.trackEffects(this.effects, execution),
};
}
scopeValue(value, tree) {
if (!value) {
return value;
}
if (value[IS_PROXY]) {
return this.proxyStateTree.rescope(value, tree);
}
else if (isPlainObject(value)) {
return Object.assign({}, ...Object.keys(value).map((key) => ({
[key]: this.proxyStateTree.rescope(value[key], tree),
})));
}
else {
return value;
}
}
addExecutionMutation(mutation) {
;
this.mutations.push(mutation);
}
createAction(name, originalAction) {
this.actionReferences[name] = originalAction;
const actionFunc = (value, boundExecution) => {
const action = this.actionReferences[name];
// Developer might unintentionally pass more arguments, so have to ensure
// that it is an actual execution
boundExecution =
boundExecution && boundExecution[EXECUTION] ? boundExecution : undefined;
if (ENVIRONMENT === 'production' || action[IS_OPERATOR]) {
const execution = this.createExecution(name, action, boundExecution);
this.eventHub.emit(EventType.ACTION_START, Object.assign(Object.assign({}, execution), { value }));
if (action[IS_OPERATOR]) {
return new Promise((resolve, reject) => {
action(null, Object.assign(Object.assign({}, this.createContext(execution, this.proxyStateTree)), { value }), (err, finalContext) => {
execution.isRunning = false;
finalContext &&
this.eventHub.emit(EventType.ACTION_END, Object.assign(Object.assign({}, finalContext.execution), { operatorId: finalContext.execution.operatorId - 1 }));
if (err)
reject(err);
else {
resolve(this.mode.mode === MODE_TEST
? finalContext.execution
: undefined);
}
});
});
}
else {
const mutationTree = execution.getMutationTree();
if (this.isStrict) {
mutationTree.blockMutations();
}
const returnValue = action(this.createContext(execution, mutationTree), value);
this.eventHub.emit(EventType.ACTION_END, execution);
return returnValue;
}
}
else {
const execution = Object.assign(Object.assign({}, this.createExecution(name, action, boundExecution)), { operatorId: 0, type: 'action' });
this.eventHub.emit(EventType.ACTION_START, Object.assign(Object.assign({}, execution), { value }));
this.eventHub.emit(EventType.OPERATOR_START, execution);
const mutationTree = execution.getMutationTree();
if (this.isStrict) {
mutationTree.blockMutations();
}
mutationTree.onMutation((mutation) => {
this.eventHub.emit(EventType.MUTATIONS, Object.assign(Object.assign({}, execution), { mutations: [mutation] }));
});
const scopedValue = this.scopeValue(value, mutationTree);
const context = this.createContext(execution, mutationTree);
try {
let pendingFlush;
mutationTree.onMutation((mutation) => {
if (pendingFlush) {
clearTimeout(pendingFlush);
}
if (this.mode.mode === MODE_TEST) {
this.addExecutionMutation(mutation);
}
pendingFlush = setTimeout(() => {
pendingFlush = null;
const flushData = execution.flush(true);
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign(Object.assign({}, execution), flushData), { mutations: flushData.mutations }),
});
}
});
});
let result = action(context, scopedValue);
if (isPromise(result)) {
this.eventHub.emit(EventType.OPERATOR_ASYNC, execution);
result = result
.then((promiseResult) => {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: true, result: undefined }));
this.eventHub.emit(EventType.ACTION_END, execution);
return promiseResult;
})
.catch((error) => {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: true, result: undefined, error: error.message }));
this.eventHub.emit(EventType.ACTION_END, execution);
throw error;
});
}
else {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: false, result: undefined }));
this.eventHub.emit(EventType.ACTION_END, execution);
}
return result;
}
catch (err) {
this.eventHub.emit(EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: false, result: undefined, error: err.message }));
this.eventHub.emit(EventType.ACTION_END, execution);
throw err;
}
}
};
return actionFunc;
}
trackEffects(effects = {}, execution) {
if (ENVIRONMENT === 'production') {
return effects;
}
return proxifyEffects(this.effects, (effect) => {
let result;
try {
if (this.mode.mode === MODE_TEST) {
const mode = this.mode;
result = mode.options.effectsCallback(effect);
}
else {
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: true, error: false }));
result = effect.func.apply(this, effect.args);
}
}
catch (error) {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: false, error: error.message }));
throw error;
}
if (isPromise(result)) {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: true, error: false }));
return result
.then((promisedResult) => {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, result: promisedResult, isPending: false, error: false }));
return promisedResult;
})
.catch((error) => {
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: false, error: error && error.message }));
throw error;
});
}
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, result: result, isPending: false, error: false }));
return result;
});
}
initializeDevtools(host, name, eventHub, initialState, actions) {
if (ENVIRONMENT === 'production')
return;
const devtools = new Devtools(name);
devtools.connect(host, (message) => {
switch (message.type) {
case 'refresh':
location.reload(true);
break;
case 'executeAction':
const action = message.data.name
.split('.')
.reduce((aggr, key) => aggr[key], this.actions);
message.data.payload
? action(JSON.parse(message.data.payload))
: action();
break;
case 'mutation':
const tree = this.proxyStateTree.getMutationTree();
const path = message.data.path.slice();
const value = JSON.parse(`{ "value": ${message.data.value} }`).value;
const key = path.pop();
const state = path.reduce((aggr, key) => aggr[key], tree.state);
state[key] = value;
tree.flush(true);
tree.dispose();
this.devtools.send({
type: 'state',
data: {
path: message.data.path,
value,
},
});
}
});
for (let type in EventType) {
eventHub.on(EventType[type], ((eventType) => (data) => {
devtools.send({
type: EventType[type],
data,
});
if (eventType === EventType.MUTATIONS) {
// We want to trigger property access when setting objects and arrays, as any derived set would
// then trigger and update the devtools
data.mutations.forEach((mutation) => {
const value = mutation.path
.split(this.delimiter)
.reduce((aggr, key) => aggr[key], this.proxyStateTree.state);
if (isPlainObject(value)) {
Object.keys(value).forEach((key) => value[key]);
}
else if (Array.isArray(value)) {
value.forEach((item) => {
if (isPlainObject(item)) {
Object.keys(item).forEach((key) => item[key]);
}
});
}
});
}
// Access the derived which will trigger calculation and devtools
if (eventType === EventType.DERIVED_DIRTY) {
data.derivedPath.reduce((aggr, key) => aggr[key], this.proxyStateTree.state);
}
})(EventType[type]));
}
devtools.send({
type: 'init',
data: {
state: this.proxyStateTree.state,
actions: getActionPaths(actions),
delimiter: this.delimiter,
},
});
this.devtools = devtools;
}
getState(configuration) {
let state = {};
if (configuration.state) {
state = processState(configuration.state);
}
return state;
}
getActions(actions = {}, path = []) {
return Object.keys(actions).reduce((aggr, name) => {
if (typeof actions[name] === 'function') {
const action = this.createAction(path.concat(name).join('.'), actions[name]);
action.displayName = path.concat(name).join('.');
return Object.assign(aggr, {
[name]: action,
});
}
return Object.assign(aggr, {
[name]: this.getActions(actions[name], path.concat(name)),
});
}, {});
}
/*
Related to hot reloading we update the existing action references and add any new
actions.
*/
updateActions(actions = {}, path = []) {
Object.keys(actions).forEach((name) => {
if (typeof actions[name] === 'function') {
const actionName = path.concat(name).join('.');
if (this.actionReferences[actionName]) {
this.actionReferences[actionName] = actions[name];
}
else {
const target = path.reduce((aggr, key) => {
if (!aggr[key]) {
aggr[key] = {};
}
return aggr[key];
}, this.actions);
target[name] = this.createAction(actionName, actions[name]);
target[name].displayName = path.concat(name).join('.');
}
}
else {
this.updateActions(actions[name], path.concat(name));
}
}, {});
}
getTrackStateTree() {
return this.proxyStateTree.getTrackStateTree();
}
getMutationTree() {
return this.proxyStateTree.getMutationTree();
}
reconfigure(configuration) {
const changeMutations = getChangeMutations(this.originalConfiguration.state, configuration.state || {});
this.updateActions(configuration.actions);
this.effects = configuration.effects || {};
const mutationTree = this.proxyStateTree.getMutationTree();
// We change the state to match the new structure
rehydrate(mutationTree.state, changeMutations);
// We run any mutations ran during the session, it might fail though
// as the state structure might have changed, but no worries we just
// ignore that
this.reydrateMutationsForHotReloading.forEach((mutation) => {
try {
rehydrate(mutationTree.state, [mutation]);
}
catch (error) {
// No worries, structure changed and we do not want to mutate anyways
}
});
mutationTree.flush();
mutationTree.dispose();
if (this.devtools) {
this.devtools.send({
type: 're_init',
data: {
state: this.state,
actions: getActionPaths(configuration.actions),
},
});
}
return this;
}
}
export function pipe(...operators) {
const instance = (err, context, next, final = next) => {
if (err)
next(err, context);
else {
let operatorIndex = 0;
const run = (operatorErr, operatorContext) => {
const operator = operators[operatorIndex++];
try {
;
(operator || next)(operatorErr, operatorContext, run, final);
}
catch (operatorError) {
;
(operator || next)(operatorError, operatorContext, run, final);
}
};
run(null, context);
}
};
instance[IS_OPERATOR] = true;
return instance;
}
/*
OPERATORS
*/
export function forEach(forEachItemOperator) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
let array = context.value;
let evaluatingCount = array.length;
let lastContext;
let hasErrored = false;
const evaluate = (err) => {
if (hasErrored) {
return;
}
if (err) {
hasErrored = true;
return next(err);
}
evaluatingCount--;
if (!evaluatingCount) {
operatorStopped(context, context.value);
next(null, createContext(lastContext, context.value, lastContext.execution.path &&
lastContext.execution.path.slice(0, lastContext.execution.path.length - 1)));
}
};
operatorStarted('forEach', '', context);
if (array.length) {
array.forEach((value, index) => {
lastContext = createContext(lastContext || context, value, context.execution.path &&
context.execution.path.concat(String(index)));
const nextWithPath = createNextPath(evaluate);
// @ts-ignore
forEachItemOperator(null, lastContext, nextWithPath);
});
}
else {
operatorStopped(context, context.value);
next(null, createContext(context, context.value));
}
}
};
instance[IS_OPERATOR] = true;
return instance;
}
export function parallel(...operators) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
let evaluatingCount = operators.length;
let lastContext;
let hasErrored = false;
const evaluate = (err) => {
if (hasErrored) {
return;
}
if (err) {
hasErrored = true;
return next(err, lastContext);
}
evaluatingCount--;
if (!evaluatingCount) {
operatorStopped(context, context.value);
next(null, createContext(lastContext, context.value, lastContext.execution.path &&
lastContext.execution.path.slice(0, lastContext.execution.path.length - 1)));
}
};
operatorStarted('parallel', '', context);
operators.forEach((operator, index) => {
lastContext = createContext(lastContext || context, context.value, context.execution.path && context.execution.path.concat(String(index)));
const nextWithPath = createNextPath(evaluate);
// @ts-ignore
operator(null, lastContext, nextWithPath);
});
}
};
instance[IS_OPERATOR] = true;
return instance;
}
export function map(operation) {
return createOperator('map', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else
next(null, operation(context, value));
});
}
export function noop() {
return createOperator('noop', '', (err, context, value, next) => {
if (err)
next(err, value);
else
next(null, value);
});
}
export function filter(operation) {
return createOperator('filter', getFunctionName(operation), (err, context, value, next, final) => {
if (err)
next(err, value);
else if (operation(context, value))
next(null, value);
else
final(null, value);
});
}
let hasShownActionDeprecation = false;
export function action(operation) {
if (!hasShownActionDeprecation) {
console.warn(`DEPRECATION - The action operator is deprecated in favor of "mutate". The reason is to avoid confusion between actions and operators. Check out action "${getFunctionName(operation)}"`);
hasShownActionDeprecation = true;
}
return createMutationOperator('action', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
export function mutate(operation) {
return createMutationOperator('mutate', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
export function run(operation) {
return createOperator('run', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
export function catchError(operation) {
return createMutationOperator('catchError', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(null, operation(context, err));
else
next(null, value, {
isSkipped: true,
});
});
}
export function tryCatch(paths) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
const evaluateCatch = (err, catchContext) => {
operatorStopped(context, context.value);
next(err, createContext(catchContext, context.value));
};
const evaluateTry = (err, tryContext) => {
if (err) {
const newContext = createContext(tryContext, err, context.execution.path && context.execution.path.concat('catch'));
const nextWithPath = createNextPath(evaluateCatch);
// @ts-ignore
paths.catch(null, newContext, nextWithPath);
}
else {
operatorStopped(context, context.value);
next(null, createContext(tryContext, context.value));
}
};
operatorStarted('tryCatch', '', context);
const newContext = createContext(context, context.value, context.execution.path && context.execution.path.concat('try'));
const nextWithPath = createNextPath(evaluateTry);
// @ts-ignore
paths.try(null, newContext, nextWithPath);
}
};
instance[IS_OPERATOR] = true;
return instance;
}
export function fork(operation, paths) {
return createOperator('fork', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const path = operation(context, value);
next(null, value, {
path: {
name: String(path),
operator: paths[path],
},
});
}
});
}
export function when(operation, paths) {
return createOperator('when', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else if (operation(context, value))
next(null, value, {
path: {
name: 'true',
operator: paths.true,
},
});
else
next(null, value, {
path: {
name: 'false',
operator: paths.false,
},
});
});
}
export function wait(ms) {
return createOperator('wait', String(ms), (err, context, value, next) => {
if (err)
next(err, value);
else
setTimeout(() => next(null, value), ms);
});
}
export function debounce(ms) {
let timeout;
let previousFinal;
return createOperator('debounce', String(ms), (err, context, value, next, final) => {
if (err)
next(err, value);
else {
if (timeout) {
clearTimeout(timeout);
previousFinal(null, value);
}
previousFinal = final;
timeout = setTimeout(() => {
timeout = null;
next(null, value);
}, ms);
}
});
}
export function throttle(ms) {
let timeout;
let previousFinal;
let currentNext;
return createOperator('throttle', String(ms), (err, context, value, next, final) => {
if (err)
next(err, value);
else {
if (timeout) {
previousFinal(null, value);
currentNext = next;
}
else {
timeout = setTimeout(() => {
timeout = null;
currentNext(null, value);
}, ms);
}
previousFinal = final;
currentNext = next;
}
});
}
export function waitUntil(operation) {
return createOperator('waitUntil', operation.name, (err, context, value, next) => {
if (err)
next(err, value);
else {
const tree = context.execution.getTrackStateTree();
const test = () => {
if (operation(tree.state)) {
tree.dispose();
next(null, value);
}
};
tree.trackScope(test, test);
}
});
}
//# sourceMappingURL=index.js.map
import { __awaiter } from "tslib";
import { EventType, Overmind, SERIALIZE, rehydrate, } from './';
import { EventType, Overmind, SERIALIZE, rehydrate } from './';
import { namespaced } from './config';

@@ -50,2 +50,19 @@ function toJSON(obj) {

};
const changeOptionalFoo = (context, newFoo) => {
if (newFoo !== undefined) {
context.state.foo = newFoo;
}
else {
context.state.foo = 'default-foo';
}
};
const asyncChangeOptionalFoo = (context, newFoo) => __awaiter(this, void 0, void 0, function* () {
yield Promise.resolve();
if (newFoo !== undefined) {
context.state.foo = newFoo;
}
else {
context.state.foo = 'async-default-foo';
}
});
const changeFormValue = (_, payload) => {

@@ -68,2 +85,4 @@ const { form, key, value } = payload;

rehydrateAction,
changeOptionalFoo,
asyncChangeOptionalFoo,
};

@@ -99,6 +118,2 @@ const effects = {

const app = new Overmind({
onInitialize(context, val) {
expect(context.state.foo).toBe('bar');
value = val;
},
state: {

@@ -108,2 +123,6 @@ foo: 'bar',

actions: {
onInitializeOvermind(context, val) {
expect(context.state.foo).toBe('bar');
value = val;
},
doThis() { },

@@ -148,3 +167,3 @@ },

});
test('should track action start and end', () => {
test('should track action start and end', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(2);

@@ -156,2 +175,3 @@ const app = new Overmind({

});
yield app.initialized;
app.eventHub.once(EventType.ACTION_START, (data) => {

@@ -163,3 +183,3 @@ expect(toJSON(data)).toEqual({

namespacePath: [],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -170,7 +190,7 @@ path: [],

});
app.eventHub.once(EventType.ACTION_END, (data) => {
app.eventHub.on(EventType.ACTION_END, (data) => {
expect(toJSON(data)).toEqual({
actionId: 'doThis',
isRunning: false,
executionId: 0,
executionId: 1,
actionName: 'doThis',

@@ -184,4 +204,4 @@ namespacePath: [],

app.actions.doThis();
});
test('should track operator start and end', () => {
}));
test('should track operator start and end', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(2);

@@ -193,2 +213,3 @@ const app = new Overmind({

});
yield app.initialized;
app.eventHub.once(EventType.OPERATOR_START, (data) => {

@@ -200,3 +221,3 @@ expect(toJSON(data)).toEqual({

path: [],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -214,3 +235,3 @@ namespacePath: [],

isAsync: false,
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -222,6 +243,7 @@ namespacePath: [],

app.actions.doThis();
});
test('should track mutations', () => {
}));
test('should track mutations', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.once(EventType.MUTATIONS, (data) => {

@@ -241,3 +263,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -250,6 +272,7 @@ namespacePath: [],

app.actions.changeFoo();
});
test('should track async mutations', () => {
}));
test('should track async mutations', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.on(EventType.MUTATIONS, (data) => {

@@ -269,3 +292,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -277,7 +300,8 @@ namespacePath: [],

});
app.actions.waitAndChangeFoo();
});
test('should track async mutations with async await', () => {
yield app.actions.waitAndChangeFoo();
}));
test('should track async mutations with async await', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.on(EventType.MUTATIONS, (data) => {

@@ -297,3 +321,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -305,4 +329,4 @@ path: [],

});
app.actions.asyncChangeFoo();
});
yield app.actions.asyncChangeFoo();
}));
test('should instantiate app with modules', () => {

@@ -342,9 +366,13 @@ const foo = {

foo: {
onInitialize: () => {
result.push('foo');
actions: {
onInitializeOvermind: () => {
result.push('foo');
},
},
},
bar: {
onInitialize: () => {
result.push('bar');
actions: {
onInitializeOvermind: () => {
result.push('bar');
},
},

@@ -403,3 +431,16 @@ },

});
test('should allow actions with optional parameter', () => __awaiter(void 0, void 0, void 0, function* () {
const app = createDefaultOvermind();
app.actions.changeOptionalFoo();
expect(app.state.foo).toBe('default-foo');
yield app.actions.asyncChangeOptionalFoo();
expect(app.state.foo).toBe('async-default-foo');
const newFoo = 'new-foo';
app.actions.changeOptionalFoo(newFoo);
expect(app.state.foo).toBe(newFoo);
const newAsyncFoo = 'new-async-foo';
yield app.actions.asyncChangeOptionalFoo(newAsyncFoo);
expect(app.state.foo).toBe(newAsyncFoo);
}));
});
//# sourceMappingURL=index.test.js.map
import { IFlushCallback, IMutation, IMutationTree, ITrackStateTree } from 'proxy-state-tree';
import { IAction, IOperator, IContext } from './types';
import { IAction, IOperator } from './types';
export declare type SubType<Base, Condition> = Pick<Base, {

@@ -134,15 +134,27 @@ [Key in keyof Base]: Base[Key] extends Condition | undefined ? Key : never;

declare type NestedActions = {
[key: string]: IAction<any, any, any> | IOperator<any, any, any> | NestedActions;
} | undefined;
declare type TActionValue<T> = T extends (a1: any, a2: infer TValue) => any ? TValue : never;
export declare type ResolveActions<Actions extends NestedActions> = Actions extends undefined ? {} : {
[T in keyof Actions]: Actions[T] extends IOperator<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<void> : (value: TActionValue<Actions[T]>) => Promise<void> : Actions[T] extends IAction<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => ReturnType<Actions[T]> : (value: TActionValue<Actions[T]>) => ReturnType<Actions[T]> : Actions[T] extends NestedActions ? ResolveActions<Actions[T]> : unknown;
[key: string]: Function | NestedActions;
};
declare type NestedMockActions = {
[key: string]: IAction<any, any, any> | IOperator<any, any, any> | NestedMockActions;
} | undefined;
declare type MockResult = IMutation[];
export declare type ResolveMockActions<Actions extends NestedMockActions> = Actions extends undefined ? {} : {
[T in keyof Actions]: Actions[T] extends IOperator<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<MockResult> : (value: TActionValue<Actions[T]>) => Promise<MockResult> : Actions[T] extends IAction<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<MockResult> : (value: TActionValue<Actions[T]>) => Promise<MockResult> : Actions[T] extends NestedMockActions ? ResolveMockActions<Actions[T]> : unknown;
};
export declare type ResolveAction<T> = T extends IOperator<void, infer R> ? () => Promise<R> : T extends IOperator<infer P | undefined, infer R> ? (payload?: P) => Promise<R> : T extends IOperator<infer P, infer R> ? (payload: P) => Promise<R> : T extends IAction<void, infer R> ? () => R : T extends IAction<infer P | undefined, infer R> ? (payload?: P) => R : T extends IAction<infer P, infer R> ? (payload: P) => R : T extends NestedActions ? {
[K in keyof T]: ResolveAction<T[K]>;
} : never;
export interface ContextFunction<P extends any, R extends any> {
(context: {
state: any;
actions: any;
effects: any;
reaction: any;
addMutationListener: any;
addFlushListener: any;
}, payload: P): R;
}
export interface OperatorContextFunction<P extends any, R extends any> {
(context: {
state: any;
actions: any;
effects: any;
reaction: any;
addMutationListener: any;
addFlushListener: any;
}, payload: P extends Promise<infer PP> ? PP : P): R;
}
export {};

@@ -39,7 +39,10 @@ import { __awaiter } from "tslib";

};
const onInitialize = ({ state }) => {
const onInitializeOvermind = ({ state }) => {
state.foo += '!';
};
const actions = {
onInitializeOvermind,
};
const config = {
onInitialize,
actions,
state,

@@ -46,0 +49,0 @@ };

@@ -1,3 +0,4 @@

import { Execution } from './internalTypes';
import { Execution, OperatorContextFunction } from './internalTypes';
import { IConfiguration, IContext } from './types';
export declare function action<T extends OperatorContextFunction<any, any>>(operation: T): T;
export declare function operatorStarted(type: any, arg: any, context: any): void;

@@ -4,0 +5,0 @@ export declare function operatorStopped(context: any, value: any, details?: {

import { EventType } from './internalTypes';
import { IS_OPERATOR, MODE_TEST, ORIGINAL_ACTIONS, createActionsProxy, } from './utils';
import { IS_OPERATOR, MODE_TEST, ORIGINAL_ACTIONS, createActionsProxy, getFunctionName, isPromise, } from './utils';
export function action(operation) {
return createMutationOperator('action', getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (isPromise(result)) {
next(null, result.then((resolvedValue) => resolvedValue));
}
else {
next(null, result);
}
}
});
}
export function operatorStarted(type, arg, context) {

@@ -86,3 +101,5 @@ if (process.env.NODE_ENV === 'production') {

execution: context.execution,
revertable: context.revertable,
addFlushListener: context.addFlushListener,
addMutationListener: context.addMutationListener,
reaction: context.reaction,
}, context.value, (err, value, options = {}) => {

@@ -94,3 +111,6 @@ function run(err, value) {

const nextWithPath = createNextPath(next);
options.path.operator(err, newContext, (...args) => {
const operatorToRun = options.path.operator[IS_OPERATOR]
? options.path.operator
: action(options.path.operator);
operatorToRun(err, newContext, (...args) => {
operatorStopped(context, args[1].value);

@@ -155,3 +175,5 @@ nextWithPath(...args);

execution: context.execution,
revertable: context.revertable,
addFlushListener: context.addFlushListener,
addMutationListener: context.addMutationListener,
reaction: context.reaction,
}, process.env.NODE_ENV === 'production'

@@ -158,0 +180,0 @@ ? context.value

import { createOperator, createMutationOperator } from './operator';
import { Overmind, pipe, map, mutate } from './';
import { Overmind, pipe, } from './';
describe('OPERATOR', () => {

@@ -14,13 +14,14 @@ test('should be able to create an operator', () => {

}
const test = pipe(map(({ state }) => state.foo), toUpperCase(), mutate(({ state }, val) => {
const test = pipe(({ state }) => state.foo, toUpperCase(), ({ state }, val) => {
state.foo = val;
}));
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -43,7 +44,7 @@ const overmind = new Overmind(config);

}
const test = pipe(mutate(() => {
const test = pipe(() => {
throw new Error('wut');
}), mutate(({ state }, val) => {
}, () => {
operatorsRun++;
}), catchError((err) => {
}, catchError((err) => {
expect(err.message).toBe('wut');

@@ -54,7 +55,8 @@ }));

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -82,8 +84,8 @@ const overmind = new Overmind(config);

const test = whenBananaOrApple({
banana: mutate(({ state }) => {
banana: ({ state }) => {
state.foo = 'banana';
}),
apple: mutate(({ state }) => {
},
apple: ({ state }) => {
state.foo = 'apple';
}),
},
});

@@ -93,7 +95,8 @@ const state = {

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -123,7 +126,8 @@ const overmind = new Overmind(config);

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -161,8 +165,9 @@ const overmind = new Overmind(config);

};
const actions = {
test,
mutateFoo,
};
const config = {
state,
actions: {
test,
mutateFoo,
},
actions,
};

@@ -201,8 +206,9 @@ const overmind = new Overmind(config);

};
const actions = {
test,
mutateBar,
};
const config = {
state,
actions: {
test,
mutateBar,
},
actions,
};

@@ -209,0 +215,0 @@ const overmind = new Overmind(config);

@@ -1,84 +0,88 @@

import { Overmind, pipe, map, forEach, filter, fork, when, wait, debounce, mutate, parallel, catchError, tryCatch, throttle, waitUntil, } from './';
import { __awaiter } from "tslib";
import { Overmind, pipe, branch, filter, fork, when, wait, debounce, parallel, catchError, tryCatch, throttle, waitUntil, } from './';
describe('OPERATORS', () => {
test('map', () => {
test('branch - passes input as output', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const test = pipe(map((_, value) => value.toUpperCase()), mutate(({ state }, value) => (state.foo = value)));
const state = {
foo: 'bar',
};
const actions = {
test: pipe(branch((_, value) => value.toUpperCase()), ({ state }, value) => {
state.foo = value;
}),
};
const config = {
state,
actions: {
test,
},
actions,
};
const overmind = new Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
});
});
test('map (async)', () => {
yield overmind.actions.test('foo');
expect(overmind.state.foo).toBe('foo');
}));
test('action - return value', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const test = pipe(map((_, value) => Promise.resolve(value.toUpperCase())), mutate(({ state }, value) => (state.foo = value)));
const state = {
foo: 'bar',
};
const actions = {
test: pipe((_, value) => value.toUpperCase(), ({ state }, value) => {
state.foo = value;
}),
};
const config = {
state,
actions: {
test,
},
actions,
};
const overmind = new Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
yield overmind.actions.test('foo');
expect(overmind.state.foo).toBe('FOO');
}));
test('action - return value async', () => {
expect.assertions(1);
const test = pipe((_, value) => Promise.resolve(value.toUpperCase()), ({ state }, value) => {
state.foo = value;
});
});
test('forEach', () => {
expect.assertions(1);
let runCount = 0;
const operator = (_, val, next) => {
runCount++;
next(null, val);
const state = {
foo: 'bar',
};
const test = pipe(forEach(operator));
const actions = { test };
const config = {
actions: {
test,
},
state,
actions,
};
const overmind = new Overmind(config);
return overmind.actions.test(['foo']).then(() => {
expect(runCount).toEqual(1);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
});
});
test('parallel', () => {
test('parallel', () => __awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
let runCount = 0;
const operator = (_, value, next) => {
runCount++;
next(null, value);
const operatorA = () => {
return Promise.resolve('A');
};
const test = pipe(parallel(operator, operator));
const operatorB = () => {
return Promise.resolve('B');
};
const actions = {
test: parallel(operatorA, operatorB),
};
const config = {
actions: {
test,
},
actions,
};
const overmind = new Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(runCount).toEqual(2);
});
});
const result = yield overmind.actions.test();
expect(result).toEqual(['A', 'B']);
}));
test('filter - truthy', () => {
expect.assertions(1);
const test = pipe(filter((_, value) => value === 'foo'), map((_, value) => value.toUpperCase()), mutate(({ state }, value) => (state.foo = value)));
const test = pipe(filter((_, value) => value === 'foo'), ({ state }, value) => (state.foo = value.toUpperCase()));
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -91,11 +95,12 @@ const overmind = new Overmind(config);

test('filter - falsy', () => {
const test = pipe(filter((_, value) => value === 'bar'), map((_, value) => value.toUpperCase()), mutate(({ state }, value) => (state.foo = value)));
const test = pipe(filter((_, value) => value === 'bar'), ({ state }, value) => (state.foo = value.toUpperCase()));
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -109,21 +114,24 @@ const overmind = new Overmind(config);

expect.assertions(1);
let Key;
(function (Key) {
Key["Foo"] = "foo";
})(Key || (Key = {}));
const test = pipe(fork(() => Key.Foo, {
[Key.Foo]: pipe(map((_, value) => {
return value.toUpperCase();
}), mutate(({ state }, value) => (state.foo = value))),
}));
const config = {
state: {
foo: 'bar',
const test = pipe(() => ({ type: 'foo' }), fork('type', {
foo: () => {
return 'FOO';
},
actions: {
test,
bar: () => {
return 'BAR';
},
}), ({ state }, value) => {
state.foo = value;
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions,
};
const overmind = new Overmind(config);
return overmind.actions.test('foo').then(() => {
return overmind.actions.test().then(() => {
expect(overmind.state.foo).toBe('FOO');

@@ -134,6 +142,8 @@ });

expect.assertions(1);
const test = pipe(when(() => true, {
true: pipe(map((_, value) => value.toUpperCase()), mutate(({ state }, value) => (state.foo = value))),
false: pipe(map((_, value) => Number(value)), mutate(({ state }, value) => (state.number = value))),
}));
const test = when(() => true, {
true: ({ state }, value) => {
state.foo = value.toUpperCase();
},
false: ({ state }, value) => (state.number = Number(value)),
});
const state = {

@@ -143,7 +153,8 @@ foo: 'bar',

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -159,6 +170,5 @@ const overmind = new Overmind(config);

const test = wait(500);
const actions = { test };
const config = {
actions: {
test,
},
actions,
};

@@ -172,11 +182,12 @@ const overmind = new Overmind(config);

expect.assertions(1);
const test = pipe(debounce(100), mutate(({ state }) => state.runCount++));
const test = pipe(debounce(100), ({ state }) => state.runCount++);
const state = {
runCount: 0,
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -190,11 +201,12 @@ const overmind = new Overmind(config);

expect.assertions(1);
const test = pipe(throttle(0), mutate(({ state }) => state.runCount++));
const test = pipe(throttle(0), ({ state }) => state.runCount++);
const state = {
runCount: 0,
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -208,12 +220,13 @@ const overmind = new Overmind(config);

expect.assertions(3);
const test = pipe(mutate(() => {
const test = pipe((() => {
throw new Error('wut?!?');
}), mutate(({ state }) => {
}), ({ state }, payload) => {
state.runCount++;
}), catchError(({ state }, error) => {
return payload;
}, catchError(({ state }, error) => {
state.error = error.message;
return 'hm';
}), mutate(({ state }, value) => {
}), ({ state }, value) => {
state.foo = value;
}));
});
const state = {

@@ -224,7 +237,8 @@ runCount: 0,

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -241,6 +255,6 @@ const overmind = new Overmind(config);

const test = tryCatch({
try: mutate(({ state }, value) => {
try: ({ state }, value) => {
state.foo = value;
}),
catch: mutate(() => { }),
},
catch: () => { },
});

@@ -250,7 +264,8 @@ const state = {

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -264,18 +279,19 @@ const overmind = new Overmind(config);

expect.assertions(1);
const test = pipe(tryCatch({
try: mutate(() => {
const test = tryCatch({
try: (() => {
throw new Error('ehm');
}),
catch: mutate(({ state }, value) => {
catch: ({ state }, value) => {
state.foo = value.message;
}),
}));
},
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -289,4 +305,4 @@ const overmind = new Overmind(config);

expect.assertions(1);
const increaseCount = pipe(mutate(({ state }) => state.runCount++));
const test = pipe(waitUntil((state) => state.runCount === 1), mutate(({ state }) => (state.hasRun = true)));
const increaseCount = pipe(({ state }) => state.runCount++);
const test = pipe(waitUntil((state) => state.runCount === 1), ({ state }) => (state.hasRun = true));
const state = {

@@ -296,8 +312,9 @@ runCount: 0,

};
const actions = {
increaseCount,
test,
};
const config = {
state,
actions: {
increaseCount,
test,
},
actions,
};

@@ -304,0 +321,0 @@ const overmind = new Overmind(config);

@@ -17,2 +17,3 @@ export const doNotProxy = Symbol('doNotProxy');

const method = name.pop();
// eslint-disable-next-line
return cb({

@@ -38,5 +39,5 @@ func: target.bind(thisArg ? thisArg[ORIGIN_TARGET] : undefined),

return proxifyEffects(target[prop], cb, path ? path + '.' + prop.toString() : prop.toString());
}
},
});
}
//# sourceMappingURL=proxyfyEffects.js.map

@@ -12,7 +12,8 @@ import { Overmind } from './';

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -38,7 +39,8 @@ const app = new Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -55,3 +57,2 @@ const app = new Overmind(config);

expect.assertions(1);
let runCount = 0;
const state = {

@@ -65,7 +66,8 @@ foo: {

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -75,3 +77,2 @@ const app = new Overmind(config);

app.reaction(({ foo }) => foo.bar, (bar) => {
runCount++;
expect(bar).toBe('baz2');

@@ -78,0 +79,0 @@ }, { nested: true });

@@ -9,5 +9,8 @@ export function rehydrateState(target, source, classes = {}) {

if (typeof classInstance === 'function' && Array.isArray(target[key])) {
target[key] = source[key].map(value => classInstance(value));
target[key] = source[key].map((value) => classInstance(value));
}
else if (typeof classInstance === 'function' && typeof target[key] === 'object' && target[key] !== null && target[key].constructor.name === 'Object') {
else if (typeof classInstance === 'function' &&
typeof target[key] === 'object' &&
target[key] !== null &&
target[key].constructor.name === 'Object') {
target[key] = Object.keys(source[key]).reduce((aggr, subKey) => {

@@ -21,3 +24,5 @@ aggr[subKey] = classInstance(source[key][subKey]);

}
else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
else if (typeof value === 'object' &&
!Array.isArray(value) &&
value !== null) {
if (!target[key])

@@ -42,3 +47,4 @@ target[key] = {};

if (mutation.method === 'set') {
if (typeof classInstance === 'function' && Array.isArray(mutation.args[0])) {
if (typeof classInstance === 'function' &&
Array.isArray(mutation.args[0])) {
target[key] = mutation.args[0].map((arg) => classInstance(arg));

@@ -57,5 +63,9 @@ }

else {
target[key][mutation.method].apply(target[key], typeof classInstance === 'function' ? mutation.args.map((arg) => {
return typeof arg === 'object' && arg !== null ? classInstance(arg) : arg;
}) : mutation.args);
target[key][mutation.method].apply(target[key], typeof classInstance === 'function'
? mutation.args.map((arg) => {
return typeof arg === 'object' && arg !== null
? classInstance(arg)
: arg;
})
: mutation.args);
}

@@ -62,0 +72,0 @@ });

@@ -6,9 +6,9 @@ import { SERIALIZE, rehydrate } from './';

const state = {
foo: 'bar'
foo: 'bar',
};
rehydrate(state, {
foo: 'bar2'
foo: 'bar2',
});
expect(state).toEqual({
foo: 'bar2'
foo: 'bar2',
});

@@ -19,5 +19,6 @@ });

const state = {
foo: 'bar'
foo: 'bar',
};
rehydrate(state, [{
rehydrate(state, [
{
method: 'set',

@@ -27,6 +28,7 @@ args: ['bar2'],

path: 'foo',
revert: () => { }
}]);
revert: () => { },
},
]);
expect(state).toEqual({
foo: 'bar2'
foo: 'bar2',
});

@@ -43,3 +45,3 @@ });

[SERIALIZE]: true,
name: this.name
name: this.name,
};

@@ -57,7 +59,7 @@ }

user: {
name: 'Bob2'
name: 'Bob2',
},
user2: {
name: 'Bob2'
}
name: 'Bob2',
},
}, {

@@ -69,7 +71,7 @@ user: User.fromJSON,

user: {
name: 'Bob2'
name: 'Bob2',
},
user2: {
name: 'Bob2'
}
name: 'Bob2',
},
});

@@ -91,7 +93,10 @@ });

rehydrate(state, {
users: [{
name: 'Bob2'
}, {
name: 'Bob3'
}]
users: [
{
name: 'Bob2',
},
{
name: 'Bob3',
},
],
}, {

@@ -118,9 +123,9 @@ users: User.fromJSON,

users: {
'id1': {
name: 'Bob2'
id1: {
name: 'Bob2',
},
'id2': {
name: 'Bob3'
}
}
id2: {
name: 'Bob3',
},
},
}, {

@@ -127,0 +132,0 @@ users: User.fromJSON,

@@ -1,2 +0,2 @@

import { Overmind, createOvermindSSR, json, rehydrate, } from './';
import { Overmind, createOvermindSSR, json, rehydrate } from './';
describe('Mock', () => {

@@ -35,7 +35,9 @@ test('should allow changing the state', () => {

};
const onInitialize = ({ state }, overmind) => {
rehydrate(state, mutations);
const actions = {
onInitializeOvermind: ({ state }) => {
rehydrate(state, mutations);
},
};
const config = {
onInitialize,
actions,
state,

@@ -42,0 +44,0 @@ };

@@ -12,8 +12,14 @@ import { IState } from '.';

};
export declare type StatemachineTransitions<States extends TState, Events extends TEvents, BaseState extends TBaseState> = {
[Type in Events['type']]: [BaseState] extends [never] ? ((state: States, payload: Events extends {
type: Type;
} ? Events['data'] : never) => States | void) : ((state: States & BaseState, payload: Events extends {
type: Type;
} ? Events['data'] : never) => States | void);
export declare type StatemachineTransitions<States extends TState, Events extends TEvents, BaseState extends TBaseState> = ([BaseState] extends [never] ? (event: Events, state: States) => States | void : (event: Events, state: States & BaseState) => States | void) | {
[State in States['current']]: {
[Type in Events['type']]?: [BaseState] extends [never] ? ((event: Events extends {
type: Type;
} ? Events['data'] : never, state: States extends {
current: State;
} ? States : never) => States | void) : ((event: Events extends {
type: Type;
} ? Events['data'] : never, state: States extends {
current: State;
} ? States & BaseState : never) => States | void);
};
};

@@ -28,2 +34,3 @@ export interface MachineMethods<States extends TState, Events extends TEvents, BaseState extends TBaseState> {

} ? [T, Events['data']] : [T]): Statemachine<States, Events, BaseState>;
onTransition(listener: (state: States) => void): void;
}

@@ -36,2 +43,3 @@ export declare type Statemachine<States extends TState, Events extends TEvents, BaseState extends TBaseState = never> = [BaseState] extends [never] ? States & MachineMethods<States, Events, BaseState> : States & BaseState & MachineMethods<States, Events, BaseState>;

declare const BASE_STATE: unique symbol;
declare const TRANSITION_LISTENERS: unique symbol;
export declare function deepCopy(obj: any): any;

@@ -44,2 +52,3 @@ export declare class StateMachine<State extends TState, Events extends TEvents, BaseState extends TBaseState> {

private [BASE_STATE];
private [TRANSITION_LISTENERS];
private [IS_DISPOSED];

@@ -51,2 +60,3 @@ private clone;

matches(state: any): this | undefined;
onTransition(listener: (state: State) => void): void;
}

@@ -53,0 +63,0 @@ export declare type StatemachineFactory<States extends TState, Events extends TEvents, BaseState extends TBaseState> = [BaseState] extends [never] ? {

@@ -1,2 +0,2 @@

var _a;
var _a, _b;
import isPlainObject from 'is-plain-obj';

@@ -10,2 +10,3 @@ import { PATH, PROXY_TREE, VALUE } from 'proxy-state-tree';

const BASE_STATE = Symbol('BASE_STATE');
const TRANSITION_LISTENERS = Symbol('TRANSITION_LISTENERS');
// We have to export here to avoid a circular dependency issue with "utils"

@@ -40,3 +41,4 @@ export function deepCopy(obj) {

constructor(transitions, state, baseState) {
this[_a] = false;
this[_a] = [];
this[_b] = false;
this[STATE] = state;

@@ -54,2 +56,3 @@ this[BASE_STATE] = baseState;

dispose() {
this[VALUE][TRANSITION_LISTENERS] = [];
Object.keys(this[VALUE]).forEach((key) => {

@@ -70,5 +73,12 @@ if (this[VALUE][key] instanceof StateMachine) {

const tree = this[PROXY_TREE].master.mutationTree || this[PROXY_TREE];
const transition = this[VALUE][TRANSITIONS][type];
tree.enableMutations();
const result = transition(this, data);
let result;
if (typeof this[VALUE][TRANSITIONS] === 'function') {
const transition = this[VALUE][TRANSITIONS];
result = transition({ type, data }, this);
}
else {
const transition = this[VALUE][TRANSITIONS][this[VALUE].current][type];
result = transition(data, this);
}
if (result) {

@@ -82,2 +92,3 @@ this[VALUE][CURRENT_KEYS].forEach((key) => {

Object.assign(this, result);
this[VALUE][TRANSITION_LISTENERS].forEach((listener) => listener(this));
}

@@ -92,4 +103,7 @@ tree.blockMutations();

}
onTransition(listener) {
this[VALUE][TRANSITION_LISTENERS].push(listener);
}
}
_a = IS_DISPOSED;
_a = TRANSITION_LISTENERS, _b = IS_DISPOSED;
export function statemachine(transitions) {

@@ -96,0 +110,0 @@ return {

@@ -6,5 +6,6 @@ import { createOvermind, createOvermindMock } from './';

const state = statemachine({
TEST: () => { }
FOO: {},
BAR: {},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -19,7 +20,8 @@ const config = {

const state = statemachine({
TEST: () => { }
FOO: {},
BAR: {},
}).create({
current: 'FOO',
}, {
foo: 'bar'
foo: 'bar',
});

@@ -33,7 +35,7 @@ const config = {

});
test('should transition state', () => {
const state = statemachine({
TOGGLE: (state) => ({ current: state.current === 'FOO' ? 'BAR' : 'FOO' })
test('should transition state using function', () => {
const state = statemachine((_, state) => {
return { current: state.current === 'FOO' ? 'BAR' : 'FOO' };
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -43,7 +45,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -55,8 +58,12 @@ const overmind = createOvermindMock(config);

test('should remove state when transitioning', () => {
var _a;
const state = statemachine({
TOGGLE: () => ({ current: 'BAR' })
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {
TOGGLE: () => ({ current: 'FOO', foo: 'foo' }),
},
}).create({
current: 'FOO',
foo: 'bar'
foo: 'bar',
});

@@ -66,11 +73,13 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};
const overmind = createOvermindMock(config);
const fooContext = overmind.state.matches('FOO');
expect(overmind.state.current).toBe('FOO');
expect((_a = overmind.state.matches('FOO')) === null || _a === void 0 ? void 0 : _a.foo).toBe('bar');
expect(fooContext && fooContext.foo).toBe('bar');
overmind.actions.transition();

@@ -81,12 +90,10 @@ expect(overmind.state.current).toBe('BAR');

test('should block mutations in strict mode', () => {
const state = statemachine({
TOGGLE: (state) => {
if (state.current === 'FOO') {
return { current: 'BAR' };
}
return { current: 'FOO', foo: 'bar' };
const state = statemachine((_, state) => {
if (state.current === 'FOO') {
return { current: 'BAR' };
}
return { current: 'FOO', foo: 'bar' };
}).create({
current: 'FOO',
foo: 'bar'
foo: 'bar',
});

@@ -99,9 +106,14 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};
const overmind = createOvermind(config, { devtools: false, strict: true, devEnv: 'test' });
const overmind = createOvermind(config, {
devtools: false,
strict: true,
devEnv: 'test',
});
expect(() => overmind.actions.transition()).toThrow();

@@ -111,5 +123,10 @@ });

const state = statemachine({
TOGGLE: () => { }
FOO: {
TOGGLE: () => { },
},
BAR: {
TOGGLE: () => { },
},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -119,7 +136,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -133,5 +151,8 @@ const overmind = createOvermindMock(config);

const state = statemachine({
TOGGLE: () => ({ current: 'BAR' })
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -141,7 +162,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -156,8 +178,13 @@ const overmind = createOvermind(config);

const state = statemachine({
TEST: () => { }
FOO: {
TEST: () => { },
},
BAR: {
TEST: () => { },
},
}).create({
current: 'FOO',
obj: {
foo: 'bar'
}
foo: 'bar',
},
});

@@ -169,4 +196,4 @@ const config = {

state.obj.foo = 'bar2';
}
}
},
},
};

@@ -180,3 +207,27 @@ const overmind = createOvermindMock(config);

});
test('should allow listening to state changes', () => {
expect.assertions(1);
const state = statemachine({
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {},
}).create({
current: 'FOO',
});
const transition = ({ state }) => {
state.onTransition((state) => expect(state.current).toBe('BAR'));
state.send('TOGGLE');
};
const actions = {
transition,
};
const config = {
state,
actions,
};
const overmind = createOvermind(config);
overmind.actions.transition();
});
});
//# sourceMappingURL=statemachine.test.js.map

@@ -1,4 +0,4 @@

import { Overmind } from './';
import { ResolveActions } from './internalTypes';
import { ResolveAction, ContextFunction } from './internalTypes';
import { IS_OPERATOR } from './utils';
import { IMutationCallback, IFlushCallback } from 'proxy-state-tree';
/** ===== PUBLIC API

@@ -8,3 +8,2 @@ */

export declare type IConfiguration = {
onInitialize?: any;
state?: {};

@@ -17,15 +16,23 @@ effects?: {};

};
export interface IConfig<ThisConfig extends IConfiguration> {
state: ThisConfig['state'] & {};
actions: ThisConfig['actions'] & {};
effects: ThisConfig['effects'] & {};
export declare type IContext<T extends IConfiguration> = {
state: T['state'];
actions: {
[K in keyof T['actions']]: ResolveAction<T['actions'][K]>;
};
effects: T['effects'];
reaction: IReaction<{
state: T['state'];
}>;
addMutationListener: (cb: IMutationCallback) => () => void;
addFlushListener: (cb: IFlushCallback) => () => void;
};
export interface IAction<I, O> extends ContextFunction<I, O> {
}
export declare type IContext<ThisConfig extends IConfiguration> = {
state: ThisConfig['state'];
actions: ResolveActions<ThisConfig['actions']>;
effects: ThisConfig['effects'];
revertable: (mutationsCallback: () => any) => () => void;
};
export interface IReaction<ThisConfig extends IConfiguration> {
<O>(stateCallback: (state: ThisConfig['state']) => O, updateCallback: (value: O) => void, options?: {
export interface IOperator<I, O> extends ContextFunction<I, O> {
[IS_OPERATOR]: true;
}
export interface IReaction<T extends {
state?: IState;
}> {
<O>(stateCallback: (state: T['state']) => O, updateCallback: (value: O) => void, options?: {
nested?: boolean;

@@ -35,11 +42,1 @@ immediate?: boolean;

}
export interface IAction<ThisConfig extends IConfiguration, Value, ReturnValue = void | Promise<void>> {
<InferredReturnValue extends ReturnValue>(context: IContext<ThisConfig>, value: Value): ReturnValue extends Promise<any> ? ReturnValue : InferredReturnValue | ReturnValue;
}
export interface IOperator<ThisConfig extends IConfiguration, Input, Output = Input> {
(context: IContext<ThisConfig>, value: Input): Output;
[IS_OPERATOR]: true;
}
export interface IOnInitialize<ThisConfig extends IConfiguration> {
(context: IContext<ThisConfig>, value: Overmind<ThisConfig>): void;
}
import { IMutation } from 'proxy-state-tree';
export { deepCopy } from './statemachine';
export declare const createOnInitialize: () => ({ actions }: {
actions: any;
}, instance: any) => Promise<[unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]>;
export declare const ENVIRONMENT: string;

@@ -19,7 +22,8 @@ export declare const IS_TEST: boolean;

export declare const json: <T>(obj: T) => T;
export declare function isPromise(maybePromise: any): boolean;
export declare function isPromise(maybePromise: any): any;
export declare function processState(state: {}): {};
export declare function getFunctionName(func: Function): any;
export declare function getChangeMutations(stateA: object, stateB: object, path?: string[], mutations?: IMutation[]): IMutation[];
export declare function getActionsByName(name: string, actions?: {}, currentPath?: string[]): any;
export declare function getActionPaths(actions?: {}, currentPath?: string[]): any;
export declare function createActionsProxy(actions: any, cb: any): any;

@@ -6,2 +6,8 @@ import isPlainObject from 'is-plain-obj';

export { deepCopy } from './statemachine';
export const createOnInitialize = () => {
return ({ actions }, instance) => {
const initializers = getActionsByName('onInitializeOvermind', actions);
return Promise.all(initializers.map((initialize) => initialize(instance)));
};
};
export const ENVIRONMENT = (() => {

@@ -95,2 +101,10 @@ let env;

}
export function getActionsByName(name, actions = {}, currentPath = []) {
return Object.keys(actions).reduce((aggr, key) => {
if (typeof actions[key] === 'function' && key === name) {
return aggr.concat(actions[key]);
}
return aggr.concat(getActionsByName(name, actions[key], currentPath.concat(key)));
}, []);
}
export function getActionPaths(actions = {}, currentPath = []) {

@@ -97,0 +111,0 @@ return Object.keys(actions).reduce((aggr, key) => {

@@ -7,3 +7,5 @@ import { deepCopy, getChangeMutations } from './utils';

value: 0,
get valuePlusTwo() { return this.value + 2; }
get valuePlusTwo() {
return this.value + 2;
},
};

@@ -18,3 +20,3 @@ const copy = deepCopy(original);

const stateA = {
foo: 'bar'
foo: 'bar',
};

@@ -32,5 +34,5 @@ const stateB = {

bar: {
baz: 'mip'
}
}
baz: 'mip',
},
},
};

@@ -40,5 +42,5 @@ const stateB = {

bar: {
baz: 'mip2'
}
}
baz: 'mip2',
},
},
};

@@ -54,10 +56,10 @@ const mutations = getChangeMutations(stateA, stateB);

bar: {
baz: 'mip'
}
}
baz: 'mip',
},
},
};
const stateB = {
foo: {
bar: {}
}
bar: {},
},
};

@@ -64,0 +66,0 @@ const mutations = getChangeMutations(stateA, stateB);

@@ -55,4 +55,4 @@ "use strict";

actions: {
loadConfigB: ({ effects }) => {
return effects.lazy.loadConfig('configB');
loadConfigB: ({ actions }) => {
return actions.lazy.loadConfig('configB');
},

@@ -59,0 +59,0 @@ },

@@ -5,3 +5,2 @@ import { SubType } from '../internalTypes';

[namespace: string]: () => Promise<{
onInitialize?: any;
state?: {};

@@ -14,3 +13,2 @@ effects?: {};

export declare function lazy<T extends LazyConfiguration>(configurations: T): {
onInitialize?: any;
state: SubType<{

@@ -25,7 +23,3 @@ [P in keyof T]?: ReturnType<T[P]> extends Promise<infer U> ? U extends {

} ? U['effects'] : never : never;
}, object> & {
lazy: {
loadConfig: (config: keyof T) => Promise<void>;
};
};
}, object>;
actions: SubType<{

@@ -37,3 +31,3 @@ [P in keyof T]?: ReturnType<T[P]> extends Promise<infer U> ? U extends {

lazy: {
loadConfig: IAction<any, keyof T>;
loadConfig: IAction<keyof T, any>;
};

@@ -40,0 +34,0 @@ };

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lazy = void 0;
const tslib_1 = require("tslib");
const namespaced_1 = require("./namespaced");
const utils_1 = require("../utils");
function lazy(configurations) {
let app;
return {
onInitialize(_, value) {
app = value;
},
effects: {
lazy: {
loadConfig(config) {
return app.actions.lazy.loadConfig(config);
},
},
},
actions: {
lazy: {
loadConfig(_a, key) {
var { state, execution } = _a, rest = tslib_1.__rest(_a, ["state", "execution"]);
loadConfig({ state, execution, addNamespace }, key) {
const configToLoad = configurations[key];
const namespacePath = execution.namespacePath.slice(0, execution.namespacePath.length - 1).concat(key);
const namespacePath = execution.namespacePath
.slice(0, execution.namespacePath.length - 1)
.concat(key);
return configToLoad().then((loadedConfig) => {
const newConfig = namespaced_1.namespaced({
[key]: loadedConfig,
});
if (newConfig.state && newConfig.state[key])
state[key] = utils_1.processState(newConfig.state[key]);
if (newConfig.effects && newConfig.effects[key])
app.effects[key] = newConfig.effects[key];
if (newConfig.actions && newConfig.actions[key])
app.actions[key] = app.getActions(newConfig.actions[key], namespacePath);
if (newConfig.onInitialize)
newConfig.onInitialize(Object.assign({ state, execution: Object.assign(Object.assign({}, execution), { namespacePath }) }, rest), app);
addNamespace(loadedConfig, namespacePath, state);
});

@@ -39,0 +16,0 @@ },

@@ -32,3 +32,2 @@ "use strict";

function merge(...configurations) {
const initializers = configurations.reduce((aggr, config) => config.onInitialize ? aggr.concat(config.onInitialize) : aggr, []);
const rootConfiguration = configurations.shift();

@@ -55,3 +54,2 @@ const reducedConfigurations = configurations.reduce((aggr, config) => {

return {
onInitialize: aggr.onInitialize,
state: copy(aggr.state, config.state || {}),

@@ -61,5 +59,3 @@ effects: Object.assign(Object.assign({}, aggr.effects), config.effects),

};
}, Object.assign(Object.assign({ state: {}, actions: {}, effects: {} }, rootConfiguration), { onInitialize: initializers.length
? (context, value) => Promise.all(initializers.map((cb) => cb(context, value)))
: undefined }));
}, Object.assign({ state: {}, actions: {}, effects: {} }, rootConfiguration));
return reducedConfigurations;

@@ -66,0 +62,0 @@ }

import { SubType } from '../internalTypes';
interface NamespacedConfiguration {
[namespace: string]: {
onInitialize?: any;
state?: {};

@@ -12,3 +11,2 @@ effects?: {};

export declare function namespaced<T extends NamespacedConfiguration>(namespaces: T): {
onInitialize?: any;
state: SubType<{

@@ -15,0 +13,0 @@ [P in keyof T]: T[P]['state'];

@@ -5,3 +5,3 @@ "use strict";

function parseNamespacedConfig(result, name, config) {
const { actions, effects, onInitialize, state } = config;
const { actions, effects, state } = config;
if (actions) {

@@ -16,5 +16,2 @@ result.actions[name] = actions;

}
if (onInitialize) {
result.initializers[name] = onInitialize;
}
}

@@ -35,3 +32,2 @@ function namespaced(namespaces) {

state: result.state,
onInitialize: (context, app) => Promise.all(Object.keys(result.initializers).map((key) => result.initializers[key](Object.assign(Object.assign({}, context), { execution: Object.assign(Object.assign({}, context.execution), { namespacePath: context.execution.namespacePath.concat(key) }) }), app))),
});

@@ -38,0 +34,0 @@ }

@@ -23,3 +23,5 @@ "use strict";

runScope(tree, path) {
const parent = path.slice(0, path.length - 1).reduce((curr, key) => curr[key], tree.state);
const parent = path
.slice(0, path.length - 1)
.reduce((curr, key) => curr[key], tree.state);
return this.cb(parent, tree.state);

@@ -37,3 +39,3 @@ }

}
for (let mutationPath of paths) {
for (const mutationPath of paths) {
if (this.paths.has(mutationPath)) {

@@ -73,3 +75,3 @@ this.isDirty = true;

// is for nested derived
for (let path of this.paths) {
for (const path of this.paths) {
tree.addTrackingPath(path);

@@ -76,0 +78,0 @@ tree.trackPathListeners.forEach((cb) => cb(path));

@@ -28,15 +28,15 @@ "use strict";

foo: 'bar',
upperFoo: _1.derived((state) => state.foo.toUpperCase())
upperFoo: _1.derived((state) => state.foo.toUpperCase()),
};
const actions = {
changeFoo,
removeDerived,
};
const config = {
state,
actions: {
changeFoo,
removeDerived
},
actions,
};
const app = new _1.Overmind(config);
const trackStateTree = app.getTrackStateTree();
const onTrack = () => {
};
const onTrack = () => { };
function render() {

@@ -56,3 +56,3 @@ trackStateTree.track(onTrack);

// The dirty event is async
yield new Promise(resolve => setTimeout(resolve, 0));
yield new Promise((resolve) => setTimeout(resolve, 0));
expect(dirtyCount).toBe(1);

@@ -69,15 +69,15 @@ }));

foo: 'bar',
upperFoo: null
upperFoo: null,
};
const actions = {
changeFoo,
addDerived,
};
const config = {
state,
actions: {
changeFoo,
addDerived
},
actions,
};
const app = new _1.Overmind(config);
const trackStateTree = app.getTrackStateTree();
const onTrack = () => {
};
const onTrack = () => { };
function render() {

@@ -105,7 +105,8 @@ trackStateTree.track(onTrack);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -134,7 +135,8 @@ const app = new _1.Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -165,7 +167,8 @@ const app = new _1.Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -185,7 +188,8 @@ const app = new _1.Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -205,10 +209,11 @@ const app = new _1.Overmind(config);

foo: 'bar',
upperFoo: _1.derived((parent) => parent.foo.toUpperCase())
}
upperFoo: _1.derived((parent) => parent.foo.toUpperCase()),
},
};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -240,3 +245,3 @@ const app = new _1.Overmind(config);

const state = {
class: new SomeClass()
class: new SomeClass(),
};

@@ -243,0 +248,0 @@ const config = {

@@ -63,3 +63,7 @@ "use strict";

});
this.name = typeof location !== 'undefined' && location.search.includes('OVERMIND_DEVTOOL') ? name + ' (Overmind Devtool)' : name;
this.name =
typeof location !== 'undefined' &&
location.search.includes('OVERMIND_DEVTOOL')
? name + ' (Overmind Devtool)'
: name;
}

@@ -84,3 +88,3 @@ reconnect(host, onMessage) {

name: value.constructor.name,
value
value,
};

@@ -97,3 +101,4 @@ }

circularReferenceCache.push(value);
if (!safeClassNames.has(value.constructor.name) && !unsafeClassNames.has(value.constructor.name)) {
if (!safeClassNames.has(value.constructor.name) &&
!unsafeClassNames.has(value.constructor.name)) {
try {

@@ -111,3 +116,3 @@ JSON.stringify(value);

name: value.constructor.name,
value
value,
};

@@ -114,0 +119,0 @@ }

@@ -1,114 +0,15 @@

import { EventEmitter } from 'betsy';
import { IFlushCallback, IMutation, IMutationCallback, IMutationTree, ITrackStateTree } from 'proxy-state-tree';
import { Devtools } from './Devtools';
import { DefaultMode, Events, NestedPartial, Options, ResolveActions, SSRMode, TestMode } from './internalTypes';
import { createMutationOperator, createOperator } from './operator';
import { IAction, IConfiguration, IContext, IOnInitialize, IOperator, IReaction } from './types';
import * as internalTypes from './internalTypes';
import { Overmind } from './Overmind';
import { IConfiguration } from './types';
export * from './types';
export { createOperator, createMutationOperator, ResolveActions };
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT } from './utils';
export * from './operators';
export { Overmind } from './Overmind';
export { ResolveAction, OperatorContextFunction, ContextFunction, } from './internalTypes';
export { createOperator, createMutationOperator } from './operator';
export { MODE_DEFAULT, MODE_TEST, MODE_SSR, ENVIRONMENT, json } from './utils';
export { SERIALIZE, rehydrate } from './rehydrate';
export { Statemachine, statemachine } from './statemachine';
export * from './OvermindMock';
export * from './OvermindSSR';
export declare const derived: <S extends object, R extends object, O>(cb: (state: S, rootState: R) => O) => O;
/** This type can be overwriten by app developers if they want to avoid
* typing and then they can import `Action`, `Operation` etc. directly from
* overmind.
*/
export interface Config {
}
export interface Context extends IContext<Config> {
}
export declare type RootState = Context['state'];
export interface Action<Value = void, ReturnValue = void> extends IAction<Config, Value, ReturnValue> {
}
export interface AsyncAction<Value = void, ReturnValue = void> extends IAction<Config, Value, Promise<ReturnValue>> {
}
export interface OnInitialize extends IOnInitialize<Config> {
}
export interface Reaction extends IReaction<Config> {
}
export { json } from './utils';
export interface OvermindSSR<Config extends IConfiguration> extends Overmind<Config> {
hydrate(): IMutation[];
}
export declare function createOvermindSSR<Config extends IConfiguration>(config: Config): OvermindSSR<Config>;
export interface OvermindMock<Config extends IConfiguration> extends Overmind<Config> {
onInitialize: () => Promise<IMutation[]>;
mutations: IMutation[];
}
export declare function createOvermindMock<Config extends IConfiguration>(config: Config): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, setInitialState: (state: Config['state']) => void): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, mockedEffects: NestedPartial<Config['effects']>): OvermindMock<Config>;
export declare function createOvermindMock<Config extends IConfiguration>(config: Config, mockedEffects: NestedPartial<Config['effects']>, setInitialState: (state: Config['state']) => void): OvermindMock<Config>;
export declare function createOvermind<Config extends IConfiguration>(config: Config, options?: Options): Overmind<Config>;
export declare class Overmind<ThisConfig extends IConfiguration> implements IConfiguration {
private proxyStateTree;
private actionReferences;
private nextExecutionId;
private mode;
private reydrateMutationsForHotReloading;
private originalConfiguration;
private isStrict;
initialized: Promise<any>;
eventHub: EventEmitter<Events>;
devtools: Devtools;
actions: ResolveActions<ThisConfig['actions']>;
state: ThisConfig['state'];
effects: ThisConfig['effects'] & {};
delimiter: string;
constructor(configuration: ThisConfig, options?: Options, mode?: DefaultMode | TestMode | SSRMode);
private createProxyStateTree;
private createExecution;
private createContext;
private scopeValue;
private addExecutionMutation;
private createAction;
private trackEffects;
private initializeDevtools;
private getState;
private getActions;
private updateActions;
getTrackStateTree(): ITrackStateTree<any>;
getMutationTree(): IMutationTree<any>;
reaction: IReaction<ThisConfig>;
addMutationListener: (cb: IMutationCallback) => () => void;
addFlushListener: (cb: IFlushCallback) => () => IFlushCallback[];
reconfigure(configuration: IConfiguration): this;
}
export declare type Operator<Input = void, Output = Input> = IOperator<Config, Input, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, Output = B>(aOperator: IOperator<ThisConfig, A, B>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, Output = C>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, Output = D>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, Output = E>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, Output = F>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, Output = G>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, Output = H>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>): IOperator<ThisConfig, A, Output>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>): IOperator<ThisConfig, A, I extends never ? any : I>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I, J>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>, iOperator: IOperator<ThisConfig, I, J>): IOperator<ThisConfig, A, J extends never ? any : J>;
export declare function pipe<ThisConfig extends IConfiguration, A, B, C, D, E, F, G, H, I, J, K>(aOperator: IOperator<ThisConfig, A, B>, bOperator: IOperator<ThisConfig, B, C>, cOperator: IOperator<ThisConfig, C, D>, dOperator: IOperator<ThisConfig, D, E>, eOperator: IOperator<ThisConfig, E, F>, fOperator: IOperator<ThisConfig, F, G>, gOperator: IOperator<ThisConfig, G, H>, hOperator: IOperator<ThisConfig, H, I>, iOperator: IOperator<ThisConfig, I, J>, jOperator: IOperator<ThisConfig, J, K>): IOperator<ThisConfig, A, K extends never ? any : K>;
export declare function forEach<Input extends any[], ThisConfig extends IConfiguration = Config>(forEachItemOperator: IOperator<ThisConfig, Input extends Array<infer U> ? U : never>): IOperator<ThisConfig, Input, Input>;
export declare function parallel<Input, ThisConfig extends IConfiguration = Config>(...operators: IOperator<ThisConfig, Input>[]): IOperator<ThisConfig, Input, Input>;
export declare function map<Input, Output, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => Output): IOperator<ThisConfig, Input, Output extends Promise<infer U> ? U : Output>;
export declare function noop<Input, ThisConfig extends IConfiguration = Config>(): IOperator<ThisConfig, Input>;
export declare function filter<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => boolean): IOperator<ThisConfig, Input, Input>;
export declare function action<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function mutate<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function run<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => void): IOperator<ThisConfig, Input, Input>;
export declare function catchError<Input, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Error) => Input): IOperator<ThisConfig, Input, Input>;
export declare function tryCatch<Input, ThisConfig extends IConfiguration = Config>(paths: {
try: IOperator<ThisConfig, Input>;
catch: IOperator<ThisConfig, Error>;
}): IOperator<ThisConfig, Input, Input>;
export declare function fork<Input, Paths extends {
[key: string]: IOperator<ThisConfig, any, any>;
}, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => keyof Paths, paths: Paths & {
[N in keyof Paths]: IOperator<ThisConfig, Input, any>;
}): IOperator<ThisConfig, Input, Input>;
export declare function when<Input, OutputA, OutputB, ThisConfig extends IConfiguration = Config>(operation: (context: IContext<ThisConfig>, value: Input) => boolean, paths: {
true: IOperator<ThisConfig, Input, OutputA>;
false: IOperator<ThisConfig, Input, OutputB>;
}): IOperator<ThisConfig, Input, OutputA | OutputB>;
export declare function wait<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function debounce<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function throttle<Input, ThisConfig extends IConfiguration = Config>(ms: number): IOperator<ThisConfig, Input, Input>;
export declare function waitUntil<Input, ThisConfig extends IConfiguration = Config>(operation: (state: ThisConfig['state']) => boolean): IOperator<ThisConfig, Input, Input>;
export declare function createOvermind<Config extends IConfiguration>(config: Config, options?: internalTypes.Options): Overmind<Config>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.waitUntil = exports.throttle = exports.debounce = exports.wait = exports.when = exports.fork = exports.tryCatch = exports.catchError = exports.run = exports.mutate = exports.action = exports.filter = exports.noop = exports.map = exports.parallel = exports.forEach = exports.pipe = exports.Overmind = exports.createOvermind = exports.createOvermindMock = exports.createOvermindSSR = exports.json = exports.derived = exports.statemachine = exports.rehydrate = exports.SERIALIZE = exports.ENVIRONMENT = exports.MODE_SSR = exports.MODE_TEST = exports.MODE_DEFAULT = exports.createMutationOperator = exports.createOperator = void 0;
exports.createOvermind = exports.derived = exports.statemachine = exports.rehydrate = exports.SERIALIZE = exports.json = exports.ENVIRONMENT = exports.MODE_SSR = exports.MODE_TEST = exports.MODE_DEFAULT = exports.createMutationOperator = exports.createOperator = exports.Overmind = void 0;
const tslib_1 = require("tslib");
const betsy_1 = require("betsy");
const is_plain_obj_1 = tslib_1.__importDefault(require("is-plain-obj"));
const proxy_state_tree_1 = require("proxy-state-tree");
const derived_1 = require("./derived");
const Devtools_1 = require("./Devtools");
const internalTypes_1 = require("./internalTypes");
const operator_1 = require("./operator");
const Overmind_1 = require("./Overmind");
const utils = tslib_1.__importStar(require("./utils"));
tslib_1.__exportStar(require("./types"), exports);
tslib_1.__exportStar(require("./operators"), exports);
var Overmind_2 = require("./Overmind");
Object.defineProperty(exports, "Overmind", { enumerable: true, get: function () { return Overmind_2.Overmind; } });
var operator_1 = require("./operator");
Object.defineProperty(exports, "createOperator", { enumerable: true, get: function () { return operator_1.createOperator; } });
Object.defineProperty(exports, "createMutationOperator", { enumerable: true, get: function () { return operator_1.createMutationOperator; } });
Object.defineProperty(exports, "createOperator", { enumerable: true, get: function () { return operator_1.createOperator; } });
const proxyfyEffects_1 = require("./proxyfyEffects");
const rehydrate_1 = require("./rehydrate");
const utils_1 = require("./utils");
tslib_1.__exportStar(require("./types"), exports);
var utils_2 = require("./utils");
Object.defineProperty(exports, "MODE_DEFAULT", { enumerable: true, get: function () { return utils_2.MODE_DEFAULT; } });
Object.defineProperty(exports, "MODE_TEST", { enumerable: true, get: function () { return utils_2.MODE_TEST; } });
Object.defineProperty(exports, "MODE_SSR", { enumerable: true, get: function () { return utils_2.MODE_SSR; } });
Object.defineProperty(exports, "ENVIRONMENT", { enumerable: true, get: function () { return utils_2.ENVIRONMENT; } });
var rehydrate_2 = require("./rehydrate");
Object.defineProperty(exports, "SERIALIZE", { enumerable: true, get: function () { return rehydrate_2.SERIALIZE; } });
Object.defineProperty(exports, "rehydrate", { enumerable: true, get: function () { return rehydrate_2.rehydrate; } });
var utils_1 = require("./utils");
Object.defineProperty(exports, "MODE_DEFAULT", { enumerable: true, get: function () { return utils_1.MODE_DEFAULT; } });
Object.defineProperty(exports, "MODE_TEST", { enumerable: true, get: function () { return utils_1.MODE_TEST; } });
Object.defineProperty(exports, "MODE_SSR", { enumerable: true, get: function () { return utils_1.MODE_SSR; } });
Object.defineProperty(exports, "ENVIRONMENT", { enumerable: true, get: function () { return utils_1.ENVIRONMENT; } });
Object.defineProperty(exports, "json", { enumerable: true, get: function () { return utils_1.json; } });
var rehydrate_1 = require("./rehydrate");
Object.defineProperty(exports, "SERIALIZE", { enumerable: true, get: function () { return rehydrate_1.SERIALIZE; } });
Object.defineProperty(exports, "rehydrate", { enumerable: true, get: function () { return rehydrate_1.rehydrate; } });
var statemachine_1 = require("./statemachine");
Object.defineProperty(exports, "statemachine", { enumerable: true, get: function () { return statemachine_1.statemachine; } });
exports.derived = (cb) => {
tslib_1.__exportStar(require("./OvermindMock"), exports);
tslib_1.__exportStar(require("./OvermindSSR"), exports);
const derived = (cb) => {
cb[derived_1.IS_DERIVED_CONSTRUCTOR] = true;
return cb;
};
var utils_3 = require("./utils");
Object.defineProperty(exports, "json", { enumerable: true, get: function () { return utils_3.json; } });
function createOvermindSSR(config) {
const ssr = new Overmind(config, {
devtools: false,
}, {
mode: utils_1.MODE_SSR,
});
const mutationTree = ssr.proxyStateTree.getMutationTree();
ssr.state = mutationTree.state;
ssr.hydrate = () => {
return mutationTree.flush().mutations;
};
return ssr;
}
exports.createOvermindSSR = createOvermindSSR;
function createOvermindMock(...args) {
const setState = typeof args[1] === 'function' ? args[1] : args[2];
const mockedEffects = typeof args[1] === 'function' ? undefined : args[1];
const state = utils_1.deepCopy(args[0].state);
if (setState) {
;
setState(state);
}
const mock = new Overmind(Object.assign({}, args[0], {
state,
}), {
devtools: false,
}, {
mode: utils_1.MODE_TEST,
options: {
effectsCallback: (effect) => {
const mockedEffect = (effect.name
? effect.name.split('.')
: []).reduce((aggr, key) => (aggr ? aggr[key] : aggr), mockedEffects);
if (!mockedEffect || (mockedEffect && !mockedEffect[effect.method])) {
throw new Error(`The effect "${effect.name}" with method ${effect.method} has not been mocked`);
}
return mockedEffect[effect.method](...effect.args);
},
},
});
const action = mock.createAction('onInitialize', args[0].onInitialize);
mock.onInitialize = () => action(mock);
mock.mutations = [];
return mock;
}
exports.createOvermindMock = createOvermindMock;
exports.derived = derived;
function createOvermind(config, options) {
return new Overmind(config, options, { mode: utils_1.MODE_DEFAULT });
return new Overmind_1.Overmind(config, options, { mode: utils.MODE_DEFAULT });
}
exports.createOvermind = createOvermind;
const hotReloadingCache = {};
// We do not use IConfig<Config> directly to type the class in order to avoid
// the 'import(...)' function to be used in exported types.
class Overmind {
constructor(configuration, options = {}, mode = {
mode: utils_1.MODE_DEFAULT,
}) {
this.actionReferences = {};
this.nextExecutionId = 0;
this.reydrateMutationsForHotReloading = [];
this.isStrict = false;
this.reaction = (stateCallback, updateCallback, options = {}) => {
let disposer;
if (options.nested) {
const value = stateCallback(this.state);
if (!value || !value[proxy_state_tree_1.IS_PROXY]) {
throw new Error('You have to return an object or array from the Overmind state when using a "nested" reaction');
}
const path = value[proxy_state_tree_1.PATH];
disposer = this.addFlushListener((mutations) => {
mutations.forEach((mutation) => {
if (mutation.path.startsWith(path)) {
updateCallback(path
? path
.split(this.delimiter)
.reduce((aggr, key) => aggr[key], this.state)
: this.state);
}
});
});
}
else {
const tree = this.proxyStateTree.getTrackStateTree();
let returnValue;
const updateReaction = () => {
tree.trackScope(() => (returnValue = stateCallback(tree.state)), () => {
updateReaction();
updateCallback(returnValue);
});
};
updateReaction();
disposer = () => {
tree.dispose();
};
}
if (options.immediate) {
updateCallback(stateCallback(this.state));
}
return disposer;
};
this.addMutationListener = (cb) => {
return this.proxyStateTree.onMutation(cb);
};
this.addFlushListener = (cb) => {
return this.proxyStateTree.onFlush(cb);
};
const name = options.name || 'OvermindApp';
const devEnv = options.devEnv || 'development';
const isNode = process && process.title && process.title.includes('node');
this.delimiter = options.delimiter || '.';
this.isStrict = Boolean(options.strict);
if (utils_1.ENVIRONMENT === devEnv &&
mode.mode === utils_1.MODE_DEFAULT &&
options.hotReloading !== false &&
!isNode) {
if (hotReloadingCache[name]) {
return hotReloadingCache[name].reconfigure(configuration);
}
else {
hotReloadingCache[name] = this;
}
}
/*
Set up an eventHub to trigger information from derived, computed and reactions
*/
const eventHub = mode.mode === utils_1.MODE_SSR
? new utils_1.MockedEventEmitter()
: new betsy_1.EventEmitter();
/*
Create the proxy state tree instance with the state and a wrapper to expose
the eventHub
*/
const proxyStateTree = this.createProxyStateTree(configuration, eventHub, mode.mode === utils_1.MODE_TEST || utils_1.ENVIRONMENT === devEnv, mode.mode === utils_1.MODE_SSR);
this.originalConfiguration = configuration;
this.state = proxyStateTree.state;
this.effects = configuration.effects || {};
this.proxyStateTree = proxyStateTree;
this.eventHub = eventHub;
this.mode = mode;
/*
Expose the created actions
*/
this.actions = this.getActions(configuration.actions);
if (mode.mode === utils_1.MODE_SSR) {
return;
}
if (utils_1.ENVIRONMENT === devEnv &&
mode.mode === utils_1.MODE_DEFAULT &&
typeof window !== 'undefined') {
let warning = 'OVERMIND: You are running in DEVELOPMENT mode.';
if (options.logProxies !== true) {
const originalConsoleLog = console.log;
console.log = (...args) => originalConsoleLog.apply(console, args.map((arg) => (arg && arg[proxy_state_tree_1.IS_PROXY] ? arg[proxy_state_tree_1.VALUE] : arg)));
warning +=
'\n\n - To improve debugging experience "console.log" will NOT log proxies from Overmind, but the actual value. Please see docs to turn off this behaviour';
}
if (options.devtools ||
(typeof location !== 'undefined' &&
location.hostname === 'localhost' &&
options.devtools !== false)) {
const host = options.devtools === true ? 'localhost:3031' : options.devtools;
const name = options.name
? options.name
: typeof document === 'undefined'
? 'NoName'
: document.title || 'NoName';
this.initializeDevtools(host, name, eventHub, proxyStateTree.sourceState, configuration.actions);
}
else if (options.devtools !== false) {
warning +=
'\n\n - You are not running on localhost. You will have to manually define the devtools option to connect';
}
if (!utils_1.IS_TEST) {
console.warn(warning);
}
}
if (utils_1.ENVIRONMENT === 'production' && mode.mode === utils_1.MODE_DEFAULT) {
eventHub.on(internalTypes_1.EventType.OPERATOR_ASYNC, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
proxyStateTree.getMutationTree().flush(true);
}
});
eventHub.on(internalTypes_1.EventType.ACTION_END, (execution) => {
if (!execution.parentExecution || !execution.parentExecution.isRunning)
proxyStateTree.getMutationTree().flush();
});
let nextTick;
const flushTree = () => {
proxyStateTree.getMutationTree().flush(true);
};
this.proxyStateTree.onMutation(() => {
nextTick && clearTimeout(nextTick);
nextTick = setTimeout(flushTree, 0);
});
}
else if (mode.mode === utils_1.MODE_DEFAULT || mode.mode === utils_1.MODE_TEST) {
if (utils_1.ENVIRONMENT === 'test' ||
(this.devtools && options.hotReloading !== false)) {
eventHub.on(internalTypes_1.EventType.MUTATIONS, (execution) => {
this.reydrateMutationsForHotReloading = this.reydrateMutationsForHotReloading.concat(execution.mutations);
});
}
eventHub.on(internalTypes_1.EventType.OPERATOR_ASYNC, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
const flushData = execution.flush(true);
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign({}, execution), flushData),
});
}
}
});
eventHub.on(internalTypes_1.EventType.ACTION_END, (execution) => {
if (!execution.parentExecution ||
!execution.parentExecution.isRunning) {
const flushData = execution.flush();
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign({}, execution), flushData),
});
}
}
});
}
if (mode.mode === utils_1.MODE_DEFAULT && configuration.onInitialize) {
const onInitialize = this.createAction('onInitialize', configuration.onInitialize);
this.initialized = Promise.resolve(onInitialize(this));
}
else {
this.initialized = Promise.resolve(null);
}
}
createProxyStateTree(configuration, eventHub, devmode, ssr) {
const proxyStateTree = new proxy_state_tree_1.ProxyStateTree(this.getState(configuration), {
devmode,
ssr,
delimiter: this.delimiter,
onSetFunction: (tree, path, target, prop, func) => {
if (func[derived_1.IS_DERIVED_CONSTRUCTOR]) {
return new derived_1.Derived(func);
}
return func;
},
onGetFunction: (tree, path, target, prop) => {
let func = target[prop];
if (func[derived_1.IS_DERIVED]) {
return func(eventHub, tree, proxyStateTree, path.split(this.delimiter));
}
if (func[derived_1.IS_DERIVED_CONSTRUCTOR]) {
const derived = new derived_1.Derived(func);
target[prop] = derived;
return derived(eventHub, tree, proxyStateTree, path.split(this.delimiter));
}
return func;
},
onGetter: devmode
? (path, value) => {
this.eventHub.emitAsync(internalTypes_1.EventType.GETTER, {
path,
value,
});
}
: undefined,
});
return proxyStateTree;
}
createExecution(name, action, parentExecution) {
const namespacePath = name.split('.');
namespacePath.pop();
if (utils_1.ENVIRONMENT === 'production') {
return {
[utils_1.EXECUTION]: true,
parentExecution,
namespacePath,
actionName: name,
getMutationTree: () => {
return this.proxyStateTree.getMutationTree();
},
getTrackStateTree: () => {
return this.proxyStateTree.getTrackStateTree();
},
emit: this.eventHub.emit.bind(this.eventHub),
};
}
const mutationTrees = [];
const execution = {
[utils_1.EXECUTION]: true,
namespacePath,
actionId: name,
executionId: this.nextExecutionId++,
actionName: name,
operatorId: 0,
isRunning: true,
parentExecution,
path: [],
emit: this.eventHub.emit.bind(this.eventHub),
send: this.devtools ? this.devtools.send.bind(this.devtools) : () => { },
trackEffects: this.trackEffects.bind(this, this.effects),
getNextOperatorId: (() => {
let currentOperatorId = 0;
return () => ++currentOperatorId;
})(),
flush: parentExecution
? parentExecution.flush
: (isAsync) => {
return this.proxyStateTree.flush(mutationTrees, isAsync);
},
getMutationTree: parentExecution
? parentExecution.getMutationTree
: () => {
const mutationTree = this.proxyStateTree.getMutationTree();
mutationTrees.push(mutationTree);
return mutationTree;
},
getTrackStateTree: () => {
return this.proxyStateTree.getTrackStateTree();
},
onFlush: (cb) => {
return this.proxyStateTree.onFlush(cb);
},
scopeValue: (value, tree) => {
return this.scopeValue(value, tree);
},
};
return execution;
}
createContext(execution, tree) {
return {
state: tree.state,
actions: utils_1.createActionsProxy(this.actions, (action) => {
return (value) => action(value, execution.isRunning ? execution : null);
}),
execution,
proxyStateTree: this.proxyStateTree,
effects: this.trackEffects(this.effects, execution),
};
}
scopeValue(value, tree) {
if (!value) {
return value;
}
if (value[proxy_state_tree_1.IS_PROXY]) {
return this.proxyStateTree.rescope(value, tree);
}
else if (is_plain_obj_1.default(value)) {
return Object.assign({}, ...Object.keys(value).map((key) => ({
[key]: this.proxyStateTree.rescope(value[key], tree),
})));
}
else {
return value;
}
}
addExecutionMutation(mutation) {
;
this.mutations.push(mutation);
}
createAction(name, originalAction) {
this.actionReferences[name] = originalAction;
const actionFunc = (value, boundExecution) => {
const action = this.actionReferences[name];
// Developer might unintentionally pass more arguments, so have to ensure
// that it is an actual execution
boundExecution =
boundExecution && boundExecution[utils_1.EXECUTION] ? boundExecution : undefined;
if (utils_1.ENVIRONMENT === 'production' || action[utils_1.IS_OPERATOR]) {
const execution = this.createExecution(name, action, boundExecution);
this.eventHub.emit(internalTypes_1.EventType.ACTION_START, Object.assign(Object.assign({}, execution), { value }));
if (action[utils_1.IS_OPERATOR]) {
return new Promise((resolve, reject) => {
action(null, Object.assign(Object.assign({}, this.createContext(execution, this.proxyStateTree)), { value }), (err, finalContext) => {
execution.isRunning = false;
finalContext &&
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, Object.assign(Object.assign({}, finalContext.execution), { operatorId: finalContext.execution.operatorId - 1 }));
if (err)
reject(err);
else {
resolve(this.mode.mode === utils_1.MODE_TEST
? finalContext.execution
: undefined);
}
});
});
}
else {
const mutationTree = execution.getMutationTree();
if (this.isStrict) {
mutationTree.blockMutations();
}
const returnValue = action(this.createContext(execution, mutationTree), value);
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, execution);
return returnValue;
}
}
else {
const execution = Object.assign(Object.assign({}, this.createExecution(name, action, boundExecution)), { operatorId: 0, type: 'action' });
this.eventHub.emit(internalTypes_1.EventType.ACTION_START, Object.assign(Object.assign({}, execution), { value }));
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_START, execution);
const mutationTree = execution.getMutationTree();
if (this.isStrict) {
mutationTree.blockMutations();
}
mutationTree.onMutation((mutation) => {
this.eventHub.emit(internalTypes_1.EventType.MUTATIONS, Object.assign(Object.assign({}, execution), { mutations: [mutation] }));
});
const scopedValue = this.scopeValue(value, mutationTree);
const context = this.createContext(execution, mutationTree);
try {
let pendingFlush;
mutationTree.onMutation((mutation) => {
if (pendingFlush) {
clearTimeout(pendingFlush);
}
if (this.mode.mode === utils_1.MODE_TEST) {
this.addExecutionMutation(mutation);
}
pendingFlush = setTimeout(() => {
pendingFlush = null;
const flushData = execution.flush(true);
if (this.devtools && flushData.mutations.length) {
this.devtools.send({
type: 'flush',
data: Object.assign(Object.assign(Object.assign({}, execution), flushData), { mutations: flushData.mutations }),
});
}
});
});
let result = action(context, scopedValue);
if (utils_1.isPromise(result)) {
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_ASYNC, execution);
result = result
.then((promiseResult) => {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: true, result: undefined }));
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, execution);
return promiseResult;
})
.catch((error) => {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: true, result: undefined, error: error.message }));
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, execution);
throw error;
});
}
else {
execution.isRunning = false;
if (!boundExecution) {
mutationTree.dispose();
}
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: false, result: undefined }));
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, execution);
}
return result;
}
catch (err) {
this.eventHub.emit(internalTypes_1.EventType.OPERATOR_END, Object.assign(Object.assign({}, execution), { isAsync: false, result: undefined, error: err.message }));
this.eventHub.emit(internalTypes_1.EventType.ACTION_END, execution);
throw err;
}
}
};
return actionFunc;
}
trackEffects(effects = {}, execution) {
if (utils_1.ENVIRONMENT === 'production') {
return effects;
}
return proxyfyEffects_1.proxifyEffects(this.effects, (effect) => {
let result;
try {
if (this.mode.mode === utils_1.MODE_TEST) {
const mode = this.mode;
result = mode.options.effectsCallback(effect);
}
else {
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: true, error: false }));
result = effect.func.apply(this, effect.args);
}
}
catch (error) {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: false, error: error.message }));
throw error;
}
if (utils_1.isPromise(result)) {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: true, error: false }));
return result
.then((promisedResult) => {
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, result: promisedResult, isPending: false, error: false }));
return promisedResult;
})
.catch((error) => {
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, isPending: false, error: error && error.message }));
throw error;
});
}
// eslint-disable-next-line standard/no-callback-literal
this.eventHub.emit(internalTypes_1.EventType.EFFECT, Object.assign(Object.assign(Object.assign({}, execution), effect), { args: effect.args, result: result, isPending: false, error: false }));
return result;
});
}
initializeDevtools(host, name, eventHub, initialState, actions) {
if (utils_1.ENVIRONMENT === 'production')
return;
const devtools = new Devtools_1.Devtools(name);
devtools.connect(host, (message) => {
switch (message.type) {
case 'refresh':
location.reload(true);
break;
case 'executeAction':
const action = message.data.name
.split('.')
.reduce((aggr, key) => aggr[key], this.actions);
message.data.payload
? action(JSON.parse(message.data.payload))
: action();
break;
case 'mutation':
const tree = this.proxyStateTree.getMutationTree();
const path = message.data.path.slice();
const value = JSON.parse(`{ "value": ${message.data.value} }`).value;
const key = path.pop();
const state = path.reduce((aggr, key) => aggr[key], tree.state);
state[key] = value;
tree.flush(true);
tree.dispose();
this.devtools.send({
type: 'state',
data: {
path: message.data.path,
value,
},
});
}
});
for (let type in internalTypes_1.EventType) {
eventHub.on(internalTypes_1.EventType[type], ((eventType) => (data) => {
devtools.send({
type: internalTypes_1.EventType[type],
data,
});
if (eventType === internalTypes_1.EventType.MUTATIONS) {
// We want to trigger property access when setting objects and arrays, as any derived set would
// then trigger and update the devtools
data.mutations.forEach((mutation) => {
const value = mutation.path
.split(this.delimiter)
.reduce((aggr, key) => aggr[key], this.proxyStateTree.state);
if (is_plain_obj_1.default(value)) {
Object.keys(value).forEach((key) => value[key]);
}
else if (Array.isArray(value)) {
value.forEach((item) => {
if (is_plain_obj_1.default(item)) {
Object.keys(item).forEach((key) => item[key]);
}
});
}
});
}
// Access the derived which will trigger calculation and devtools
if (eventType === internalTypes_1.EventType.DERIVED_DIRTY) {
data.derivedPath.reduce((aggr, key) => aggr[key], this.proxyStateTree.state);
}
})(internalTypes_1.EventType[type]));
}
devtools.send({
type: 'init',
data: {
state: this.proxyStateTree.state,
actions: utils_1.getActionPaths(actions),
delimiter: this.delimiter,
},
});
this.devtools = devtools;
}
getState(configuration) {
let state = {};
if (configuration.state) {
state = utils_1.processState(configuration.state);
}
return state;
}
getActions(actions = {}, path = []) {
return Object.keys(actions).reduce((aggr, name) => {
if (typeof actions[name] === 'function') {
const action = this.createAction(path.concat(name).join('.'), actions[name]);
action.displayName = path.concat(name).join('.');
return Object.assign(aggr, {
[name]: action,
});
}
return Object.assign(aggr, {
[name]: this.getActions(actions[name], path.concat(name)),
});
}, {});
}
/*
Related to hot reloading we update the existing action references and add any new
actions.
*/
updateActions(actions = {}, path = []) {
Object.keys(actions).forEach((name) => {
if (typeof actions[name] === 'function') {
const actionName = path.concat(name).join('.');
if (this.actionReferences[actionName]) {
this.actionReferences[actionName] = actions[name];
}
else {
const target = path.reduce((aggr, key) => {
if (!aggr[key]) {
aggr[key] = {};
}
return aggr[key];
}, this.actions);
target[name] = this.createAction(actionName, actions[name]);
target[name].displayName = path.concat(name).join('.');
}
}
else {
this.updateActions(actions[name], path.concat(name));
}
}, {});
}
getTrackStateTree() {
return this.proxyStateTree.getTrackStateTree();
}
getMutationTree() {
return this.proxyStateTree.getMutationTree();
}
reconfigure(configuration) {
const changeMutations = utils_1.getChangeMutations(this.originalConfiguration.state, configuration.state || {});
this.updateActions(configuration.actions);
this.effects = configuration.effects || {};
const mutationTree = this.proxyStateTree.getMutationTree();
// We change the state to match the new structure
rehydrate_1.rehydrate(mutationTree.state, changeMutations);
// We run any mutations ran during the session, it might fail though
// as the state structure might have changed, but no worries we just
// ignore that
this.reydrateMutationsForHotReloading.forEach((mutation) => {
try {
rehydrate_1.rehydrate(mutationTree.state, [mutation]);
}
catch (error) {
// No worries, structure changed and we do not want to mutate anyways
}
});
mutationTree.flush();
mutationTree.dispose();
if (this.devtools) {
this.devtools.send({
type: 're_init',
data: {
state: this.state,
actions: utils_1.getActionPaths(configuration.actions),
},
});
}
return this;
}
}
exports.Overmind = Overmind;
function pipe(...operators) {
const instance = (err, context, next, final = next) => {
if (err)
next(err, context);
else {
let operatorIndex = 0;
const run = (operatorErr, operatorContext) => {
const operator = operators[operatorIndex++];
try {
;
(operator || next)(operatorErr, operatorContext, run, final);
}
catch (operatorError) {
;
(operator || next)(operatorError, operatorContext, run, final);
}
};
run(null, context);
}
};
instance[utils_1.IS_OPERATOR] = true;
return instance;
}
exports.pipe = pipe;
/*
OPERATORS
*/
function forEach(forEachItemOperator) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
let array = context.value;
let evaluatingCount = array.length;
let lastContext;
let hasErrored = false;
const evaluate = (err) => {
if (hasErrored) {
return;
}
if (err) {
hasErrored = true;
return next(err);
}
evaluatingCount--;
if (!evaluatingCount) {
operator_1.operatorStopped(context, context.value);
next(null, operator_1.createContext(lastContext, context.value, lastContext.execution.path &&
lastContext.execution.path.slice(0, lastContext.execution.path.length - 1)));
}
};
operator_1.operatorStarted('forEach', '', context);
if (array.length) {
array.forEach((value, index) => {
lastContext = operator_1.createContext(lastContext || context, value, context.execution.path &&
context.execution.path.concat(String(index)));
const nextWithPath = operator_1.createNextPath(evaluate);
// @ts-ignore
forEachItemOperator(null, lastContext, nextWithPath);
});
}
else {
operator_1.operatorStopped(context, context.value);
next(null, operator_1.createContext(context, context.value));
}
}
};
instance[utils_1.IS_OPERATOR] = true;
return instance;
}
exports.forEach = forEach;
function parallel(...operators) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
let evaluatingCount = operators.length;
let lastContext;
let hasErrored = false;
const evaluate = (err) => {
if (hasErrored) {
return;
}
if (err) {
hasErrored = true;
return next(err, lastContext);
}
evaluatingCount--;
if (!evaluatingCount) {
operator_1.operatorStopped(context, context.value);
next(null, operator_1.createContext(lastContext, context.value, lastContext.execution.path &&
lastContext.execution.path.slice(0, lastContext.execution.path.length - 1)));
}
};
operator_1.operatorStarted('parallel', '', context);
operators.forEach((operator, index) => {
lastContext = operator_1.createContext(lastContext || context, context.value, context.execution.path && context.execution.path.concat(String(index)));
const nextWithPath = operator_1.createNextPath(evaluate);
// @ts-ignore
operator(null, lastContext, nextWithPath);
});
}
};
instance[utils_1.IS_OPERATOR] = true;
return instance;
}
exports.parallel = parallel;
function map(operation) {
return operator_1.createOperator('map', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else
next(null, operation(context, value));
});
}
exports.map = map;
function noop() {
return operator_1.createOperator('noop', '', (err, context, value, next) => {
if (err)
next(err, value);
else
next(null, value);
});
}
exports.noop = noop;
function filter(operation) {
return operator_1.createOperator('filter', utils_1.getFunctionName(operation), (err, context, value, next, final) => {
if (err)
next(err, value);
else if (operation(context, value))
next(null, value);
else
final(null, value);
});
}
exports.filter = filter;
let hasShownActionDeprecation = false;
function action(operation) {
if (!hasShownActionDeprecation) {
console.warn(`DEPRECATION - The action operator is deprecated in favor of "mutate". The reason is to avoid confusion between actions and operators. Check out action "${utils_1.getFunctionName(operation)}"`);
hasShownActionDeprecation = true;
}
return operator_1.createMutationOperator('action', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (utils_1.isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
exports.action = action;
function mutate(operation) {
return operator_1.createMutationOperator('mutate', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (utils_1.isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
exports.mutate = mutate;
function run(operation) {
return operator_1.createOperator('run', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (utils_1.isPromise(result)) {
next(null, result.then(() => value));
}
else {
next(null, value);
}
}
});
}
exports.run = run;
function catchError(operation) {
return operator_1.createMutationOperator('catchError', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(null, operation(context, err));
else
next(null, value, {
isSkipped: true,
});
});
}
exports.catchError = catchError;
function tryCatch(paths) {
const instance = (err, context, next) => {
if (err)
next(err, context);
else {
const evaluateCatch = (err, catchContext) => {
operator_1.operatorStopped(context, context.value);
next(err, operator_1.createContext(catchContext, context.value));
};
const evaluateTry = (err, tryContext) => {
if (err) {
const newContext = operator_1.createContext(tryContext, err, context.execution.path && context.execution.path.concat('catch'));
const nextWithPath = operator_1.createNextPath(evaluateCatch);
// @ts-ignore
paths.catch(null, newContext, nextWithPath);
}
else {
operator_1.operatorStopped(context, context.value);
next(null, operator_1.createContext(tryContext, context.value));
}
};
operator_1.operatorStarted('tryCatch', '', context);
const newContext = operator_1.createContext(context, context.value, context.execution.path && context.execution.path.concat('try'));
const nextWithPath = operator_1.createNextPath(evaluateTry);
// @ts-ignore
paths.try(null, newContext, nextWithPath);
}
};
instance[utils_1.IS_OPERATOR] = true;
return instance;
}
exports.tryCatch = tryCatch;
function fork(operation, paths) {
return operator_1.createOperator('fork', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const path = operation(context, value);
next(null, value, {
path: {
name: String(path),
operator: paths[path],
},
});
}
});
}
exports.fork = fork;
function when(operation, paths) {
return operator_1.createOperator('when', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else if (operation(context, value))
next(null, value, {
path: {
name: 'true',
operator: paths.true,
},
});
else
next(null, value, {
path: {
name: 'false',
operator: paths.false,
},
});
});
}
exports.when = when;
function wait(ms) {
return operator_1.createOperator('wait', String(ms), (err, context, value, next) => {
if (err)
next(err, value);
else
setTimeout(() => next(null, value), ms);
});
}
exports.wait = wait;
function debounce(ms) {
let timeout;
let previousFinal;
return operator_1.createOperator('debounce', String(ms), (err, context, value, next, final) => {
if (err)
next(err, value);
else {
if (timeout) {
clearTimeout(timeout);
previousFinal(null, value);
}
previousFinal = final;
timeout = setTimeout(() => {
timeout = null;
next(null, value);
}, ms);
}
});
}
exports.debounce = debounce;
function throttle(ms) {
let timeout;
let previousFinal;
let currentNext;
return operator_1.createOperator('throttle', String(ms), (err, context, value, next, final) => {
if (err)
next(err, value);
else {
if (timeout) {
previousFinal(null, value);
currentNext = next;
}
else {
timeout = setTimeout(() => {
timeout = null;
currentNext(null, value);
}, ms);
}
previousFinal = final;
currentNext = next;
}
});
}
exports.throttle = throttle;
function waitUntil(operation) {
return operator_1.createOperator('waitUntil', operation.name, (err, context, value, next) => {
if (err)
next(err, value);
else {
const tree = context.execution.getTrackStateTree();
const test = () => {
if (operation(tree.state)) {
tree.dispose();
next(null, value);
}
};
tree.trackScope(test, test);
}
});
}
exports.waitUntil = waitUntil;
//# sourceMappingURL=index.js.map

@@ -52,2 +52,19 @@ "use strict";

};
const changeOptionalFoo = (context, newFoo) => {
if (newFoo !== undefined) {
context.state.foo = newFoo;
}
else {
context.state.foo = 'default-foo';
}
};
const asyncChangeOptionalFoo = (context, newFoo) => tslib_1.__awaiter(this, void 0, void 0, function* () {
yield Promise.resolve();
if (newFoo !== undefined) {
context.state.foo = newFoo;
}
else {
context.state.foo = 'async-default-foo';
}
});
const changeFormValue = (_, payload) => {

@@ -70,2 +87,4 @@ const { form, key, value } = payload;

rehydrateAction,
changeOptionalFoo,
asyncChangeOptionalFoo,
};

@@ -101,6 +120,2 @@ const effects = {

const app = new _1.Overmind({
onInitialize(context, val) {
expect(context.state.foo).toBe('bar');
value = val;
},
state: {

@@ -110,2 +125,6 @@ foo: 'bar',

actions: {
onInitializeOvermind(context, val) {
expect(context.state.foo).toBe('bar');
value = val;
},
doThis() { },

@@ -150,3 +169,3 @@ },

});
test('should track action start and end', () => {
test('should track action start and end', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(2);

@@ -158,2 +177,3 @@ const app = new _1.Overmind({

});
yield app.initialized;
app.eventHub.once(_1.EventType.ACTION_START, (data) => {

@@ -165,3 +185,3 @@ expect(toJSON(data)).toEqual({

namespacePath: [],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -172,7 +192,7 @@ path: [],

});
app.eventHub.once(_1.EventType.ACTION_END, (data) => {
app.eventHub.on(_1.EventType.ACTION_END, (data) => {
expect(toJSON(data)).toEqual({
actionId: 'doThis',
isRunning: false,
executionId: 0,
executionId: 1,
actionName: 'doThis',

@@ -186,4 +206,4 @@ namespacePath: [],

app.actions.doThis();
});
test('should track operator start and end', () => {
}));
test('should track operator start and end', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(2);

@@ -195,2 +215,3 @@ const app = new _1.Overmind({

});
yield app.initialized;
app.eventHub.once(_1.EventType.OPERATOR_START, (data) => {

@@ -202,3 +223,3 @@ expect(toJSON(data)).toEqual({

path: [],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -216,3 +237,3 @@ namespacePath: [],

isAsync: false,
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -224,6 +245,7 @@ namespacePath: [],

app.actions.doThis();
});
test('should track mutations', () => {
}));
test('should track mutations', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.once(_1.EventType.MUTATIONS, (data) => {

@@ -243,3 +265,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -252,6 +274,7 @@ namespacePath: [],

app.actions.changeFoo();
});
test('should track async mutations', () => {
}));
test('should track async mutations', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.on(_1.EventType.MUTATIONS, (data) => {

@@ -271,3 +294,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -279,7 +302,8 @@ namespacePath: [],

});
app.actions.waitAndChangeFoo();
});
test('should track async mutations with async await', () => {
yield app.actions.waitAndChangeFoo();
}));
test('should track async mutations with async await', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const app = createDefaultOvermind();
yield app.initialized;
app.eventHub.on(_1.EventType.MUTATIONS, (data) => {

@@ -299,3 +323,3 @@ expect(toJSON(data)).toEqual({

],
executionId: 0,
executionId: 1,
operatorId: 0,

@@ -307,4 +331,4 @@ path: [],

});
app.actions.asyncChangeFoo();
});
yield app.actions.asyncChangeFoo();
}));
test('should instantiate app with modules', () => {

@@ -344,9 +368,13 @@ const foo = {

foo: {
onInitialize: () => {
result.push('foo');
actions: {
onInitializeOvermind: () => {
result.push('foo');
},
},
},
bar: {
onInitialize: () => {
result.push('bar');
actions: {
onInitializeOvermind: () => {
result.push('bar');
},
},

@@ -405,3 +433,16 @@ },

});
test('should allow actions with optional parameter', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const app = createDefaultOvermind();
app.actions.changeOptionalFoo();
expect(app.state.foo).toBe('default-foo');
yield app.actions.asyncChangeOptionalFoo();
expect(app.state.foo).toBe('async-default-foo');
const newFoo = 'new-foo';
app.actions.changeOptionalFoo(newFoo);
expect(app.state.foo).toBe(newFoo);
const newAsyncFoo = 'new-async-foo';
yield app.actions.asyncChangeOptionalFoo(newAsyncFoo);
expect(app.state.foo).toBe(newAsyncFoo);
}));
});
//# sourceMappingURL=index.test.js.map
import { IFlushCallback, IMutation, IMutationTree, ITrackStateTree } from 'proxy-state-tree';
import { IAction, IOperator, IContext } from './types';
import { IAction, IOperator } from './types';
export declare type SubType<Base, Condition> = Pick<Base, {

@@ -134,15 +134,27 @@ [Key in keyof Base]: Base[Key] extends Condition | undefined ? Key : never;

declare type NestedActions = {
[key: string]: IAction<any, any, any> | IOperator<any, any, any> | NestedActions;
} | undefined;
declare type TActionValue<T> = T extends (a1: any, a2: infer TValue) => any ? TValue : never;
export declare type ResolveActions<Actions extends NestedActions> = Actions extends undefined ? {} : {
[T in keyof Actions]: Actions[T] extends IOperator<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<void> : (value: TActionValue<Actions[T]>) => Promise<void> : Actions[T] extends IAction<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => ReturnType<Actions[T]> : (value: TActionValue<Actions[T]>) => ReturnType<Actions[T]> : Actions[T] extends NestedActions ? ResolveActions<Actions[T]> : unknown;
[key: string]: Function | NestedActions;
};
declare type NestedMockActions = {
[key: string]: IAction<any, any, any> | IOperator<any, any, any> | NestedMockActions;
} | undefined;
declare type MockResult = IMutation[];
export declare type ResolveMockActions<Actions extends NestedMockActions> = Actions extends undefined ? {} : {
[T in keyof Actions]: Actions[T] extends IOperator<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<MockResult> : (value: TActionValue<Actions[T]>) => Promise<MockResult> : Actions[T] extends IAction<any, any, any> ? Actions[T] extends (context: IContext<any>, value: void) => any ? () => Promise<MockResult> : (value: TActionValue<Actions[T]>) => Promise<MockResult> : Actions[T] extends NestedMockActions ? ResolveMockActions<Actions[T]> : unknown;
};
export declare type ResolveAction<T> = T extends IOperator<void, infer R> ? () => Promise<R> : T extends IOperator<infer P | undefined, infer R> ? (payload?: P) => Promise<R> : T extends IOperator<infer P, infer R> ? (payload: P) => Promise<R> : T extends IAction<void, infer R> ? () => R : T extends IAction<infer P | undefined, infer R> ? (payload?: P) => R : T extends IAction<infer P, infer R> ? (payload: P) => R : T extends NestedActions ? {
[K in keyof T]: ResolveAction<T[K]>;
} : never;
export interface ContextFunction<P extends any, R extends any> {
(context: {
state: any;
actions: any;
effects: any;
reaction: any;
addMutationListener: any;
addFlushListener: any;
}, payload: P): R;
}
export interface OperatorContextFunction<P extends any, R extends any> {
(context: {
state: any;
actions: any;
effects: any;
reaction: any;
addMutationListener: any;
addFlushListener: any;
}, payload: P extends Promise<infer PP> ? PP : P): R;
}
export {};

@@ -41,7 +41,10 @@ "use strict";

};
const onInitialize = ({ state }) => {
const onInitializeOvermind = ({ state }) => {
state.foo += '!';
};
const actions = {
onInitializeOvermind,
};
const config = {
onInitialize,
actions,
state,

@@ -48,0 +51,0 @@ };

@@ -1,3 +0,4 @@

import { Execution } from './internalTypes';
import { Execution, OperatorContextFunction } from './internalTypes';
import { IConfiguration, IContext } from './types';
export declare function action<T extends OperatorContextFunction<any, any>>(operation: T): T;
export declare function operatorStarted(type: any, arg: any, context: any): void;

@@ -4,0 +5,0 @@ export declare function operatorStopped(context: any, value: any, details?: {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMutationOperator = exports.createOperator = exports.createNextPath = exports.createContext = exports.operatorStopped = exports.operatorStarted = void 0;
exports.createMutationOperator = exports.createOperator = exports.createNextPath = exports.createContext = exports.operatorStopped = exports.operatorStarted = exports.action = void 0;
const internalTypes_1 = require("./internalTypes");
const utils_1 = require("./utils");
function action(operation) {
return createMutationOperator('action', utils_1.getFunctionName(operation), (err, context, value, next) => {
if (err)
next(err, value);
else {
const result = operation(context, value);
if (utils_1.isPromise(result)) {
next(null, result.then((resolvedValue) => resolvedValue));
}
else {
next(null, result);
}
}
});
}
exports.action = action;
function operatorStarted(type, arg, context) {

@@ -93,3 +109,5 @@ if (process.env.NODE_ENV === 'production') {

execution: context.execution,
revertable: context.revertable,
addFlushListener: context.addFlushListener,
addMutationListener: context.addMutationListener,
reaction: context.reaction,
}, context.value, (err, value, options = {}) => {

@@ -101,3 +119,6 @@ function run(err, value) {

const nextWithPath = createNextPath(next);
options.path.operator(err, newContext, (...args) => {
const operatorToRun = options.path.operator[utils_1.IS_OPERATOR]
? options.path.operator
: action(options.path.operator);
operatorToRun(err, newContext, (...args) => {
operatorStopped(context, args[1].value);

@@ -163,3 +184,5 @@ nextWithPath(...args);

execution: context.execution,
revertable: context.revertable,
addFlushListener: context.addFlushListener,
addMutationListener: context.addMutationListener,
reaction: context.reaction,
}, process.env.NODE_ENV === 'production'

@@ -166,0 +189,0 @@ ? context.value

@@ -16,13 +16,14 @@ "use strict";

}
const test = _1.pipe(_1.map(({ state }) => state.foo), toUpperCase(), _1.mutate(({ state }, val) => {
const test = _1.pipe(({ state }) => state.foo, toUpperCase(), ({ state }, val) => {
state.foo = val;
}));
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -45,7 +46,7 @@ const overmind = new _1.Overmind(config);

}
const test = _1.pipe(_1.mutate(() => {
const test = _1.pipe(() => {
throw new Error('wut');
}), _1.mutate(({ state }, val) => {
}, () => {
operatorsRun++;
}), catchError((err) => {
}, catchError((err) => {
expect(err.message).toBe('wut');

@@ -56,7 +57,8 @@ }));

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -84,8 +86,8 @@ const overmind = new _1.Overmind(config);

const test = whenBananaOrApple({
banana: _1.mutate(({ state }) => {
banana: ({ state }) => {
state.foo = 'banana';
}),
apple: _1.mutate(({ state }) => {
},
apple: ({ state }) => {
state.foo = 'apple';
}),
},
});

@@ -95,7 +97,8 @@ const state = {

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -125,7 +128,8 @@ const overmind = new _1.Overmind(config);

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -163,8 +167,9 @@ const overmind = new _1.Overmind(config);

};
const actions = {
test,
mutateFoo,
};
const config = {
state,
actions: {
test,
mutateFoo,
},
actions,
};

@@ -203,8 +208,9 @@ const overmind = new _1.Overmind(config);

};
const actions = {
test,
mutateBar,
};
const config = {
state,
actions: {
test,
mutateBar,
},
actions,
};

@@ -211,0 +217,0 @@ const overmind = new _1.Overmind(config);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const _1 = require("./");
describe('OPERATORS', () => {
test('map', () => {
test('branch - passes input as output', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const test = _1.pipe(_1.map((_, value) => value.toUpperCase()), _1.mutate(({ state }, value) => (state.foo = value)));
const state = {
foo: 'bar',
};
const actions = {
test: _1.pipe(_1.branch((_, value) => value.toUpperCase()), ({ state }, value) => {
state.foo = value;
}),
};
const config = {
state,
actions: {
test,
},
actions,
};
const overmind = new _1.Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
});
});
test('map (async)', () => {
yield overmind.actions.test('foo');
expect(overmind.state.foo).toBe('foo');
}));
test('action - return value', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
const test = _1.pipe(_1.map((_, value) => Promise.resolve(value.toUpperCase())), _1.mutate(({ state }, value) => (state.foo = value)));
const state = {
foo: 'bar',
};
const actions = {
test: _1.pipe((_, value) => value.toUpperCase(), ({ state }, value) => {
state.foo = value;
}),
};
const config = {
state,
actions: {
test,
},
actions,
};
const overmind = new _1.Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
yield overmind.actions.test('foo');
expect(overmind.state.foo).toBe('FOO');
}));
test('action - return value async', () => {
expect.assertions(1);
const test = _1.pipe((_, value) => Promise.resolve(value.toUpperCase()), ({ state }, value) => {
state.foo = value;
});
});
test('forEach', () => {
expect.assertions(1);
let runCount = 0;
const operator = (_, val, next) => {
runCount++;
next(null, val);
const state = {
foo: 'bar',
};
const test = _1.pipe(_1.forEach(operator));
const actions = { test };
const config = {
actions: {
test,
},
state,
actions,
};
const overmind = new _1.Overmind(config);
return overmind.actions.test(['foo']).then(() => {
expect(runCount).toEqual(1);
return overmind.actions.test('foo').then(() => {
expect(overmind.state.foo).toBe('FOO');
});
});
test('parallel', () => {
test('parallel', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
expect.assertions(1);
let runCount = 0;
const operator = (_, value, next) => {
runCount++;
next(null, value);
const operatorA = () => {
return Promise.resolve('A');
};
const test = _1.pipe(_1.parallel(operator, operator));
const operatorB = () => {
return Promise.resolve('B');
};
const actions = {
test: _1.parallel(operatorA, operatorB),
};
const config = {
actions: {
test,
},
actions,
};
const overmind = new _1.Overmind(config);
return overmind.actions.test('foo').then(() => {
expect(runCount).toEqual(2);
});
});
const result = yield overmind.actions.test();
expect(result).toEqual(['A', 'B']);
}));
test('filter - truthy', () => {
expect.assertions(1);
const test = _1.pipe(_1.filter((_, value) => value === 'foo'), _1.map((_, value) => value.toUpperCase()), _1.mutate(({ state }, value) => (state.foo = value)));
const test = _1.pipe(_1.filter((_, value) => value === 'foo'), ({ state }, value) => (state.foo = value.toUpperCase()));
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -93,11 +97,12 @@ const overmind = new _1.Overmind(config);

test('filter - falsy', () => {
const test = _1.pipe(_1.filter((_, value) => value === 'bar'), _1.map((_, value) => value.toUpperCase()), _1.mutate(({ state }, value) => (state.foo = value)));
const test = _1.pipe(_1.filter((_, value) => value === 'bar'), ({ state }, value) => (state.foo = value.toUpperCase()));
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -111,21 +116,24 @@ const overmind = new _1.Overmind(config);

expect.assertions(1);
let Key;
(function (Key) {
Key["Foo"] = "foo";
})(Key || (Key = {}));
const test = _1.pipe(_1.fork(() => Key.Foo, {
[Key.Foo]: _1.pipe(_1.map((_, value) => {
return value.toUpperCase();
}), _1.mutate(({ state }, value) => (state.foo = value))),
}));
const config = {
state: {
foo: 'bar',
const test = _1.pipe(() => ({ type: 'foo' }), _1.fork('type', {
foo: () => {
return 'FOO';
},
actions: {
test,
bar: () => {
return 'BAR';
},
}), ({ state }, value) => {
state.foo = value;
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions,
};
const overmind = new _1.Overmind(config);
return overmind.actions.test('foo').then(() => {
return overmind.actions.test().then(() => {
expect(overmind.state.foo).toBe('FOO');

@@ -136,6 +144,8 @@ });

expect.assertions(1);
const test = _1.pipe(_1.when(() => true, {
true: _1.pipe(_1.map((_, value) => value.toUpperCase()), _1.mutate(({ state }, value) => (state.foo = value))),
false: _1.pipe(_1.map((_, value) => Number(value)), _1.mutate(({ state }, value) => (state.number = value))),
}));
const test = _1.when(() => true, {
true: ({ state }, value) => {
state.foo = value.toUpperCase();
},
false: ({ state }, value) => (state.number = Number(value)),
});
const state = {

@@ -145,7 +155,8 @@ foo: 'bar',

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -161,6 +172,5 @@ const overmind = new _1.Overmind(config);

const test = _1.wait(500);
const actions = { test };
const config = {
actions: {
test,
},
actions,
};

@@ -174,11 +184,12 @@ const overmind = new _1.Overmind(config);

expect.assertions(1);
const test = _1.pipe(_1.debounce(100), _1.mutate(({ state }) => state.runCount++));
const test = _1.pipe(_1.debounce(100), ({ state }) => state.runCount++);
const state = {
runCount: 0,
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -192,11 +203,12 @@ const overmind = new _1.Overmind(config);

expect.assertions(1);
const test = _1.pipe(_1.throttle(0), _1.mutate(({ state }) => state.runCount++));
const test = _1.pipe(_1.throttle(0), ({ state }) => state.runCount++);
const state = {
runCount: 0,
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -210,12 +222,13 @@ const overmind = new _1.Overmind(config);

expect.assertions(3);
const test = _1.pipe(_1.mutate(() => {
const test = _1.pipe((() => {
throw new Error('wut?!?');
}), _1.mutate(({ state }) => {
}), ({ state }, payload) => {
state.runCount++;
}), _1.catchError(({ state }, error) => {
return payload;
}, _1.catchError(({ state }, error) => {
state.error = error.message;
return 'hm';
}), _1.mutate(({ state }, value) => {
}), ({ state }, value) => {
state.foo = value;
}));
});
const state = {

@@ -226,7 +239,8 @@ runCount: 0,

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -243,6 +257,6 @@ const overmind = new _1.Overmind(config);

const test = _1.tryCatch({
try: _1.mutate(({ state }, value) => {
try: ({ state }, value) => {
state.foo = value;
}),
catch: _1.mutate(() => { }),
},
catch: () => { },
});

@@ -252,7 +266,8 @@ const state = {

};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -266,18 +281,19 @@ const overmind = new _1.Overmind(config);

expect.assertions(1);
const test = _1.pipe(_1.tryCatch({
try: _1.mutate(() => {
const test = _1.tryCatch({
try: (() => {
throw new Error('ehm');
}),
catch: _1.mutate(({ state }, value) => {
catch: ({ state }, value) => {
state.foo = value.message;
}),
}));
},
});
const state = {
foo: 'bar',
};
const actions = {
test,
};
const config = {
state,
actions: {
test,
},
actions,
};

@@ -291,4 +307,4 @@ const overmind = new _1.Overmind(config);

expect.assertions(1);
const increaseCount = _1.pipe(_1.mutate(({ state }) => state.runCount++));
const test = _1.pipe(_1.waitUntil((state) => state.runCount === 1), _1.mutate(({ state }) => (state.hasRun = true)));
const increaseCount = _1.pipe(({ state }) => state.runCount++);
const test = _1.pipe(_1.waitUntil((state) => state.runCount === 1), ({ state }) => (state.hasRun = true));
const state = {

@@ -298,8 +314,9 @@ runCount: 0,

};
const actions = {
increaseCount,
test,
};
const config = {
state,
actions: {
increaseCount,
test,
},
actions,
};

@@ -306,0 +323,0 @@ const overmind = new _1.Overmind(config);

@@ -20,2 +20,3 @@ "use strict";

const method = name.pop();
// eslint-disable-next-line
return cb({

@@ -41,3 +42,3 @@ func: target.bind(thisArg ? thisArg[ORIGIN_TARGET] : undefined),

return proxifyEffects(target[prop], cb, path ? path + '.' + prop.toString() : prop.toString());
}
},
});

@@ -44,0 +45,0 @@ }

@@ -14,7 +14,8 @@ "use strict";

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -40,7 +41,8 @@ const app = new _1.Overmind(config);

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -57,3 +59,2 @@ const app = new _1.Overmind(config);

expect.assertions(1);
let runCount = 0;
const state = {

@@ -67,7 +68,8 @@ foo: {

};
const actions = {
changeFoo,
};
const config = {
state,
actions: {
changeFoo,
},
actions,
};

@@ -77,3 +79,2 @@ const app = new _1.Overmind(config);

app.reaction(({ foo }) => foo.bar, (bar) => {
runCount++;
expect(bar).toBe('baz2');

@@ -80,0 +81,0 @@ }, { nested: true });

@@ -12,5 +12,8 @@ "use strict";

if (typeof classInstance === 'function' && Array.isArray(target[key])) {
target[key] = source[key].map(value => classInstance(value));
target[key] = source[key].map((value) => classInstance(value));
}
else if (typeof classInstance === 'function' && typeof target[key] === 'object' && target[key] !== null && target[key].constructor.name === 'Object') {
else if (typeof classInstance === 'function' &&
typeof target[key] === 'object' &&
target[key] !== null &&
target[key].constructor.name === 'Object') {
target[key] = Object.keys(source[key]).reduce((aggr, subKey) => {

@@ -24,3 +27,5 @@ aggr[subKey] = classInstance(source[key][subKey]);

}
else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
else if (typeof value === 'object' &&
!Array.isArray(value) &&
value !== null) {
if (!target[key])

@@ -37,3 +42,3 @@ target[key] = {};

exports.SERIALIZE = Symbol('SERIALIZE');
exports.rehydrate = (state, source, classes = {}) => {
const rehydrate = (state, source, classes = {}) => {
if (Array.isArray(source)) {

@@ -47,3 +52,4 @@ const mutations = source;

if (mutation.method === 'set') {
if (typeof classInstance === 'function' && Array.isArray(mutation.args[0])) {
if (typeof classInstance === 'function' &&
Array.isArray(mutation.args[0])) {
target[key] = mutation.args[0].map((arg) => classInstance(arg));

@@ -62,5 +68,9 @@ }

else {
target[key][mutation.method].apply(target[key], typeof classInstance === 'function' ? mutation.args.map((arg) => {
return typeof arg === 'object' && arg !== null ? classInstance(arg) : arg;
}) : mutation.args);
target[key][mutation.method].apply(target[key], typeof classInstance === 'function'
? mutation.args.map((arg) => {
return typeof arg === 'object' && arg !== null
? classInstance(arg)
: arg;
})
: mutation.args);
}

@@ -73,2 +83,3 @@ });

};
exports.rehydrate = rehydrate;
//# sourceMappingURL=rehydrate.js.map

@@ -8,9 +8,9 @@ "use strict";

const state = {
foo: 'bar'
foo: 'bar',
};
_1.rehydrate(state, {
foo: 'bar2'
foo: 'bar2',
});
expect(state).toEqual({
foo: 'bar2'
foo: 'bar2',
});

@@ -21,5 +21,6 @@ });

const state = {
foo: 'bar'
foo: 'bar',
};
_1.rehydrate(state, [{
_1.rehydrate(state, [
{
method: 'set',

@@ -29,6 +30,7 @@ args: ['bar2'],

path: 'foo',
revert: () => { }
}]);
revert: () => { },
},
]);
expect(state).toEqual({
foo: 'bar2'
foo: 'bar2',
});

@@ -45,3 +47,3 @@ });

[_1.SERIALIZE]: true,
name: this.name
name: this.name,
};

@@ -59,7 +61,7 @@ }

user: {
name: 'Bob2'
name: 'Bob2',
},
user2: {
name: 'Bob2'
}
name: 'Bob2',
},
}, {

@@ -71,7 +73,7 @@ user: User.fromJSON,

user: {
name: 'Bob2'
name: 'Bob2',
},
user2: {
name: 'Bob2'
}
name: 'Bob2',
},
});

@@ -93,7 +95,10 @@ });

_1.rehydrate(state, {
users: [{
name: 'Bob2'
}, {
name: 'Bob3'
}]
users: [
{
name: 'Bob2',
},
{
name: 'Bob3',
},
],
}, {

@@ -120,9 +125,9 @@ users: User.fromJSON,

users: {
'id1': {
name: 'Bob2'
id1: {
name: 'Bob2',
},
'id2': {
name: 'Bob3'
}
}
id2: {
name: 'Bob3',
},
},
}, {

@@ -129,0 +134,0 @@ users: User.fromJSON,

@@ -37,7 +37,9 @@ "use strict";

};
const onInitialize = ({ state }, overmind) => {
_1.rehydrate(state, mutations);
const actions = {
onInitializeOvermind: ({ state }) => {
_1.rehydrate(state, mutations);
},
};
const config = {
onInitialize,
actions,
state,

@@ -44,0 +46,0 @@ };

@@ -12,8 +12,14 @@ import { IState } from '.';

};
export declare type StatemachineTransitions<States extends TState, Events extends TEvents, BaseState extends TBaseState> = {
[Type in Events['type']]: [BaseState] extends [never] ? ((state: States, payload: Events extends {
type: Type;
} ? Events['data'] : never) => States | void) : ((state: States & BaseState, payload: Events extends {
type: Type;
} ? Events['data'] : never) => States | void);
export declare type StatemachineTransitions<States extends TState, Events extends TEvents, BaseState extends TBaseState> = ([BaseState] extends [never] ? (event: Events, state: States) => States | void : (event: Events, state: States & BaseState) => States | void) | {
[State in States['current']]: {
[Type in Events['type']]?: [BaseState] extends [never] ? ((event: Events extends {
type: Type;
} ? Events['data'] : never, state: States extends {
current: State;
} ? States : never) => States | void) : ((event: Events extends {
type: Type;
} ? Events['data'] : never, state: States extends {
current: State;
} ? States & BaseState : never) => States | void);
};
};

@@ -28,2 +34,3 @@ export interface MachineMethods<States extends TState, Events extends TEvents, BaseState extends TBaseState> {

} ? [T, Events['data']] : [T]): Statemachine<States, Events, BaseState>;
onTransition(listener: (state: States) => void): void;
}

@@ -36,2 +43,3 @@ export declare type Statemachine<States extends TState, Events extends TEvents, BaseState extends TBaseState = never> = [BaseState] extends [never] ? States & MachineMethods<States, Events, BaseState> : States & BaseState & MachineMethods<States, Events, BaseState>;

declare const BASE_STATE: unique symbol;
declare const TRANSITION_LISTENERS: unique symbol;
export declare function deepCopy(obj: any): any;

@@ -44,2 +52,3 @@ export declare class StateMachine<State extends TState, Events extends TEvents, BaseState extends TBaseState> {

private [BASE_STATE];
private [TRANSITION_LISTENERS];
private [IS_DISPOSED];

@@ -51,2 +60,3 @@ private clone;

matches(state: any): this | undefined;
onTransition(listener: (state: State) => void): void;
}

@@ -53,0 +63,0 @@ export declare type StatemachineFactory<States extends TState, Events extends TEvents, BaseState extends TBaseState> = [BaseState] extends [never] ? {

"use strict";
var _a;
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });

@@ -14,2 +14,3 @@ exports.statemachine = exports.StateMachine = exports.deepCopy = void 0;

const BASE_STATE = Symbol('BASE_STATE');
const TRANSITION_LISTENERS = Symbol('TRANSITION_LISTENERS');
// We have to export here to avoid a circular dependency issue with "utils"

@@ -45,3 +46,4 @@ function deepCopy(obj) {

constructor(transitions, state, baseState) {
this[_a] = false;
this[_a] = [];
this[_b] = false;
this[STATE] = state;

@@ -59,2 +61,3 @@ this[BASE_STATE] = baseState;

dispose() {
this[proxy_state_tree_1.VALUE][TRANSITION_LISTENERS] = [];
Object.keys(this[proxy_state_tree_1.VALUE]).forEach((key) => {

@@ -75,5 +78,12 @@ if (this[proxy_state_tree_1.VALUE][key] instanceof StateMachine) {

const tree = this[proxy_state_tree_1.PROXY_TREE].master.mutationTree || this[proxy_state_tree_1.PROXY_TREE];
const transition = this[proxy_state_tree_1.VALUE][TRANSITIONS][type];
tree.enableMutations();
const result = transition(this, data);
let result;
if (typeof this[proxy_state_tree_1.VALUE][TRANSITIONS] === 'function') {
const transition = this[proxy_state_tree_1.VALUE][TRANSITIONS];
result = transition({ type, data }, this);
}
else {
const transition = this[proxy_state_tree_1.VALUE][TRANSITIONS][this[proxy_state_tree_1.VALUE].current][type];
result = transition(data, this);
}
if (result) {

@@ -87,2 +97,3 @@ this[proxy_state_tree_1.VALUE][CURRENT_KEYS].forEach((key) => {

Object.assign(this, result);
this[proxy_state_tree_1.VALUE][TRANSITION_LISTENERS].forEach((listener) => listener(this));
}

@@ -97,5 +108,8 @@ tree.blockMutations();

}
onTransition(listener) {
this[proxy_state_tree_1.VALUE][TRANSITION_LISTENERS].push(listener);
}
}
exports.StateMachine = StateMachine;
_a = IS_DISPOSED;
_a = TRANSITION_LISTENERS, _b = IS_DISPOSED;
function statemachine(transitions) {

@@ -102,0 +116,0 @@ return {

@@ -8,5 +8,6 @@ "use strict";

const state = statemachine_1.statemachine({
TEST: () => { }
FOO: {},
BAR: {},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -21,7 +22,8 @@ const config = {

const state = statemachine_1.statemachine({
TEST: () => { }
FOO: {},
BAR: {},
}).create({
current: 'FOO',
}, {
foo: 'bar'
foo: 'bar',
});

@@ -35,7 +37,7 @@ const config = {

});
test('should transition state', () => {
const state = statemachine_1.statemachine({
TOGGLE: (state) => ({ current: state.current === 'FOO' ? 'BAR' : 'FOO' })
test('should transition state using function', () => {
const state = statemachine_1.statemachine((_, state) => {
return { current: state.current === 'FOO' ? 'BAR' : 'FOO' };
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -45,7 +47,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -57,8 +60,12 @@ const overmind = _1.createOvermindMock(config);

test('should remove state when transitioning', () => {
var _a;
const state = statemachine_1.statemachine({
TOGGLE: () => ({ current: 'BAR' })
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {
TOGGLE: () => ({ current: 'FOO', foo: 'foo' }),
},
}).create({
current: 'FOO',
foo: 'bar'
foo: 'bar',
});

@@ -68,11 +75,13 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};
const overmind = _1.createOvermindMock(config);
const fooContext = overmind.state.matches('FOO');
expect(overmind.state.current).toBe('FOO');
expect((_a = overmind.state.matches('FOO')) === null || _a === void 0 ? void 0 : _a.foo).toBe('bar');
expect(fooContext && fooContext.foo).toBe('bar');
overmind.actions.transition();

@@ -83,12 +92,10 @@ expect(overmind.state.current).toBe('BAR');

test('should block mutations in strict mode', () => {
const state = statemachine_1.statemachine({
TOGGLE: (state) => {
if (state.current === 'FOO') {
return { current: 'BAR' };
}
return { current: 'FOO', foo: 'bar' };
const state = statemachine_1.statemachine((_, state) => {
if (state.current === 'FOO') {
return { current: 'BAR' };
}
return { current: 'FOO', foo: 'bar' };
}).create({
current: 'FOO',
foo: 'bar'
foo: 'bar',
});

@@ -101,9 +108,14 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};
const overmind = _1.createOvermind(config, { devtools: false, strict: true, devEnv: 'test' });
const overmind = _1.createOvermind(config, {
devtools: false,
strict: true,
devEnv: 'test',
});
expect(() => overmind.actions.transition()).toThrow();

@@ -113,5 +125,10 @@ });

const state = statemachine_1.statemachine({
TOGGLE: () => { }
FOO: {
TOGGLE: () => { },
},
BAR: {
TOGGLE: () => { },
},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -121,7 +138,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -135,5 +153,8 @@ const overmind = _1.createOvermindMock(config);

const state = statemachine_1.statemachine({
TOGGLE: () => ({ current: 'BAR' })
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {},
}).create({
current: 'FOO'
current: 'FOO',
});

@@ -143,7 +164,8 @@ const transition = ({ state }) => {

};
const actions = {
transition,
};
const config = {
state,
actions: {
transition
}
actions,
};

@@ -158,8 +180,13 @@ const overmind = _1.createOvermind(config);

const state = statemachine_1.statemachine({
TEST: () => { }
FOO: {
TEST: () => { },
},
BAR: {
TEST: () => { },
},
}).create({
current: 'FOO',
obj: {
foo: 'bar'
}
foo: 'bar',
},
});

@@ -171,4 +198,4 @@ const config = {

state.obj.foo = 'bar2';
}
}
},
},
};

@@ -182,3 +209,27 @@ const overmind = _1.createOvermindMock(config);

});
test('should allow listening to state changes', () => {
expect.assertions(1);
const state = statemachine_1.statemachine({
FOO: {
TOGGLE: () => ({ current: 'BAR' }),
},
BAR: {},
}).create({
current: 'FOO',
});
const transition = ({ state }) => {
state.onTransition((state) => expect(state.current).toBe('BAR'));
state.send('TOGGLE');
};
const actions = {
transition,
};
const config = {
state,
actions,
};
const overmind = _1.createOvermind(config);
overmind.actions.transition();
});
});
//# sourceMappingURL=statemachine.test.js.map

@@ -1,4 +0,4 @@

import { Overmind } from './';
import { ResolveActions } from './internalTypes';
import { ResolveAction, ContextFunction } from './internalTypes';
import { IS_OPERATOR } from './utils';
import { IMutationCallback, IFlushCallback } from 'proxy-state-tree';
/** ===== PUBLIC API

@@ -8,3 +8,2 @@ */

export declare type IConfiguration = {
onInitialize?: any;
state?: {};

@@ -17,15 +16,23 @@ effects?: {};

};
export interface IConfig<ThisConfig extends IConfiguration> {
state: ThisConfig['state'] & {};
actions: ThisConfig['actions'] & {};
effects: ThisConfig['effects'] & {};
export declare type IContext<T extends IConfiguration> = {
state: T['state'];
actions: {
[K in keyof T['actions']]: ResolveAction<T['actions'][K]>;
};
effects: T['effects'];
reaction: IReaction<{
state: T['state'];
}>;
addMutationListener: (cb: IMutationCallback) => () => void;
addFlushListener: (cb: IFlushCallback) => () => void;
};
export interface IAction<I, O> extends ContextFunction<I, O> {
}
export declare type IContext<ThisConfig extends IConfiguration> = {
state: ThisConfig['state'];
actions: ResolveActions<ThisConfig['actions']>;
effects: ThisConfig['effects'];
revertable: (mutationsCallback: () => any) => () => void;
};
export interface IReaction<ThisConfig extends IConfiguration> {
<O>(stateCallback: (state: ThisConfig['state']) => O, updateCallback: (value: O) => void, options?: {
export interface IOperator<I, O> extends ContextFunction<I, O> {
[IS_OPERATOR]: true;
}
export interface IReaction<T extends {
state?: IState;
}> {
<O>(stateCallback: (state: T['state']) => O, updateCallback: (value: O) => void, options?: {
nested?: boolean;

@@ -35,11 +42,1 @@ immediate?: boolean;

}
export interface IAction<ThisConfig extends IConfiguration, Value, ReturnValue = void | Promise<void>> {
<InferredReturnValue extends ReturnValue>(context: IContext<ThisConfig>, value: Value): ReturnValue extends Promise<any> ? ReturnValue : InferredReturnValue | ReturnValue;
}
export interface IOperator<ThisConfig extends IConfiguration, Input, Output = Input> {
(context: IContext<ThisConfig>, value: Input): Output;
[IS_OPERATOR]: true;
}
export interface IOnInitialize<ThisConfig extends IConfiguration> {
(context: IContext<ThisConfig>, value: Overmind<ThisConfig>): void;
}
import { IMutation } from 'proxy-state-tree';
export { deepCopy } from './statemachine';
export declare const createOnInitialize: () => ({ actions }: {
actions: any;
}, instance: any) => Promise<[unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]>;
export declare const ENVIRONMENT: string;

@@ -19,7 +22,8 @@ export declare const IS_TEST: boolean;

export declare const json: <T>(obj: T) => T;
export declare function isPromise(maybePromise: any): boolean;
export declare function isPromise(maybePromise: any): any;
export declare function processState(state: {}): {};
export declare function getFunctionName(func: Function): any;
export declare function getChangeMutations(stateA: object, stateB: object, path?: string[], mutations?: IMutation[]): IMutation[];
export declare function getActionsByName(name: string, actions?: {}, currentPath?: string[]): any;
export declare function getActionPaths(actions?: {}, currentPath?: string[]): any;
export declare function createActionsProxy(actions: any, cb: any): any;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createActionsProxy = exports.getActionPaths = exports.getChangeMutations = exports.getFunctionName = exports.processState = exports.isPromise = exports.json = exports.MockedEventEmitter = exports.MODE_SSR = exports.MODE_TEST = exports.MODE_DEFAULT = exports.EXECUTION = exports.ORIGINAL_ACTIONS = exports.IS_OPERATOR = exports.IS_TEST = exports.ENVIRONMENT = exports.deepCopy = void 0;
exports.createActionsProxy = exports.getActionPaths = exports.getActionsByName = exports.getChangeMutations = exports.getFunctionName = exports.processState = exports.isPromise = exports.json = exports.MockedEventEmitter = exports.MODE_SSR = exports.MODE_TEST = exports.MODE_DEFAULT = exports.EXECUTION = exports.ORIGINAL_ACTIONS = exports.IS_OPERATOR = exports.IS_TEST = exports.ENVIRONMENT = exports.createOnInitialize = exports.deepCopy = void 0;
const tslib_1 = require("tslib");

@@ -11,2 +11,9 @@ const is_plain_obj_1 = tslib_1.__importDefault(require("is-plain-obj"));

Object.defineProperty(exports, "deepCopy", { enumerable: true, get: function () { return statemachine_2.deepCopy; } });
const createOnInitialize = () => {
return ({ actions }, instance) => {
const initializers = getActionsByName('onInitializeOvermind', actions);
return Promise.all(initializers.map((initialize) => initialize(instance)));
};
};
exports.createOnInitialize = createOnInitialize;
exports.ENVIRONMENT = (() => {

@@ -38,5 +45,6 @@ let env;

exports.MockedEventEmitter = MockedEventEmitter;
exports.json = (obj) => {
const json = (obj) => {
return statemachine_1.deepCopy(obj && obj[proxy_state_tree_1.IS_PROXY] ? obj[proxy_state_tree_1.VALUE] : obj);
};
exports.json = json;
function isPromise(maybePromise) {

@@ -106,2 +114,11 @@ return (maybePromise instanceof Promise ||

exports.getChangeMutations = getChangeMutations;
function getActionsByName(name, actions = {}, currentPath = []) {
return Object.keys(actions).reduce((aggr, key) => {
if (typeof actions[key] === 'function' && key === name) {
return aggr.concat(actions[key]);
}
return aggr.concat(getActionsByName(name, actions[key], currentPath.concat(key)));
}, []);
}
exports.getActionsByName = getActionsByName;
function getActionPaths(actions = {}, currentPath = []) {

@@ -108,0 +125,0 @@ return Object.keys(actions).reduce((aggr, key) => {

@@ -9,3 +9,5 @@ "use strict";

value: 0,
get valuePlusTwo() { return this.value + 2; }
get valuePlusTwo() {
return this.value + 2;
},
};

@@ -20,3 +22,3 @@ const copy = utils_1.deepCopy(original);

const stateA = {
foo: 'bar'
foo: 'bar',
};

@@ -34,5 +36,5 @@ const stateB = {

bar: {
baz: 'mip'
}
}
baz: 'mip',
},
},
};

@@ -42,5 +44,5 @@ const stateB = {

bar: {
baz: 'mip2'
}
}
baz: 'mip2',
},
},
};

@@ -56,10 +58,10 @@ const mutations = utils_1.getChangeMutations(stateA, stateB);

bar: {
baz: 'mip'
}
}
baz: 'mip',
},
},
};
const stateB = {
foo: {
bar: {}
}
bar: {},
},
};

@@ -66,0 +68,0 @@ const mutations = utils_1.getChangeMutations(stateA, stateB);

{
"name": "overmind",
"version": "27.0.0-1611398336423",
"version": "27.0.0-1624124645626",
"description": "Frictionless state management",

@@ -38,6 +38,5 @@ "author": "Christian Alfoni <christianalfoni@gmail.com>",

"is-plain-obj": "^1.1.0",
"betsy": "1.0.2-1611398336423",
"non-blocking-json": "1.1.1-1611398336423",
"tslib": "^1.10.0",
"proxy-state-tree": "6.2.0-1611398336423"
"betsy": "1.0.2-1624124645626",
"tslib": "^2.3.0",
"proxy-state-tree": "6.2.0-1624124645626"
},

@@ -44,0 +43,0 @@ "devDependencies": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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