varstor 0.6.63 → 0.6.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/varstor.js CHANGED
@@ -25,16 +25,11 @@ __webpack_require__.r(__webpack_exports__);
25
25
  /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! . */ "./src/index.ts");
26
26
 
27
27
  function addStateActions(namespace, actions) {
28
- const stateAcessor = {
29
- get: ___WEBPACK_IMPORTED_MODULE_0__.getState.bind(null, namespace),
30
- set: ___WEBPACK_IMPORTED_MODULE_0__.setState.bind(null, namespace),
31
- reset: ___WEBPACK_IMPORTED_MODULE_0__.resetState.bind(null, namespace),
32
- };
33
- for (let [actionName, actionFn] of Object.entries(actions)) {
28
+ for (const [actionName, actionFn] of Object.entries(actions)) {
34
29
  ___WEBPACK_IMPORTED_MODULE_0__.STATE[namespace(actionName)] = {
35
30
  key: actionName,
36
31
  namespace,
37
- value: actionFn.bind(null, stateAcessor),
32
+ value: actionFn.bind(null, (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace())),
38
33
  isAction: true,
39
34
  listeners: [],
40
35
  };
@@ -71,11 +66,13 @@ __webpack_require__.r(__webpack_exports__);
71
66
  /* harmony export */ forEach: () => (/* binding */ forEach),
72
67
  /* harmony export */ getParamNames: () => (/* binding */ getParamNames),
73
68
  /* harmony export */ isArray: () => (/* binding */ isArray),
69
+ /* harmony export */ isAsyncFunction: () => (/* binding */ isAsyncFunction),
74
70
  /* harmony export */ isFunction: () => (/* binding */ isFunction),
75
71
  /* harmony export */ isObject: () => (/* binding */ isObject),
76
72
  /* harmony export */ isString: () => (/* binding */ isString),
77
73
  /* harmony export */ map: () => (/* binding */ map),
78
- /* harmony export */ recreateStructure: () => (/* binding */ recreateStructure)
74
+ /* harmony export */ recreateStructure: () => (/* binding */ recreateStructure),
75
+ /* harmony export */ uid: () => (/* binding */ uid)
79
76
  /* harmony export */ });
80
77
  const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
81
78
  const ARGUMENT_NAMES = /([^\s,]+)/g;
@@ -88,6 +85,9 @@ function isString(obj) {
88
85
  function isFunction(obj) {
89
86
  return getObjectType(obj) === "[object Function]";
90
87
  }
88
+ function isAsyncFunction(obj) {
89
+ return getObjectType(obj) === "[object AsyncFunction]";
90
+ }
91
91
  function isObject(obj) {
92
92
  return getObjectType(obj) === "[object Object]";
93
93
  }
@@ -133,6 +133,9 @@ function recreateStructure(value) {
133
133
  }
134
134
  return newValue;
135
135
  }
136
+ function uid() {
137
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
138
+ }
136
139
 
137
140
 
138
141
  /***/ },
@@ -146,10 +149,12 @@ function recreateStructure(value) {
146
149
  __webpack_require__.r(__webpack_exports__);
147
150
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
148
151
  /* harmony export */ STATE: () => (/* binding */ STATE),
152
+ /* harmony export */ createPendingChanges: () => (/* binding */ createPendingChanges),
149
153
  /* harmony export */ createStore: () => (/* binding */ createStore),
150
154
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
151
155
  /* harmony export */ getState: () => (/* binding */ getState),
152
156
  /* harmony export */ getValues: () => (/* binding */ getValues),
157
+ /* harmony export */ joinStateChanges: () => (/* binding */ joinStateChanges),
153
158
  /* harmony export */ resetState: () => (/* binding */ resetState),
154
159
  /* harmony export */ setState: () => (/* binding */ setState),
155
160
  /* harmony export */ setupValue: () => (/* binding */ setupValue)
@@ -158,15 +163,15 @@ __webpack_require__.r(__webpack_exports__);
158
163
  /* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ "./src/helpers.ts");
159
164
  /* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./actions */ "./src/actions.ts");
160
165
  /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
161
- /* harmony import */ var _validation__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./validation */ "./src/validation.ts");
162
- /* harmony import */ var _listeners__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./listeners */ "./src/listeners.ts");
163
-
166
+ /* harmony import */ var _listeners__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./listeners */ "./src/listeners.ts");
164
167
 
165
168
 
166
169
 
167
170
 
168
171
 
169
172
  const STATE = {};
173
+ const STATE_CHANGED_PIECES = {};
174
+ const STATE_PENDING_CHANGES = {};
170
175
  const STORAGE = {};
171
176
  setStorageUtils(_storage__WEBPACK_IMPORTED_MODULE_0__["default"]);
