Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pullstate

Package Overview
Dependencies
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pullstate - npm Package Compare versions

Comparing version 0.7.1 to 0.8.0-alpha.0

24

Changelog.md

@@ -1,3 +0,23 @@

### 0.7.0
## 0.8.0
Some refactoring of the Async Actions and adding of hooks for much finer grained control:
`shortCicuitHook()`: Run checks to resolve the action with a response before it even sets out.
`breakCacheHook()`: When an action's state is being returned from the cache, this hook allows you to run checks on the current cache and your stores to decide whether this action should be run again (essentially flushing / breaking the cache).
`postActionHook()`: This hook allows you to run some things after the action has resolved, and most importantly allows code to run after each time we hit the cached result of this action as well. This is very useful for interface changes which need to change / update outside of the action code.
`postActionHook()` is run with a context variable which tells you in which context it was run, one of: CACHE, SHORT_CIRCUIT, DIRECT_RUN
These hooks should hopefully allow even more boilerplate code to be eliminated while working in asynchronous state scenarios.
## 0.7.1
* Made the `isResolved()` function safe from causing infinite loops (Async Action resolves, but the state of the store still makes `isResolved()` return false which causes a re-trigger when re-rendering - most likely happens when not checking for error states in `isResolved()`) - instead posting an error message to the console informing about the loop which needs to be fixed.
## 0.7.0
**:warning: Replaced with async action hooks above in 0.8.0**
Added the options of setting an `isResolve()` synchronous checking function on Async Actions. This allows for early escape hatching (we don't need to run this async action based on the current state) and cache busting (even though we ran this Async Action before and we have a cached result, the current state indicates we need to run it again).

@@ -38,3 +58,3 @@

### 0.6.0
## 0.6.0

@@ -41,0 +61,0 @@ * Added "reactions" to store state. Usable like so:

import { IPullstateAllStores } from "./PullstateCore";
declare type TPullstateAsyncUpdateListener = () => void;
export declare type TPullstateAsyncWatchResponse<R, T extends string> = [boolean, boolean, TAsyncActionResult<R, T>, boolean];
export declare type TPullstateAsyncResponseCacheFull<R, T extends string> = [boolean, boolean, TAsyncActionResult<R, T>, boolean, TAsyncActionResult<R, T> | true | null];
export declare type TPullstateAsyncBeckonResponse<R, T extends string> = [boolean, TAsyncActionResult<R, T>, boolean];

@@ -31,3 +32,10 @@ export declare type TPullstateAsyncRunResponse<R, T extends string> = Promise<TAsyncActionResult<R, T>>;

export declare type TPullstateAsyncAction<A, R, T extends string, S extends IPullstateAllStores> = (args: A, stores: S) => Promise<TAsyncActionResult<R, T>>;
export declare type TPullstateAsyncIsResolvedFunction<A, R, T extends string, S extends IPullstateAllStores> = (args: A, stores: S) => TAsyncActionResult<R, T> | false;
export declare type TPullstateAsyncShortCircuitHook<A, R, T extends string, S extends IPullstateAllStores> = (args: A, stores: S) => TAsyncActionResult<R, T> | false;
export declare type TPullstateAsyncCacheBreakHook<A, R, T extends string, S extends IPullstateAllStores> = (args: A, result: TAsyncActionResult<R, T>, stores: S) => boolean;
export declare enum EPostActionContext {
CACHE = "CACHE",
SHORT_CIRCUIT = "SHORT_CIRCUIT",
DIRECT_RUN = "DIRECT_RUN"
}
export declare type TPullstateAsyncPostActionHook<A, R, T extends string, S extends IPullstateAllStores> = (args: A, result: TAsyncActionResult<R, T>, stores: S, context: EPostActionContext) => TAsyncActionResult<R, T> | void;
export interface IAsyncActionBeckonOptions {

@@ -41,2 +49,3 @@ ssr?: boolean;

treatAsUpdate?: boolean;
ignoreShortCircuit?: boolean;
}

@@ -71,3 +80,9 @@ declare type TAsyncActionBeckon<A, R, T extends string> = (args?: A, options?: IAsyncActionBeckonOptions) => TPullstateAsyncBeckonResponse<R, T>;

export declare function errorResult<R = any, T extends string = string>(tags?: (EAsyncEndTags | T)[], message?: string): IAsyncActionResultNegative<T>;
export declare function createAsyncAction<A = any, R = any, T extends string = string, S extends IPullstateAllStores = IPullstateAllStores>(action: TPullstateAsyncAction<A, R, T, S>, isResolved?: TPullstateAsyncIsResolvedFunction<A, R, T, S>, clientStores?: S): IOCreateAsyncActionOutput<A, R, T>;
export interface ICreateAsyncActionOptions<A, R, T extends string, S extends IPullstateAllStores> {
clientStores?: S;
shortCircuitHook?: TPullstateAsyncShortCircuitHook<A, R, T, S>;
cacheBreakHook?: TPullstateAsyncCacheBreakHook<A, R, T, S>;
postActionHook?: TPullstateAsyncPostActionHook<A, R, T, S>;
}
export declare function createAsyncAction<A = any, R = any, T extends string = string, S extends IPullstateAllStores = IPullstateAllStores>(action: TPullstateAsyncAction<A, R, T, S>, { clientStores, shortCircuitHook, cacheBreakHook, postActionHook, }?: ICreateAsyncActionOptions<A, R, T, S>): IOCreateAsyncActionOutput<A, R, T>;
export {};

120

dist/index.es.js

@@ -129,2 +129,8 @@ import React,{useState,useRef,useCallback,useEffect,useContext,useMemo}from'react';const shallowEqual = require("fbjs/lib/shallowEqual");

})(EAsyncEndTags || (EAsyncEndTags = {}));
var EPostActionContext;
(function (EPostActionContext) {
EPostActionContext["CACHE"] = "CACHE";
EPostActionContext["SHORT_CIRCUIT"] = "SHORT_CIRCUIT";
EPostActionContext["DIRECT_RUN"] = "DIRECT_RUN";
})(EPostActionContext || (EPostActionContext = {}));
const clientAsyncCache = {

@@ -201,48 +207,62 @@ listeners: {},

}
function createAsyncAction(action, isResolved, clientStores = {}) {
function createAsyncAction(action, { clientStores = {}, shortCircuitHook, cacheBreakHook, postActionHook, } = {}) {
const ordinal = asyncCreationOrdinal++;
const onServer = typeof window === "undefined";
let isResolvedWatcher = {};
console.log(`Pullstate Core creating action with options`);
console.log({ shortCircuitHook, cacheBreakHook, postActionHook, clientStores });
let cacheBreakWatcher = {};
let watchIdOrd = 0;
const shouldUpdate = {};
function runPostActionHook(result, args, stores, context) {
if (postActionHook !== undefined) {
const potentialResponse = postActionHook(args, result, stores, context);
return potentialResponse != null ? potentialResponse : result;
}
return result;
}
function checkKeyAndReturnResponse(key, cache, initiate, ssr, args, stores) {
let checkedResolved = false;
const isResolvedUndefined = isResolved === undefined;
if (cache.results.hasOwnProperty(key)) {
if (isResolvedUndefined || isResolved(args, stores) !== false) {
if (!isResolvedUndefined) {
isResolvedWatcher[key] = 0;
const cacheBreakLoop = (cacheBreakWatcher.hasOwnProperty(key) && cacheBreakWatcher[key] > 2);
if (cacheBreakHook !== undefined &&
cacheBreakHook(args, cache.results[key][2], stores) &&
!cacheBreakLoop) {
if (cacheBreakWatcher.hasOwnProperty(key)) {
cacheBreakWatcher[key]++;
}
return cache.results[key];
else {
cacheBreakWatcher[key] = 1;
}
delete cache.results[key];
}
else {
delete cache.results[key];
checkedResolved = true;
if (cacheBreakLoop) {
console.error(`[${key}] Pullstate detected an infinite loop caused by cacheBreakHook()
returning true too often (breaking cache as soon as your action is resolving - hence
causing beckoned actions to run the action again) in one of your AsyncActions - prevented
further looping. Fix in your cacheBreakHook() is needed.`);
}
else {
cacheBreakWatcher[key] = 0;
}
return [
true,
true,
runPostActionHook(cache.results[key][2], args, stores, EPostActionContext.CACHE),
false,
];
}
}
if (!cache.actions.hasOwnProperty(key)) {
if (!checkedResolved && !isResolvedUndefined) {
const resolvedResponse = isResolved(args, stores);
if (resolvedResponse !== false) {
cache.results[key] = [true, true, resolvedResponse, false];
return cache.results[key];
if (shortCircuitHook !== undefined) {
const shortCircuitResponse = shortCircuitHook(args, stores);
if (shortCircuitResponse !== false) {
cache.results[key] = [true, true, shortCircuitResponse, false];
return [
true,
true,
runPostActionHook(shortCircuitResponse, args, stores, EPostActionContext.SHORT_CIRCUIT),
false,
];
}
}
if (!isResolvedUndefined) {
isResolvedWatcher[key] = isResolvedWatcher[key] !== undefined ? isResolvedWatcher[key] + 1 : 1;
}
if (!isResolvedUndefined && isResolvedWatcher[key] !== undefined && isResolvedWatcher[key] > 2) {
console.error(`Pullstate [${key}]: an Async Action with isResolved() set may be causing an infinite loop. Not initiating the next run of this action. Check your method to make sure, or file an issue if this is not the case.`);
return [
false,
false,
{
message: "",
tags: [EAsyncEndTags.UNFINISHED],
error: false,
payload: null,
},
false,
];
}
if (initiate) {

@@ -283,3 +303,3 @@ if (ssr || !onServer) {

tags: [EAsyncEndTags.UNFINISHED],
error: false,
error: true,
payload: null,

@@ -297,3 +317,3 @@ },

tags: [EAsyncEndTags.UNFINISHED],
error: false,
error: true,
payload: null,

@@ -359,3 +379,3 @@ },

};
const run = async (args = {}, { treatAsUpdate = false } = {}) => {
const run = async (args = {}, { treatAsUpdate = false, ignoreShortCircuit = false } = {}) => {
const key = createKey(ordinal, args);

@@ -366,3 +386,3 @@ const [, prevFinished, prevResp] = clientAsyncCache.results[key] || [

{
error: false,
error: true,
message: "",

@@ -379,2 +399,12 @@ payload: null,

}
console.log(`Running async function`);
console.log({ shortCircuitHook });
if (shortCircuitHook !== undefined) {
const shortCircuitResponse = shortCircuitHook(args, clientStores);
if (shortCircuitResponse !== false) {
clientAsyncCache.results[key] = [true, true, shortCircuitResponse, false];
notifyListeners(key);
return runPostActionHook(shortCircuitResponse, args, clientStores, EPostActionContext.DIRECT_RUN);
}
}
notifyListeners(key);

@@ -388,3 +418,3 @@ let currentActionOrd = actionOrdUpdate(clientAsyncCache, key);

}
return result;
return runPostActionHook(result, args, clientStores, EPostActionContext.DIRECT_RUN);
}

@@ -402,3 +432,3 @@ catch (e) {

}
return result;
return runPostActionHook(result, args, clientStores, EPostActionContext.DIRECT_RUN);
}

@@ -459,3 +489,6 @@ };

}
newStores[storeName]._setInternalOptions({ ssr, reactionCreators: this.originStores[storeName]._getReactionCreators() });
newStores[storeName]._setInternalOptions({
ssr,
reactionCreators: this.originStores[storeName]._getReactionCreators(),
});
}

@@ -467,4 +500,9 @@ return new PullstateInstance(newStores);

}
createAsyncAction(action, isResolved) {
return createAsyncAction(action, isResolved, this.originStores);
createAsyncAction(action, options = {}) {
return createAsyncAction(action, {
clientStores: this.originStores,
shortCircuitHook: options.shortCircuitHook,
cacheBreakHook: options.cacheBreakHook,
postActionHook: options.postActionHook,
});
}

@@ -471,0 +509,0 @@ }

@@ -128,2 +128,8 @@ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});function _interopDefault(e){return(e&&(typeof e==='object')&&'default'in e)?e['default']:e}var React=require('react'),React__default=_interopDefault(React);const shallowEqual = require("fbjs/lib/shallowEqual");

})(exports.EAsyncEndTags || (exports.EAsyncEndTags = {}));
var EPostActionContext;
(function (EPostActionContext) {
EPostActionContext["CACHE"] = "CACHE";
EPostActionContext["SHORT_CIRCUIT"] = "SHORT_CIRCUIT";
EPostActionContext["DIRECT_RUN"] = "DIRECT_RUN";
})(EPostActionContext || (EPostActionContext = {}));
const clientAsyncCache = {

@@ -200,48 +206,62 @@ listeners: {},

}
function createAsyncAction(action, isResolved, clientStores = {}) {
function createAsyncAction(action, { clientStores = {}, shortCircuitHook, cacheBreakHook, postActionHook, } = {}) {
const ordinal = asyncCreationOrdinal++;
const onServer = typeof window === "undefined";
let isResolvedWatcher = {};
console.log(`Pullstate Core creating action with options`);
console.log({ shortCircuitHook, cacheBreakHook, postActionHook, clientStores });
let cacheBreakWatcher = {};
let watchIdOrd = 0;
const shouldUpdate = {};
function runPostActionHook(result, args, stores, context) {
if (postActionHook !== undefined) {
const potentialResponse = postActionHook(args, result, stores, context);
return potentialResponse != null ? potentialResponse : result;
}
return result;
}
function checkKeyAndReturnResponse(key, cache, initiate, ssr, args, stores) {
let checkedResolved = false;
const isResolvedUndefined = isResolved === undefined;
if (cache.results.hasOwnProperty(key)) {
if (isResolvedUndefined || isResolved(args, stores) !== false) {
if (!isResolvedUndefined) {
isResolvedWatcher[key] = 0;
const cacheBreakLoop = (cacheBreakWatcher.hasOwnProperty(key) && cacheBreakWatcher[key] > 2);
if (cacheBreakHook !== undefined &&
cacheBreakHook(args, cache.results[key][2], stores) &&
!cacheBreakLoop) {
if (cacheBreakWatcher.hasOwnProperty(key)) {
cacheBreakWatcher[key]++;
}
return cache.results[key];
else {
cacheBreakWatcher[key] = 1;
}
delete cache.results[key];
}
else {
delete cache.results[key];
checkedResolved = true;
if (cacheBreakLoop) {
console.error(`[${key}] Pullstate detected an infinite loop caused by cacheBreakHook()
returning true too often (breaking cache as soon as your action is resolving - hence
causing beckoned actions to run the action again) in one of your AsyncActions - prevented
further looping. Fix in your cacheBreakHook() is needed.`);
}
else {
cacheBreakWatcher[key] = 0;
}
return [
true,
true,
runPostActionHook(cache.results[key][2], args, stores, EPostActionContext.CACHE),
false,
];
}
}
if (!cache.actions.hasOwnProperty(key)) {
if (!checkedResolved && !isResolvedUndefined) {
const resolvedResponse = isResolved(args, stores);
if (resolvedResponse !== false) {
cache.results[key] = [true, true, resolvedResponse, false];
return cache.results[key];
if (shortCircuitHook !== undefined) {
const shortCircuitResponse = shortCircuitHook(args, stores);
if (shortCircuitResponse !== false) {
cache.results[key] = [true, true, shortCircuitResponse, false];
return [
true,
true,
runPostActionHook(shortCircuitResponse, args, stores, EPostActionContext.SHORT_CIRCUIT),
false,
];
}
}
if (!isResolvedUndefined) {
isResolvedWatcher[key] = isResolvedWatcher[key] !== undefined ? isResolvedWatcher[key] + 1 : 1;
}
if (!isResolvedUndefined && isResolvedWatcher[key] !== undefined && isResolvedWatcher[key] > 2) {
console.error(`Pullstate [${key}]: an Async Action with isResolved() set may be causing an infinite loop. Not initiating the next run of this action. Check your method to make sure, or file an issue if this is not the case.`);
return [
false,
false,
{
message: "",
tags: [exports.EAsyncEndTags.UNFINISHED],
error: false,
payload: null,
},
false,
];
}
if (initiate) {

@@ -282,3 +302,3 @@ if (ssr || !onServer) {

tags: [exports.EAsyncEndTags.UNFINISHED],
error: false,
error: true,
payload: null,

@@ -296,3 +316,3 @@ },

tags: [exports.EAsyncEndTags.UNFINISHED],
error: false,
error: true,
payload: null,

@@ -358,3 +378,3 @@ },

};
const run = async (args = {}, { treatAsUpdate = false } = {}) => {
const run = async (args = {}, { treatAsUpdate = false, ignoreShortCircuit = false } = {}) => {
const key = createKey(ordinal, args);

@@ -365,3 +385,3 @@ const [, prevFinished, prevResp] = clientAsyncCache.results[key] || [

{
error: false,
error: true,
message: "",

@@ -378,2 +398,12 @@ payload: null,

}
console.log(`Running async function`);
console.log({ shortCircuitHook });
if (shortCircuitHook !== undefined) {
const shortCircuitResponse = shortCircuitHook(args, clientStores);
if (shortCircuitResponse !== false) {
clientAsyncCache.results[key] = [true, true, shortCircuitResponse, false];
notifyListeners(key);
return runPostActionHook(shortCircuitResponse, args, clientStores, EPostActionContext.DIRECT_RUN);
}
}
notifyListeners(key);

@@ -387,3 +417,3 @@ let currentActionOrd = actionOrdUpdate(clientAsyncCache, key);

}
return result;
return runPostActionHook(result, args, clientStores, EPostActionContext.DIRECT_RUN);
}

@@ -401,3 +431,3 @@ catch (e) {

}
return result;
return runPostActionHook(result, args, clientStores, EPostActionContext.DIRECT_RUN);
}

@@ -458,3 +488,6 @@ };

}
newStores[storeName]._setInternalOptions({ ssr, reactionCreators: this.originStores[storeName]._getReactionCreators() });
newStores[storeName]._setInternalOptions({
ssr,
reactionCreators: this.originStores[storeName]._getReactionCreators(),
});
}

@@ -466,4 +499,9 @@ return new PullstateInstance(newStores);

}
createAsyncAction(action, isResolved) {
return createAsyncAction(action, isResolved, this.originStores);
createAsyncAction(action, options = {}) {
return createAsyncAction(action, {
clientStores: this.originStores,
shortCircuitHook: options.shortCircuitHook,
cacheBreakHook: options.cacheBreakHook,
postActionHook: options.postActionHook,
});
}

@@ -470,0 +508,0 @@ }

import React from "react";
import { Store } from "./Store";
import { IOCreateAsyncActionOutput, IPullstateAsyncActionOrdState, IPullstateAsyncCache, IPullstateAsyncResultState, TPullstateAsyncAction, TPullstateAsyncIsResolvedFunction } from "./async";
import { ICreateAsyncActionOptions, IOCreateAsyncActionOutput, IPullstateAsyncActionOrdState, IPullstateAsyncCache, IPullstateAsyncResultState, TPullstateAsyncAction } from "./async";
declare type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export interface IPullstateAllStores {

@@ -21,3 +22,3 @@ [storeName: string]: Store<any>;

useStores(): S;
createAsyncAction<A = any, R = any, T extends string = string>(action: TPullstateAsyncAction<A, R, T, S>, isResolved?: TPullstateAsyncIsResolvedFunction<A, R, T, S>): IOCreateAsyncActionOutput<A, R, T>;
createAsyncAction<A = any, R = any, T extends string = string>(action: TPullstateAsyncAction<A, R, T, S>, options?: Omit<ICreateAsyncActionOptions<A, R, T, S>, "clientStores">): IOCreateAsyncActionOutput<A, R, T>;
}

@@ -24,0 +25,0 @@ interface IPullstateSnapshot {

{
"name": "pullstate",
"version": "0.7.1",
"version": "0.8.0-alpha.0",
"description": "Simple state stores using immer and React hooks",

@@ -51,4 +51,2 @@ "main": "dist/index.js",

"prettier": "^1.16.4",
"react": "^16.8.4",
"react-dom": "^16.8.4",
"react-test-renderer": "^16.8.3",

@@ -55,0 +53,0 @@ "rollup": "^1.2.2",

@@ -0,1 +1,5 @@

<p align="center">
<img width="736" height="373" src="https://github.com/lostpebble/pullstate/raw/master/graphics/pullstate-logo.png" alt="Pullstate" />
</p>
### pullstate

@@ -2,0 +6,0 @@

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