172
177
  async function addState(namespace, initialState, isPersistent) {
@@ -176,12 +181,8 @@ async function addState(namespace, initialState, isPersistent) {
176
181
  if (STORAGE.IS_AVAILABE(storageType)) {
177
182
  await STORAGE.UPDATE_STATE(values, storageType);
178
183
  }
179
- if (!_listeners__WEBPACK_IMPORTED_MODULE_5__.LISTENERS[namespace()]) {
180
- _listeners__WEBPACK_IMPORTED_MODULE_5__.LISTENERS[namespace()] = [];
181
- }
182
184
  for (const key in initialState) {
183
185
  const fullKey = namespace(key);
184
- _validation__WEBPACK_IMPORTED_MODULE_4__.isValid.Defining(fullKey);
185
186
  STATE[fullKey] = setupValue(key, namespace, values[fullKey], defaultValues[key], storageType);
186
187
  }
187
188
  return createStore(namespace());
@@ -232,6 +233,26 @@ function getArguments(dependencies, namespace) {
232
233
  const values = getValues(namespace);
233
234
  return dependencies.map((name) => values[name]);
234
235
  }
236
+ async function joinStateChanges(changesPiece) {
237
+ for (const [updateId, { storageTypes, readyStorageTypes, changes },] of Object.entries(STATE_CHANGED_PIECES)) {
238
+ if (changesPiece[updateId]) {
239
+ const storageType = changesPiece[updateId].newValue;
240
+ readyStorageTypes[storageType] = true;
241
+ delete changesPiece[updateId];
242
+ Object.assign(changes, changesPiece);
243
+ if (STORAGE.IS_AVAILABE(storageType)) {
244
+ STORAGE.REMOVE_KEY(storageType, updateId);
245
+ }
246
+ for (const key in storageTypes) {
247
+ if (!readyStorageTypes[key]) {
248
+ return;
249
+ }
250
+ }
251
+ delete STATE_CHANGED_PIECES[updateId];
252
+ await onStateChange(changes);
253
+ }
254
+ }
255
+ }
235
256
  async function onStateChange(changes) {
236
257
  const realChanges = {};
237
258
  for (const key in changes) {
@@ -246,7 +267,7 @@ async function onStateChange(changes) {
246
267
  }
247
268
  updateDependencies(key, changes, realChanges);
248
269
  }
249
- await (0,_listeners__WEBPACK_IMPORTED_MODULE_5__.runStateChangeListeners)((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.filter)(realChanges, (k, v) => !v.isSame));
270
+ await (0,_listeners__WEBPACK_IMPORTED_MODULE_4__.runStateChangeListeners)((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.filter)(realChanges, (k, v) => !v.isSame));
250
271
  }
251
272
  function updateDependencies(key, changes, realChanges) {
252
273
  STATE[key].dependants?.forEach((name) => {
@@ -279,6 +300,8 @@ function getState(namespace, arg) {
279
300
  }
280
301
  async function setState(namespace, changes) {
281
302
  const storageChanges = {};
303
+ const updateId = (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.uid)();
304
+ const storageTypes = {};
282
305
  (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.forEach)(changes, (k, v) => {
283
306
  const fullKey = namespace(k);
284
307
  const { storageType, computeFn, isAction } = STATE[fullKey];
@@ -288,10 +311,16 @@ async function setState(namespace, changes) {
288
311
  if (!storageChanges[storageType]) {
289
312
  storageChanges[storageType] = {};
290
313
  }
314
+ storageTypes[storageType] = true;
291
315
  storageChanges[storageType][fullKey] = v;
292
316
  });
317
+ STATE_CHANGED_PIECES[updateId] = {
318
+ storageTypes,
319
+ readyStorageTypes: {},
320
+ changes: {},
321
+ };
293
322
  for (let [storageType, changes] of Object.entries(storageChanges)) {
294
- await setValues(storageType, changes);
323
+ await setValues(storageType, { ...changes, [updateId]: storageType });
295
324
  }
296
325
  return createStore(namespace());
297
326
  }
@@ -302,21 +331,38 @@ async function setValues(storageType, changes) {
302
331
  return;
303
332
  }
304
333
  }
305
- onStateChange((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(changes, (k, newValue) => [k, { newValue }]));
334
+ joinStateChanges((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(changes, (k, newValue) => [k, { newValue }]));
306
335
  }
307
336
  async function resetState(namespace, keys) {
337
+ await setState(namespace, getDefaultValues(namespace, keys));
338
+ return createStore(namespace());
339
+ }
340
+ function getDefaultValues(namespace, keys) {
308
341
  const namespaceState = getNamespaceState(namespace);
309
- await setState(namespace, (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(keys
342
+ return (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.map)(keys
310
343
  ? (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.filter)(namespaceState, (k, { key }) => keys.includes(key))
311
- : namespaceState, (k, { key, defaultValue }) => [key, defaultValue]));
312
- return createStore(namespace());
344
+ : namespaceState, (k, { key, defaultValue }) => [key, defaultValue]);
345
+ }
346
+ function createPendingChanges(namespace) {
347
+ const flush = () => {
348
+ const changes = STATE_PENDING_CHANGES[namespace()];
349
+ STATE_PENDING_CHANGES[namespace()] = {};
350
+ return changes;
351
+ };
352
+ return {
353
+ add: (changes) => Object.assign(STATE_PENDING_CHANGES[namespace()], changes),
354
+ reset: (keys) => Object.assign(STATE_PENDING_CHANGES[namespace()], getDefaultValues(namespace, keys)),
355
+ get: () => STATE_PENDING_CHANGES[namespace()],
356
+ flush,
357
+ commit: () => setState(namespace, flush()),
358
+ };
313
359
  }
314
360
  function main(namespace) {
315
361
  if (!arguments[1] || (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isString)(arguments[1])) {
316
362
  return getState.apply(null, arguments);
317
363
  }
318
- if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isArray)(arguments[1])) {
319
- return _listeners__WEBPACK_IMPORTED_MODULE_5__.addStateListener.apply(null, arguments);
364
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isArray)(arguments[1]) || (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isFunction)(arguments[1]) || (0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isAsyncFunction)(arguments[1])) {
365
+ return _listeners__WEBPACK_IMPORTED_MODULE_4__.addStateListener.apply(null, arguments);
320
366
  }
321
367
  if ((0,_helpers__WEBPACK_IMPORTED_MODULE_1__.isObject)(arguments[1])) {
322
368
  return setState.apply(null, arguments);
@@ -330,17 +376,25 @@ function addNamespace(namespace, str) {
330
376
  }
331
377
  function createStore(_namespace) {
332
378
  const namespace = ((key) => addNamespace(_namespace, key));
379
+ if (!STATE_PENDING_CHANGES[namespace()]) {
380
+ STATE_PENDING_CHANGES[namespace()] = {};
381
+ }
382
+ if (!_listeners__WEBPACK_IMPORTED_MODULE_4__.LISTENERS[namespace()]) {
383
+ _listeners__WEBPACK_IMPORTED_MODULE_4__.LISTENERS[namespace()] = [];
384
+ }
333
385
  return Object.assign(main.bind(null, namespace), {
334
386
  add: (state) => addState(namespace, state, false),
335
387
  addPersistent: (state) => addState(namespace, state, true),
336
388
  get: (newNamespace) => getState(namespace, newNamespace),
337
389
  set: async (changes) => await setState(namespace, changes),
338
390
  reset: (keys) => resetState(namespace, keys),
339
- onChange: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_5__.addStateListener)(namespace, keys, cb),
340
- removeListener: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_5__.removeStateListener)(namespace, keys, cb),
391
+ changes: createPendingChanges(namespace),
392
+ onChange: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_4__.addStateListener)(namespace, keys, cb),
393
+ removeListener: (keys, cb) => (0,_listeners__WEBPACK_IMPORTED_MODULE_4__.removeStateListener)(namespace, keys, cb),
341
394
  actions: (actions) => (0,_actions__WEBPACK_IMPORTED_MODULE_2__.addStateActions)(namespace, actions),
342
395
  setStorageUtils,
343
- onStateChange,
396
+ joinStateChanges,
397
+ namespace,
344
398
  });
345
399
  }
346
400
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (createStore(""));
@@ -371,24 +425,33 @@ const LISTENERS = {};
371
425
  async function runStateChangeListeners(realChanges) {
372
426
  if (Object.keys(realChanges).length) {
373
427
  const { namespace } = ___WEBPACK_IMPORTED_MODULE_0__.STATE[Object.keys(realChanges)[0]];
374
- const stateValues = (0,___WEBPACK_IMPORTED_MODULE_0__.getValues)(namespace);
375
- for (let [changeKey, change] of Object.entries(realChanges)) {
428
+ for (const [changeKey] of Object.entries(realChanges)) {
376
429
  const { listeners, key } = ___WEBPACK_IMPORTED_MODULE_0__.STATE[changeKey];
377
430
  for (const cb of listeners) {
378
- await cb([key], stateValues, change);
431
+ const fn = cb.bind(null, [key], (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace()));
432
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(cb)) {
433
+ await fn();
434
+ }
435
+ else {
436
+ fn();
437
+ }
379
438
  }
380
439
  }
381
- const readableKeys = (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k) => k.slice(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER.length));
440
+ const namespaceLength = `${namespace()}${_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER}`.length;
441
+ const readableKeys = (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k) => k.slice(namespaceLength));
382
442
  for (const cb of LISTENERS[namespace()]) {
383
- await cb(readableKeys, stateValues, (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.map)(realChanges, (k, v) => [
384
- k.slice(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER.length),
385
- v,
386
- ]));
443
+ const fn = cb.bind(null, readableKeys, (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace()));
444
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(cb)) {
445
+ await fn();
446
+ }
447
+ else {
448
+ fn();
449
+ }
387
450
  }
388
451
  }
389
452
  }
390
453
  function addStateListener(namespace, observables, cb) {
391
- if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables)) {
454
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables) || (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(observables)) {
392
455
  LISTENERS[namespace()].push(observables);
393
456
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
394
457
  }
@@ -396,7 +459,7 @@ function addStateListener(namespace, observables, cb) {
396
459
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
397
460
  }
398
461
  function removeStateListener(namespace, observables, removeCb) {
399
- if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables)) {
462
+ if ((0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isFunction)(observables) || (0,_helpers__WEBPACK_IMPORTED_MODULE_2__.isAsyncFunction)(observables)) {
400
463
  const removeIdx = LISTENERS[namespace()].findIndex((cb) => cb === observables);
401
464
  LISTENERS[namespace()].splice(removeIdx, 1);
402
465
  return (0,___WEBPACK_IMPORTED_MODULE_0__.createStore)(namespace());
@@ -444,52 +507,20 @@ async function setStorageValue(storageType, changes) {
444
507
  }
445
508
  return false;
446
509
  }
510
+ function removeStorageKey(type, key) {
511
+ if (type) {
512
+ localStorage.removeItem(key);
513
+ }
514
+ }
447
515
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
448
516
  GET_TYPE: getStorageType,
449
517
  IS_AVAILABE: isStorageAvailable,
450
518
  UPDATE_STATE: updateFromLocalStorage,
451
519
  SET_VALUES: setStorageValue,
520
+ REMOVE_KEY: removeStorageKey,
452
521
  });
453
522
 
454
523
 
455
- /***/ },
456
-
457
- /***/ "./src/validation.ts"
458
- /*!***************************!*\
459
- !*** ./src/validation.ts ***!
460
- \***************************/
461
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
462
-
463
- __webpack_require__.r(__webpack_exports__);
464
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
465
- /* harmony export */ isValid: () => (/* binding */ isValid)
466
- /* harmony export */ });
467
- /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! . */ "./src/index.ts");
468
- /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
469
-
470
-
471
- function splitFullKey(fullKey) {
472
- const segments = fullKey.split(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER);
473
- return [segments.slice(-1)[0], segments.join(_constants__WEBPACK_IMPORTED_MODULE_1__.NAMESPACE_DELIMITER)];
474
- }
475
- const isValid = {
476
- Setting: (fullKey) => {
477
- if (!___WEBPACK_IMPORTED_MODULE_0__.STATE[fullKey]) {
478
- const [key, namespace] = splitFullKey(fullKey);
479
- throw new Error(`Setting "${key}" key in "${namespace}" namespace. DOES NOT EXIST`);
480
- }
481
- return true;
482
- },
483
- Defining: (fullKey) => {
484
- if (___WEBPACK_IMPORTED_MODULE_0__.STATE[fullKey]) {
485
- const [key, namespace] = splitFullKey(fullKey);
486
- throw new Error(`Redefining "${key}" key in "${namespace}" namespace. ALREADY DEFINED`);
487
- }
488
- return true;
489
- },
490
- };
491
-
492
-
493
524
  /***/ }
494
525
 
495
526
  /******/ });
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see varstor.min.js.LICENSE.txt */
2
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Varstor=t():e.Varstor=t()}(this,()=>(()=>{"use strict";var e={"./src/actions.ts"(e,t,n){n.r(t),n.d(t,{addStateActions:()=>s});var r=n("./src/index.ts");function s(e,t){const n={get:r.getState.bind(null,e),set:r.setState.bind(null,e),reset:r.resetState.bind(null,e)};for(let[s,c]of Object.entries(t))r.STATE[e(s)]={key:s,namespace:e,value:c.bind(null,n),isAction:!0,listeners:[]}}},"./src/constants.ts"(e,t,n){n.r(t),n.d(t,{NAMESPACE_DELIMITER:()=>r});const r="::"},"./src/helpers.ts"(e,t,n){n.r(t),n.d(t,{filter:()=>p,forEach:()=>d,getParamNames:()=>l,isArray:()=>c,isFunction:()=>i,isObject:()=>a,isString:()=>o,map:()=>f,recreateStructure:()=>S});const r=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,s=/([^\s,]+)/g;function c(e){return"[object Array]"===u(e)}function o(e){return"[object String]"===u(e)}function i(e){return"[object Function]"===u(e)}function a(e){return"[object Object]"===u(e)}function u(e){return Object.prototype.toString.call(e)}function l(e){const t=e.toString().replace(r,"").split("=>")[0],n=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(s);return null===n?[]:n}function f(e,t){const n=Object.entries(e).map(([e,n])=>t(e,n));return 2===n[0]?.length?Object.fromEntries(n):n}function d(e,t){Object.entries(e||{}).forEach(([e,n])=>t(e,n))}function p(e,t){return Object.fromEntries(Object.entries(e||{}).filter(([e,n])=>!0===t(e,n)))}function S(e){let t=e;if(c(e))return t=[],e.forEach(e=>t.push(S(e))),t;if(a(e)){t={};for(let n in e)t[n]=S(e[n]);return t}return t}},"./src/index.ts"(e,t,n){n.r(t),n.d(t,{STATE:()=>u,createStore:()=>h,default:()=>v,getState:()=>A,getValues:()=>S,resetState:()=>m,setState:()=>T,setupValue:()=>d});var r=n("./src/storage.ts"),s=n("./src/helpers.ts"),c=n("./src/actions.ts"),o=n("./src/constants.ts"),i=n("./src/validation.ts"),a=n("./src/listeners.ts");const u={},l={};async function f(e,t,n){const r=l.GET_TYPE(n),c=Object.assign({},t),o=(0,s.map)(t,(t,n)=>[e(t),n]);l.IS_AVAILABE(r)&&await l.UPDATE_STATE(o,r),a.LISTENERS[e()]||(a.LISTENERS[e()]=[]);for(const n in t){const t=e(n);i.isValid.Defining(t),u[t]=d(n,e,o[t],c[n],r)}return h(e())}function d(e,t,n,r,c){const o=t(e),i=(0,s.isFunction)(n),a=i?(0,s.getParamNames)(n):[];return a.forEach(e=>{const n=t(e);u[n]||(u[n]={dependants:[],dependencies:[],namespace:t,storageType:c}),u[n].dependants?.push(o)}),{key:e,fullKey:o,value:i?n.apply(null,E(a,t)):n,computeFn:i&&n,dependencies:a,dependants:[],listeners:[],defaultValue:r,storageType:c,namespace:t}}function p(e){return(0,s.filter)(u,(t,{key:n})=>t===e(n))}function S(e){return(0,s.map)(p(e),(e,{key:t,value:n})=>[t,n])}function E(e,t){const n=S(t);return e.map(e=>n[e])}async function g(e){const t={};for(const n in e){const r=u[n].value,s=e[n].newValue;r!==s?(t[n]={newValue:s,prevValue:r},u[n].value=s):t[n]={isSame:!0},y(n,e,t)}await(0,a.runStateChangeListeners)((0,s.filter)(t,(e,t)=>!t.isSame))}function y(e,t,n){u[e].dependants?.forEach(e=>{const{dependencies:r,namespace:s}=u[e];if(!function(e,t,n,r){return e.every(e=>{const s=t(e);return n.includes(s)&&r.includes(s)||!n.includes(s)})}(r,s,Object.keys(t),Object.keys(n))||n[e])return;const c=u[e].value,o=u[e].computeFn?.apply(null,E(r,s));c!==o&&(n[e]={newValue:o,prevValue:c},u[e].value=o,y(e,t,n))})}function A(e,t){return(0,s.isString)(t)?h(t):(0,s.recreateStructure)(S(e))}async function T(e,t){const n={};(0,s.forEach)(t,(t,r)=>{const s=e(t),{storageType:c,computeFn:o,isAction:i}=u[s];o||i||(n[c]||(n[c]={}),n[c][s]=r)});for(let[e,t]of Object.entries(n))await b(e,t);return h(e())}async function b(e,t){if(l.IS_AVAILABE(e)){if(await l.SET_VALUES(e,t))return}g((0,s.map)(t,(e,t)=>[e,{newValue:t}]))}async function m(e,t){const n=p(e);return await T(e,(0,s.map)(t?(0,s.filter)(n,(e,{key:n})=>t.includes(n)):n,(e,{key:t,defaultValue:n})=>[t,n])),h(e())}function j(e){return!arguments[1]||(0,s.isString)(arguments[1])?A.apply(null,arguments):(0,s.isArray)(arguments[1])?a.addStateListener.apply(null,arguments):(0,s.isObject)(arguments[1])?T.apply(null,arguments):void 0}function O(e){Object.assign(l,e)}function h(e){const t=t=>function(e,t){return`${e}${(0,s.isString)(t)&&o.NAMESPACE_DELIMITER||""}${t||""}`}(e,t);return Object.assign(j.bind(null,t),{add:e=>f(t,e,!1),addPersistent:e=>f(t,e,!0),get:e=>A(t,e),set:async e=>await T(t,e),reset:e=>m(t,e),onChange:(e,n)=>(0,a.addStateListener)(t,e,n),removeListener:(e,n)=>(0,a.removeStateListener)(t,e,n),actions:e=>(0,c.addStateActions)(t,e),setStorageUtils:O,onStateChange:g})}O(r.default);const v=h("")},"./src/listeners.ts"(e,t,n){n.r(t),n.d(t,{LISTENERS:()=>o,addStateListener:()=>a,removeStateListener:()=>u,runStateChangeListeners:()=>i});var r=n("./src/index.ts"),s=n("./src/constants.ts"),c=n("./src/helpers.ts");const o={};async function i(e){if(Object.keys(e).length){const{namespace:t}=r.STATE[Object.keys(e)[0]],n=(0,r.getValues)(t);for(let[t,s]of Object.entries(e)){const{listeners:e,key:c}=r.STATE[t];for(const t of e)await t([c],n,s)}const i=(0,c.map)(e,e=>e.slice(s.NAMESPACE_DELIMITER.length));for(const r of o[t()])await r(i,n,(0,c.map)(e,(e,t)=>[e.slice(s.NAMESPACE_DELIMITER.length),t]))}}function a(e,t,n){return(0,c.isFunction)(t)?(o[e()].push(t),(0,r.createStore)(e())):(t.forEach(t=>r.STATE[e(t)].listeners?.push(n)),(0,r.createStore)(e()))}function u(e,t,n){if((0,c.isFunction)(t)){const n=o[e()].findIndex(e=>e===t);return o[e()].splice(n,1),(0,r.createStore)(e())}return t.forEach(t=>{const s=r.STATE[e(t)].listeners,c=s?.findIndex(e=>e===n);s?.splice(c,1)}),(0,r.createStore)(e())}},"./src/storage.ts"(e,t,n){n.r(t),n.d(t,{default:()=>r});const r={GET_TYPE:function(e){return e?"localStorage":""},IS_AVAILABE:function(e){return!!e},UPDATE_STATE:async function(e){const t={};for(const n in e){const e=localStorage.getItem(n);null!==e&&(t[n]=e)}return Object.assign(e,t)},SET_VALUES:async function(e,t){for(let[e,n]of Object.entries(t))localStorage.setItem(e,n);return!1}}},"./src/validation.ts"(e,t,n){n.r(t),n.d(t,{isValid:()=>o});var r=n("./src/index.ts"),s=n("./src/constants.ts");function c(e){const t=e.split(s.NAMESPACE_DELIMITER);return[t.slice(-1)[0],t.join(s.NAMESPACE_DELIMITER)]}const o={Setting:e=>{if(!r.STATE[e]){const[t,n]=c(e);throw new Error(`Setting "${t}" key in "${n}" namespace. DOES NOT EXIST`)}return!0},Defining:e=>{if(r.STATE[e]){const[t,n]=c(e);throw new Error(`Redefining "${t}" key in "${n}" namespace. ALREADY DEFINED`)}return!0}}}};const t={};function n(r){const s=t[r];if(void 0!==s)return s.exports;const c=t[r]={exports:{}};if(!(r in e)){delete t[r];const e=new Error("Cannot find module '"+r+"'");throw e.code="MODULE_NOT_FOUND",e}return e[r](c,c.exports,n),c.exports}n.d=(e,t)=>{if(Array.isArray(t))for(var r=0;r<t.length;){var s=t[r++],c=t[r++];n.o(e,s)?0===c&&r++:0===c?Object.defineProperty(e,s,{enumerable:!0,value:t[r++]}):Object.defineProperty(e,s,{enumerable:!0,get:c})}else for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let r=n("./src/index.ts");return r=r.default,r})());
2
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Varstor=t():e.Varstor=t()}(this,()=>(()=>{"use strict";var e={"./src/actions.ts"(e,t,n){n.r(t),n.d(t,{addStateActions:()=>s});var r=n("./src/index.ts");function s(e,t){for(const[n,s]of Object.entries(t))r.STATE[e(n)]={key:n,namespace:e,value:s.bind(null,(0,r.createStore)(e())),isAction:!0,listeners:[]}}},"./src/constants.ts"(e,t,n){n.r(t),n.d(t,{NAMESPACE_DELIMITER:()=>r});const r="::"},"./src/helpers.ts"(e,t,n){n.r(t),n.d(t,{filter:()=>S,forEach:()=>p,getParamNames:()=>f,isArray:()=>c,isAsyncFunction:()=>a,isFunction:()=>i,isObject:()=>u,isString:()=>o,map:()=>d,recreateStructure:()=>y,uid:()=>g});const r=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,s=/([^\s,]+)/g;function c(e){return"[object Array]"===l(e)}function o(e){return"[object String]"===l(e)}function i(e){return"[object Function]"===l(e)}function a(e){return"[object AsyncFunction]"===l(e)}function u(e){return"[object Object]"===l(e)}function l(e){return Object.prototype.toString.call(e)}function f(e){const t=e.toString().replace(r,"").split("=>")[0],n=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(s);return null===n?[]:n}function d(e,t){const n=Object.entries(e).map(([e,n])=>t(e,n));return 2===n[0]?.length?Object.fromEntries(n):n}function p(e,t){Object.entries(e||{}).forEach(([e,n])=>t(e,n))}function S(e,t){return Object.fromEntries(Object.entries(e||{}).filter(([e,n])=>!0===t(e,n)))}function y(e){let t=e;if(c(e))return t=[],e.forEach(e=>t.push(y(e))),t;if(u(e)){t={};for(let n in e)t[n]=y(e[n]);return t}return t}function g(){return Date.now().toString(36)+Math.random().toString(36).substr(2)}},"./src/index.ts"(e,t,n){n.r(t),n.d(t,{STATE:()=>a,createPendingChanges:()=>v,createStore:()=>V,default:()=>_,getState:()=>A,getValues:()=>y,joinStateChanges:()=>E,resetState:()=>O,setState:()=>j,setupValue:()=>p});var r=n("./src/storage.ts"),s=n("./src/helpers.ts"),c=n("./src/actions.ts"),o=n("./src/constants.ts"),i=n("./src/listeners.ts");const a={},u={},l={},f={};async function d(e,t,n){const r=f.GET_TYPE(n),c=Object.assign({},t),o=(0,s.map)(t,(t,n)=>[e(t),n]);f.IS_AVAILABE(r)&&await f.UPDATE_STATE(o,r);for(const n in t){const t=e(n);a[t]=p(n,e,o[t],c[n],r)}return V(e())}function p(e,t,n,r,c){const o=t(e),i=(0,s.isFunction)(n),u=i?(0,s.getParamNames)(n):[];return u.forEach(e=>{const n=t(e);a[n]||(a[n]={dependants:[],dependencies:[],namespace:t,storageType:c}),a[n].dependants?.push(o)}),{key:e,fullKey:o,value:i?n.apply(null,g(u,t)):n,computeFn:i&&n,dependencies:u,dependants:[],listeners:[],defaultValue:r,storageType:c,namespace:t}}function S(e){return(0,s.filter)(a,(t,{key:n})=>t===e(n))}function y(e){return(0,s.map)(S(e),(e,{key:t,value:n})=>[t,n])}function g(e,t){const n=y(t);return e.map(e=>n[e])}async function E(e){for(const[t,{storageTypes:n,readyStorageTypes:r,changes:s}]of Object.entries(u))if(e[t]){const c=e[t].newValue;r[c]=!0,delete e[t],Object.assign(s,e),f.IS_AVAILABE(c)&&f.REMOVE_KEY(c,t);for(const e in n)if(!r[e])return;delete u[t],await b(s)}}async function b(e){const t={};for(const n in e){const r=a[n].value,s=e[n].newValue;r!==s?(t[n]={newValue:s,prevValue:r},a[n].value=s):t[n]={isSame:!0},m(n,e,t)}await(0,i.runStateChangeListeners)((0,s.filter)(t,(e,t)=>!t.isSame))}function m(e,t,n){a[e].dependants?.forEach(e=>{const{dependencies:r,namespace:s}=a[e];if(!function(e,t,n,r){return e.every(e=>{const s=t(e);return n.includes(s)&&r.includes(s)||!n.includes(s)})}(r,s,Object.keys(t),Object.keys(n))||n[e])return;const c=a[e].value,o=a[e].computeFn?.apply(null,g(r,s));c!==o&&(n[e]={newValue:o,prevValue:c},a[e].value=o,m(e,t,n))})}function A(e,t){return(0,s.isString)(t)?V(t):(0,s.recreateStructure)(y(e))}async function j(e,t){const n={},r=(0,s.uid)(),c={};(0,s.forEach)(t,(t,r)=>{const s=e(t),{storageType:o,computeFn:i,isAction:u}=a[s];i||u||(n[o]||(n[o]={}),c[o]=!0,n[o][s]=r)}),u[r]={storageTypes:c,readyStorageTypes:{},changes:{}};for(let[e,t]of Object.entries(n))await T(e,{...t,[r]:e});return V(e())}async function T(e,t){if(f.IS_AVAILABE(e)){if(await f.SET_VALUES(e,t))return}E((0,s.map)(t,(e,t)=>[e,{newValue:t}]))}async function O(e,t){return await j(e,h(e,t)),V(e())}function h(e,t){const n=S(e);return(0,s.map)(t?(0,s.filter)(n,(e,{key:n})=>t.includes(n)):n,(e,{key:t,defaultValue:n})=>[t,n])}function v(e){const t=()=>{const t=l[e()];return l[e()]={},t};return{add:t=>Object.assign(l[e()],t),reset:t=>Object.assign(l[e()],h(e,t)),get:()=>l[e()],flush:t,commit:()=>j(e,t())}}function I(e){return!arguments[1]||(0,s.isString)(arguments[1])?A.apply(null,arguments):(0,s.isArray)(arguments[1])||(0,s.isFunction)(arguments[1])||(0,s.isAsyncFunction)(arguments[1])?i.addStateListener.apply(null,arguments):(0,s.isObject)(arguments[1])?j.apply(null,arguments):void 0}function L(e){Object.assign(f,e)}function V(e){const t=t=>function(e,t){return`${e}${(0,s.isString)(t)&&o.NAMESPACE_DELIMITER||""}${t||""}`}(e,t);return l[t()]||(l[t()]={}),i.LISTENERS[t()]||(i.LISTENERS[t()]=[]),Object.assign(I.bind(null,t),{add:e=>d(t,e,!1),addPersistent:e=>d(t,e,!0),get:e=>A(t,e),set:async e=>await j(t,e),reset:e=>O(t,e),changes:v(t),onChange:(e,n)=>(0,i.addStateListener)(t,e,n),removeListener:(e,n)=>(0,i.removeStateListener)(t,e,n),actions:e=>(0,c.addStateActions)(t,e),setStorageUtils:L,joinStateChanges:E,namespace:t})}L(r.default);const _=V("")},"./src/listeners.ts"(e,t,n){n.r(t),n.d(t,{LISTENERS:()=>o,addStateListener:()=>a,removeStateListener:()=>u,runStateChangeListeners:()=>i});var r=n("./src/index.ts"),s=n("./src/constants.ts"),c=n("./src/helpers.ts");const o={};async function i(e){if(Object.keys(e).length){const{namespace:t}=r.STATE[Object.keys(e)[0]];for(const[n]of Object.entries(e)){const{listeners:e,key:s}=r.STATE[n];for(const n of e){const e=n.bind(null,[s],(0,r.createStore)(t()));(0,c.isAsyncFunction)(n)?await e():e()}}const n=`${t()}${s.NAMESPACE_DELIMITER}`.length,i=(0,c.map)(e,e=>e.slice(n));for(const e of o[t()]){const n=e.bind(null,i,(0,r.createStore)(t()));(0,c.isAsyncFunction)(e)?await n():n()}}}function a(e,t,n){return(0,c.isFunction)(t)||(0,c.isAsyncFunction)(t)?(o[e()].push(t),(0,r.createStore)(e())):(t.forEach(t=>r.STATE[e(t)].listeners?.push(n)),(0,r.createStore)(e()))}function u(e,t,n){if((0,c.isFunction)(t)||(0,c.isAsyncFunction)(t)){const n=o[e()].findIndex(e=>e===t);return o[e()].splice(n,1),(0,r.createStore)(e())}return t.forEach(t=>{const s=r.STATE[e(t)].listeners,c=s?.findIndex(e=>e===n);s?.splice(c,1)}),(0,r.createStore)(e())}},"./src/storage.ts"(e,t,n){n.r(t),n.d(t,{default:()=>r});const r={GET_TYPE:function(e){return e?"localStorage":""},IS_AVAILABE:function(e){return!!e},UPDATE_STATE:async function(e){const t={};for(const n in e){const e=localStorage.getItem(n);null!==e&&(t[n]=e)}return Object.assign(e,t)},SET_VALUES:async function(e,t){for(let[e,n]of Object.entries(t))localStorage.setItem(e,n);return!1},REMOVE_KEY:function(e,t){e&&localStorage.removeItem(t)}}}};const t={};function n(r){const s=t[r];if(void 0!==s)return s.exports;const c=t[r]={exports:{}};if(!(r in e)){delete t[r];const e=new Error("Cannot find module '"+r+"'");throw e.code="MODULE_NOT_FOUND",e}return e[r](c,c.exports,n),c.exports}n.d=(e,t)=>{if(Array.isArray(t))for(var r=0;r<t.length;){var s=t[r++],c=t[r++];n.o(e,s)?0===c&&r++:0===c?Object.defineProperty(e,s,{enumerable:!0,value:t[r++]}):Object.defineProperty(e,s,{enumerable:!0,get:c})}else for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let r=n("./src/index.ts");return r=r.default,r})());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "varstor",
3
- "version": "0.6.63",
3
+ "version": "0.6.65",
4
4
  "description": "State manager for web applications and webextensions, employing reactivity, wrapping, and uniting the usage of different storages' values and common variables into a simple universal interface",
5
5
  "license": "MIT",
6
6
  "author": "Igor Morozov <ismorozs@gmail.com>",
package/src/actions.ts CHANGED
@@ -1,17 +1,11 @@
1
- import { STATE, getState, setState, resetState } from ".";
1
+ import { STATE, createStore } from ".";
2
2
 
3
3
  export function addStateActions(namespace: INamespace, actions: IStateActions) {
4
- const stateAcessor = {
5
- get: getState.bind(null, namespace),
6
- set: setState.bind(null, namespace),
7
- reset: resetState.bind(null, namespace),
8
- };
9
-
10
- for (let [actionName, actionFn] of Object.entries(actions)) {
4
+ for (const [actionName, actionFn] of Object.entries(actions)) {
11
5
  STATE[namespace(actionName)] = {
12
6
  key: actionName,
13
7
  namespace,
14
- value: actionFn.bind(null, stateAcessor),
8
+ value: actionFn.bind(null, createStore(namespace())),
15
9
  isAction: true,
16
10
  listeners: [],
17
11
  };
package/src/helpers.ts CHANGED
@@ -13,6 +13,10 @@ export function isFunction(obj: unknown) {
13
13
  return getObjectType(obj) === "[object Function]";
14
14
  }
15
15
 
16
+ export function isAsyncFunction (obj: unknown) {
17
+ return getObjectType(obj) === "[object AsyncFunction]";
18
+ }
19
+
16
20
  export function isObject(obj: unknown) {
17
21
  return getObjectType(obj) === "[object Object]";
18
22
  }
@@ -86,3 +90,7 @@ export function recreateStructure(value: unknown) {
86
90
 
87
91
  return newValue;
88
92
  }
93
+
94
+ export function uid() {
95
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
96
+ }
package/src/index.ts CHANGED
@@ -10,13 +10,14 @@ import {
10
10
  filter,
11
11
  recreateStructure,
12
12
  forEach,
13
+ uid,
14
+ isAsyncFunction,
13
15
  } from "./helpers";
14
16
 
15
17
  import { addStateActions } from "./actions";
16
18
 
17
19
  import { NAMESPACE_DELIMITER } from "./constants";
18
20
 
19
- import { isValid } from "./validation";
20
21
  import {
21
22
  runStateChangeListeners,
22
23
  addStateListener,
@@ -25,6 +26,8 @@ import {
25
26
  } from "./listeners";
26
27
 
27
28
  export const STATE = {} as IState;
29
+ const STATE_CHANGED_PIECES = {} as IStateUpdatePieces;
30
+ const STATE_PENDING_CHANGES = {} as IStatePendingChanges;
28
31
  const STORAGE = {} as IStorageFunctions;
29
32
 
30
33
  setStorageUtils(storageUtils);
@@ -45,13 +48,8 @@ async function addState(
45
48
  await STORAGE.UPDATE_STATE(values, storageType as string);
46
49
  }
47
50
 
48
- if (!LISTENERS[namespace()]) {
49
- LISTENERS[namespace()] = [];
50
- }
51
-
52
51
  for (const key in initialState) {
53
52
  const fullKey = namespace(key);
54
- isValid.Defining(fullKey);
55
53
  STATE[fullKey] = setupValue(
56
54
  key,
57
55
  namespace,
@@ -125,6 +123,33 @@ function getArguments(dependencies: string[], namespace: INamespace) {
125
123
  return dependencies.map((name) => values[name as keyof typeof values]);
126
124
  }
127
125
 
126
+ export async function joinStateChanges(changesPiece: IStateChanges) {
127
+ for (const [
128
+ updateId,
129
+ { storageTypes, readyStorageTypes, changes },
130
+ ] of Object.entries(STATE_CHANGED_PIECES)) {
131
+ if (changesPiece[updateId]) {
132
+ const storageType = changesPiece[updateId].newValue;
133
+ readyStorageTypes[storageType] = true;
134
+ delete changesPiece[updateId];
135
+ Object.assign(changes, changesPiece);
136
+ if (STORAGE.IS_AVAILABE(storageType)) {
137
+ STORAGE.REMOVE_KEY(storageType, updateId);
138
+ }
139
+
140
+ for (const key in storageTypes) {
141
+ if (!readyStorageTypes[key]) {
142
+ return;
143
+ }
144
+ }
145
+
146
+ delete STATE_CHANGED_PIECES[updateId];
147
+
148
+ await onStateChange(changes);
149
+ }
150
+ }
151
+ }
152
+
128
153
  async function onStateChange(changes: IStateChanges) {
129
154
  const realChanges = {} as IStateChanges;
130
155
 
@@ -207,6 +232,8 @@ export async function setState(
207
232
  changes: Record<string, unknown>,
208
233
  ): Promise<unknown> {
209
234
  const storageChanges: Record<string, any> = {};
235
+ const updateId = uid();
236
+ const storageTypes = {} as Record<string, boolean>;
210
237
 
211
238
  forEach(changes, (k, v) => {
212
239
  const fullKey = namespace(k);
@@ -220,11 +247,19 @@ export async function setState(
220
247
  storageChanges[storageType!] = {};
221
248
  }
222
249
 
250
+ storageTypes[storageType!] = true;
251
+
223
252
  storageChanges[storageType!][fullKey] = v;
224
253
  });
225
254
 
255
+ STATE_CHANGED_PIECES[updateId] = {
256
+ storageTypes,
257
+ readyStorageTypes: {},
258
+ changes: {},
259
+ };
260
+
226
261
  for (let [storageType, changes] of Object.entries(storageChanges)) {
227
- await setValues(storageType, changes);
262
+ await setValues(storageType, { ...changes, [updateId]: storageType });
228
263
  }
229
264
 
230
265
  return createStore(namespace());
@@ -241,25 +276,47 @@ async function setValues(
241
276
  }
242
277
  }
243
278
 
244
- onStateChange(
279
+ joinStateChanges(
245
280
  map(changes, (k, newValue) => [k, { newValue }]) as Record<string, any>,
246
281
  );
247
282
  }
248
283
 
249
284
  export async function resetState(namespace: INamespace, keys?: string[]) {
285
+ await setState(namespace, getDefaultValues(namespace, keys));
286
+
287
+ return createStore(namespace());
288
+ }
289
+
290
+ function getDefaultValues(namespace: INamespace, keys?: string[]) {
250
291
  const namespaceState = getNamespaceState(namespace);
251
292
 
252
- await setState(
253
- namespace,
254
- map(
255
- keys
256
- ? filter(namespaceState, (k, { key }) => keys.includes(key!))
257
- : namespaceState,
258
- (k, { key, defaultValue }) => [key, defaultValue],
259
- ) as Record<string, any>,
260
- );
293
+ return map(
294
+ keys
295
+ ? filter(namespaceState, (k, { key }) => keys.includes(key!))
296
+ : namespaceState,
297
+ (k, { key, defaultValue }) => [key, defaultValue],
298
+ ) as Record<string, any>;
299
+ }
261
300
 
262
- return createStore(namespace());
301
+ export function createPendingChanges(namespace: INamespace) {
302
+ const flush = () => {
303
+ const changes = STATE_PENDING_CHANGES[namespace()];
304
+ STATE_PENDING_CHANGES[namespace()] = {};
305
+ return changes;
306
+ }
307
+
308
+ return {
309
+ add: (changes: Record<string, any>) =>
310
+ Object.assign(STATE_PENDING_CHANGES[namespace()], changes),
311
+ reset: (keys: string[]) =>
312
+ Object.assign(
313
+ STATE_PENDING_CHANGES[namespace()],
314
+ getDefaultValues(namespace, keys),
315
+ ),
316
+ get: () => STATE_PENDING_CHANGES[namespace()],
317
+ flush,
318
+ commit: () => setState(namespace, flush()),
319
+ };
263
320
  }
264
321
 
265
322
  function main(namespace: INamespace): any {
@@ -267,7 +324,7 @@ function main(namespace: INamespace): any {
267
324
  return getState.apply(null, arguments as unknown as [INamespace, string]);
268
325
  }
269
326
 
270
- if (isArray(arguments[1])) {
327
+ if (isArray(arguments[1]) || isFunction(arguments[1]) || isAsyncFunction(arguments[1])) {
271
328
  return addStateListener.apply(
272
329
  null,
273
330
  arguments as unknown as [INamespace, string[], () => {}],
@@ -294,6 +351,14 @@ export function createStore(_namespace: string) {
294
351
  const namespace = ((key: string) =>
295
352
  addNamespace(_namespace, key)) as INamespace;
296
353
 
354
+ if (!STATE_PENDING_CHANGES[namespace()]) {
355
+ STATE_PENDING_CHANGES[namespace()] = {};
356
+ }
357
+
358
+ if (!LISTENERS[namespace()]) {
359
+ LISTENERS[namespace()] = [];
360
+ }
361
+
297
362
  return Object.assign(main.bind(null, namespace), {
298
363
  add: (state: IStateDefault) => addState(namespace, state, false),
299
364
  addPersistent: (state: IStateDefault) => addState(namespace, state, true),
@@ -301,13 +366,15 @@ export function createStore(_namespace: string) {
301
366
  set: async (changes: Record<string, unknown>) =>
302
367
  await setState(namespace, changes),
303
368
  reset: (keys: string[]) => resetState(namespace, keys),
369
+ changes: createPendingChanges(namespace),
304
370
  onChange: (keys: string[], cb: () => {}) =>
305
371
  addStateListener(namespace, keys, cb),
306
372
  removeListener: (keys: string[], cb: () => {}) =>
307
373
  removeStateListener(namespace, keys, cb),
308
374
  actions: (actions: IStateActions) => addStateActions(namespace, actions),
309
375
  setStorageUtils,
310
- onStateChange,
376
+ joinStateChanges,
377
+ namespace,
311
378
  });
312
379
  }
313
380