@zedux/stores
Version:
The legacy composable store model of Zedux
674 lines (661 loc) • 19.9 kB
JavaScript
import { AtomInstance as V, zi as d, ZeduxPlugin as k, AtomTemplateBase as Z, injectRef as K, injectWhy as W, injectMemo as X, injectEffect as q, injectAtomGetters as J } from "@zedux/atoms";
const Q = (s) => {
const t = Object.getPrototypeOf(s);
return t ? Object.getPrototypeOf(t) ? "complex object" : "object" : "prototype-less object";
}, Et = (s) => {
const t = typeof s;
return t !== "object" ? t : s ? Array.isArray(s) ? "array" : Q(s) : "null";
}, xt = (s) => {
const t = (e) => {
const r = {
type: t.type
};
return typeof e < "u" && (r.payload = e), r;
};
return t.type = s, t;
}, $ = (s, t) => typeof s == "string" ? s : s.type, Y = (s, t) => s.map((e) => $(e)), jt = (s) => {
const t = {}, e = (r = s, i) => {
const n = t[i.type] || [];
return et(n, r, i);
};
return e.reduce = (r, i) => {
const n = Array.isArray(r) ? Y(r) : [$(r)];
return tt(t, n, i), e;
}, e;
}, tt = (s, t, e) => {
t.forEach((r) => {
s[r] || (s[r] = []), s[r].push(e);
});
}, et = (s, t, e) => s.reduce((r, i) => i(r, e.payload, e), t), b = (s, t) => {
var e;
return ((e = s == null ? void 0 : s.constructor) === null || e === void 0 ? void 0 : e.$$typeof) === t.$$typeof;
}, _ = (s) => {
if (typeof s != "object" || !s)
return !1;
const t = Object.getPrototypeOf(s);
return t ? Object.getPrototypeOf(t) === null : !1;
}, f = "@@zedux/", c = {
batch: `${f}batch`,
delegate: `${f}delegate`,
hydrate: `${f}hydrate`,
ignore: `${f}ignore`,
// for use with atoms in the @zedux/atoms package
inherit: `${f}inherit`,
merge: `${f}merge`,
prime: `${f}prime`
}, y = 1, g = 2, I = 3, C = 4, st = Symbol.for("zedux.store"), rt = (s, t, e) => {
const r = {};
return Object.entries(s).forEach(([i, n]) => {
const o = [...e, i];
r[i] = N(n, t, o);
}), r;
}, it = (s, t, e, r) => s === g ? { type: s } : s === I ? { type: s, reducer: t } : {
type: s,
destroy: e(r, t),
reducer: ot(t),
store: t
}, nt = (s) => typeof s == "function" ? I : s && b(s, l) ? C : _(s) ? y : g, N = (s, t, e = []) => {
const r = nt(s);
return r !== y ? it(r, s, t, e) : {
type: r,
children: rt(s, t, e)
};
}, ot = (s) => (e, r) => {
(r.type === c.hydrate || r.type === c.merge) && (r = {
type: c.hydrate,
payload: e
});
const i = {
metaType: c.inherit,
payload: r
};
return s.dispatch(i);
}, ct = (s) => (t = {}, e) => {
const r = {};
let i = !1;
return Object.keys(s).forEach((n) => {
const { reducer: o } = s[n], h = _(t) ? t[n] : void 0, u = o(h, e);
r[n] = u, i || (i = u !== h);
}), i || (i = !_(t) || !Object.keys(s).length && !!Object.keys(t).length), i ? r : t;
}, S = (s) => {
if (!s)
return;
const { children: t, destroy: e } = s;
e && e(), t && Object.values(t).forEach(S);
}, j = (s, t) => {
const e = Object.assign({}, s.children);
return Object.keys(t.children).forEach((r) => {
var i;
const n = t.children[r], o = (i = s.children) === null || i === void 0 ? void 0 : i[r], h = P(o, n);
if (h.type === g) {
delete e[r];
return;
}
e[r] = h;
}), {
children: e,
reducer: ct(e),
type: y
};
}, P = (s, t) => t.type !== y ? (S(s), t) : !s || s.type !== y ? (S(s), j({ type: g }, t)) : j(s, t), R = (s, t) => {
if (!_(s) || !_(t))
return [t, t !== s];
let e = !1;
const r = Object.assign({}, s);
return Object.keys(t).forEach((i) => {
const n = t[i], o = r[i], [h, u] = _(n) ? (
// Recursively merge the nested nodes.
R(o, n)
) : (
// Not a nested node (anymore, at least)
[n, n !== o]
);
u && (e || (e = u), r[i] = h);
}), [e ? r : s, e];
}, ht = (s, t, e) => !t || !e ? s.payload : (t.payload = s.payload, e), ut = (s, t) => {
for (; s.metaType; ) {
if (s.metaType === t)
return s.metaData;
s = s.payload;
}
}, at = (s) => {
for (; s.metaType; )
s = s.payload;
return s;
}, dt = (s, t) => {
let e = s, r = null, i = null;
for (; e.metaType; ) {
if (e.metaType === t)
return ht(e, r, i);
const n = Object.assign({}, e);
r && (r.payload = n), r = n, e = e.payload, i || (i = r);
}
return s;
}, w = "Minified Error", lt = (s, t) => {
for (const e of t) {
if (s.type !== y)
throw new ReferenceError(w);
if (s = s.children[e], !s)
throw new ReferenceError(w);
}
return s;
}, ft = (s, t) => {
const e = ut(t, c.delegate);
if (!e || !s)
return !1;
const r = lt(s, e);
if (r.type !== C)
throw new TypeError(w);
r.store.dispatch(dt(t, c.delegate));
}, z = (s, t, e) => {
if (!t.length)
return e;
const r = Object.assign({}, s), i = t[0];
return r[i] = z(s[i], t.slice(1), e), r;
}, pt = {
scheduleNow: (s) => s.j()
}, T = { type: c.prime }, H = (s, t) => new l(s, t);
class l {
constructor(t, e) {
this._isSolo = !0, this._subscribers = [], this.dispatch = (r) => this._isSolo ? this._dispatch(r) : (this._scheduler.scheduleNow({
j: () => this._dispatch(r),
T: 0
// UpdateStore (0)
}), this._state), this.setState = (r, i) => this._isSolo ? this._setState(r, i) : (this._scheduler.scheduleNow({
j: () => this._setState(r, i),
T: 0
// UpdateStore (0)
}), this._state), this._state = e, this._scheduler = l._scheduler || pt, t && this.use(t);
}
actionStream() {
return {
[Symbol.observable]() {
return this;
},
"@@observable"() {
return this;
},
subscribe: (t) => this.subscribe({
effects: ({ action: e, error: r }) => {
var i, n;
r && typeof t != "function" ? (i = t.error) === null || i === void 0 || i.call(t, r) : e && (typeof t == "function" ? t(e) : (n = t.next) === null || n === void 0 || n.call(t, e));
}
})
};
}
/**
Returns the current state of the store.
Do not mutate the returned value.
*/
getState() {
return this._state;
}
/**
Applies a partial state update to the store.
Accepts either a deep partial state object or a function that accepts the
current state and returns a deep partial state object.
This method only recursively traverses normal JS objects. If your store
deeply nests any other data structure, including arrays or maps, you'll have
to deeply merge them yourself using `store.setState()`.
Dispatches the special `merge` action to the store's reducers. This action's
`payload` property will be set to the resolved partial state update. Effects
subscribers can record this action to implement time travel.
IMPORTANT: Deep setting cannot remove properties from the state tree. Use
`store.setState()` for that.
Throws an error if called from the reducer layer.
Returns the new state.
Unlike setState, setStateDeep is not bound. You must call it with context -
e.g. by using dot-notation: `store.setStateDeep(...)`
*/
setStateDeep(t, e) {
return this._isSolo ? this._setState(t, e, !0) : (this._scheduler.scheduleNow({
j: () => this._setState(t, e, !0),
T: 0
// UpdateStore (0)
}), this._state);
}
/**
Registers a subscriber with the store.
The subscriber will be notified every time the store's state
changes.
Returns a subscription object. Calling `subscription.unsubscribe()`
unregisters the subscriber.
*/
subscribe(t) {
const e = typeof t == "function" ? { next: t } : t;
return this._subscribers.push(e), {
unsubscribe: () => {
this._subscribers = this._subscribers.filter((i) => i !== e);
}
};
}
/**
Merges a hierarchy descriptor into the existing hierarchy descriptor.
Intelligently diffs the two hierarchies and only creates/recreates the
necessary reducers.
Dispatches the special `prime` action to the store.
*/
use(t) {
const e = N(t, (i, n) => this._registerChildStore(i, n)), r = this._tree = P(this._tree, e);
return (this._rootReducer = r.reducer) && this._dispatchAction(T, T, this._state), this;
}
/**
* Only for internal use.
*/
_register(t) {
const e = this._parents || (this._parents = []);
return e.push(t), this._isSolo = !1, () => {
const r = e.indexOf(t);
r > -1 && e.splice(r, 1);
};
}
[Symbol.observable]() {
return this;
}
"@@observable"() {
return this;
}
_dispatch(t) {
return ft(this._tree, t) !== !1 ? this._state : this._routeAction(t);
}
_dispatchAction(t, e, r) {
this._isDispatching = !0;
let i, n = r;
try {
this._rootReducer && (n = this._rootReducer(r, e));
} catch (o) {
throw i = o, o;
} finally {
this._isDispatching = !1, this._notify(n, t, i);
}
return n;
}
_dispatchHydration(t, e, r) {
const i = e === c.hydrate ? t : R(this._state, t)[0];
if (i === this._state && !r)
return this._state;
const n = {
meta: r,
payload: i,
type: e
};
return this._dispatchAction(n, n, i);
}
_dispatchStateSetter(t, e, r) {
let i;
try {
i = t(this._state);
} catch (n) {
throw n;
}
return this._dispatchHydration(i, r ? c.merge : c.hydrate, e);
}
_doNotify(t) {
const { _subscribers: e } = this, r = t.newState !== t.oldState;
for (const i of e)
t.error && i.error && i.error(t.error), r && i.next && i.next(t.newState, t.oldState, t.action), i.effects && i.effects(t);
}
_notify(t, e, r) {
var i;
const n = {
action: e,
error: r,
newState: t,
oldState: this._state,
store: this
};
if (this._state = t, this._isSolo)
return this._doNotify(n);
this._scheduler.scheduleNow({
j: () => this._doNotify(n),
T: 1
// InformSubscribers (1)
}), (i = this._parents) === null || i === void 0 || i.forEach((o) => o(n));
}
_registerChildStore(t, e) {
this._isSolo = !1;
const r = ({ action: i, error: n, newState: o, oldState: h }) => {
if (this._isDispatching)
return;
const u = o === h ? this._state : z(this._state, t, o), a = {
metaType: c.delegate,
metaData: t,
payload: i
};
this._notify(u, a, n);
};
return e._register(r);
}
_routeAction(t) {
const e = at(t);
return e.type === c.hydrate || e.type === c.merge ? this._dispatchHydration(e.payload, e.type, e.meta) : this._dispatchAction(t, e, this._state);
}
_setState(t, e, r = !1) {
return typeof t == "function" ? this._dispatchStateSetter(t, e, r) : this._dispatchHydration(t, r ? c.merge : c.hydrate, e);
}
}
l.$$typeof = st;
const A = "@@zedux", _t = 1, yt = 3, D = (s) => ({
error: s,
isError: !0,
isLoading: !1,
isSuccess: !1,
status: "error"
}), v = (s) => ({
data: s,
isError: !1,
isLoading: !0,
isSuccess: !1,
status: "loading"
}), B = (s) => ({
data: s,
isError: !1,
isLoading: !1,
isSuccess: !0,
status: "success"
}), M = class {
constructor(s) {
this.promise = void 0, this.value = s, this.store = b(s, l) ? s : void 0, b(s, M) && Object.assign(this, s);
}
addExports(s) {
return this.exports ? this.exports = { ...this.exports, ...s } : this.exports = s, this;
}
setExports(s) {
return this.exports = s, this;
}
setPromise(s) {
return this.promise = s, this;
}
setTtl(s) {
return this.ttl = s, this;
}
};
let E = M;
E.$$typeof = Symbol.for(`${A}/AtomApi`);
const bt = (s) => new E(
s
), U = 1, x = 2, F = (s) => b(s, l) ? U : x, gt = (s) => {
const t = F(s), e = t === U ? s : H();
return t === x && e.setState(
typeof s == "function" ? () => s : s
), [t, e];
};
class G extends V {
constructor(t, e, r, i) {
super(t, e, r, i), this.e = t, this.t = e, this.id = r, this.p = i, this.dispatch = (n) => this.store.dispatch(n), this.setState = (n, o) => this.store.setState(n, o), this.setStateDeep = (n, o) => this.store.setStateDeep(n, o), this._createdAt = t._idGenerator.now();
}
/**
* @see NewAtomInstance.destroy
*/
destroy(t) {
var r, i;
if (!d.b(this, t))
return;
const e = [];
(r = this._injectors) == null || r.forEach((n) => {
var o;
if (n.type !== "@@zedux/effect") {
e.push(n);
return;
}
(o = n.cleanup) == null || o.call(n);
}), e.forEach((n) => {
var o;
(o = n.cleanup) == null || o.call(n);
}), (i = this._subscription) == null || i.unsubscribe(), d.e(this);
}
/**
* An alias for `instance.store.getState()`. Returns the current state of this
* atom instance's store.
*
* @deprecated - use `.get()` instead @see AtomInstance.get
*/
getState() {
return this.store.getState();
}
/**
* @see NewAtomInstance.get
*
* An alias for `instance.store.getState()`.
*/
get() {
return this.store.getState();
}
/**
* Force this atom instance to reevaluate.
*/
invalidate() {
this.r({ t: _t }, !1), this.e._scheduler.flush();
}
/**
* `.mutate()` is not supported in legacy, store-based atoms. Upgrade to the
* new `atom()` factory.
*/
mutate() {
throw new Error(
"`.mutate()` is not supported in legacy, store-based atoms. Upgrade to the new `atom()` factory"
);
}
set(t, e) {
return this.setState(t, e && Object.keys(e)[0]);
}
/**
* @see NewAtomInstance.j
*/
j() {
const { n: t, s: e } = d.g();
this._nextInjectors = [], this._isEvaluating = !0, l._scheduler = this.e._scheduler, d.s(this);
try {
const r = this._eval();
this.l === "Initializing" ? ([this._stateType, this.store] = gt(r), this._subscription = this.store.subscribe(
(i, n, o) => {
if (this._isEvaluating) {
this._bufferedUpdate = { newState: i, oldState: n, action: o };
return;
}
this._handleStateChange(i, n, o);
}
)) : F(r) === x && this.store.setState(
typeof r == "function" ? () => r : r
);
} catch (r) {
throw this._nextInjectors.forEach((i) => {
var n;
(n = i.cleanup) == null || n.call(i);
}), d.d(t, e), r;
} finally {
this._isEvaluating = !1, t || (l._scheduler = void 0), this._bufferedUpdate && (this._handleStateChange(
this._bufferedUpdate.newState,
this._bufferedUpdate.oldState,
this._bufferedUpdate.action
), this._bufferedUpdate = void 0), this.w = [];
}
this._injectors = this._nextInjectors, this.l !== "Initializing" && d.f(t, e);
}
/**
* @see NewAtomInstance.r
*/
r(t, e) {
this.l !== "Destroyed" && this.w.push(t) === 1 && this.e._scheduler.schedule(this, e);
}
get _infusedSetter() {
if (this._set)
return this._set;
const t = (e, r) => this.setState(e, r);
return this._set = Object.assign(t, this.exports);
}
/**
* A standard atom's value can be one of:
*
* - A raw value
* - A Zedux store
* - A function that returns a raw value
* - A function that returns a Zedux store
* - A function that returns an AtomApi
*/
_eval() {
var e;
const { _value: t } = this.t;
if (typeof t != "function")
return t;
try {
const r = t(...this.p);
if (!b(r, E))
return r;
const i = this.api = r;
return this.l === "Initializing" && i.exports && (this.exports = i.exports), typeof ((e = i.value) == null ? void 0 : e.then) == "function" ? this._setPromise(i.value, !0) : (i.promise && this._setPromise(i.promise), i.value);
} catch (r) {
throw console.error(
`Zedux: Error while evaluating atom "${this.t.key}" with params:`,
this.p,
r
), r;
}
}
_handleStateChange(t, e, r) {
d.u({ p: e, r: this.w, s: this }, !1), this.e._mods.stateChanged && this.e.modBus.dispatch(
k.actions.stateChanged({
action: r,
node: this,
newState: t,
oldState: e,
reasons: this.w
})
), r.meta !== c.batch && this.e._scheduler.flush();
}
_setPromise(t, e) {
var n;
const r = (n = this.store) == null ? void 0 : n.getState();
if (t === this.promise)
return r;
this.promise = t, t.then((o) => {
this.promise === t && (this._promiseStatus = "success", e && this.store.setState(
B(o)
));
}).catch((o) => {
this.promise === t && (this._promiseStatus = "error", this._promiseError = o, e && this.store.setState(
D(o)
));
});
const i = v(r == null ? void 0 : r.data);
return this._promiseStatus = i.status, d.u({ s: this, t: yt }, !0, !0), i;
}
}
G.$$typeof = Symbol.for(`${A}/AtomInstance`);
class L extends Z {
/**
* This method should be overridden when creating custom atom classes that
* create a custom atom instance class. Return a new instance of your atom
* instance class.
*/
_createInstance(t, e, r) {
return new G(t, this, e, r);
}
getInstanceId(t, e) {
const r = this.key;
return e != null && e.length ? `${r}-${t._idGenerator.hashParams(
e,
t.complexParams
)}` : r;
}
override(t) {
const e = mt(this.key, t, this._config);
return e._isOverride = !0, e;
}
}
const mt = (s, t, e) => new L(s, t, e), O = (s, t) => t.subscribe((e, r, i) => {
if (s._isEvaluating || i.meta === c.ignore)
return;
const n = (i == null ? void 0 : i.meta) === c.batch;
s.r({ p: r }, n), n || s.e._scheduler.flush();
}), St = d.c(
"injectStore",
(s, t, e) => {
var h;
const r = (e == null ? void 0 : e.subscribe) ?? !0, n = (typeof t == "function" ? t : (u) => H(null, u ?? t))(
e != null && e.hydrate ? (h = s.e.hydration) == null ? void 0 : h[s.id] : void 0
), o = r && O(s, n);
return {
cleanup: o ? () => o.unsubscribe() : void 0,
result: n,
type: `${A}/store`
};
},
(s, t, e, r) => {
const i = (r == null ? void 0 : r.subscribe) ?? !0;
if (!!s.cleanup === i)
return s;
if (!i)
return s.cleanup(), s.cleanup = void 0, s;
const o = O(t, s.result);
return s.cleanup = () => o.unsubscribe(), s;
}
), Tt = (s, t, {
dataOnly: e,
initialState: r,
runOnInvalidate: i,
...n
} = {}) => {
const o = K({ counter: 0 }), h = St(
e ? r : v(r),
n
);
return i && // injectWhy is an unrestricted injector - using it conditionally is fine:
W().some((u) => u.type === "cache invalidated") && o.current.counter++, o.current.promise = X(() => {
const u = o.current.controller, a = typeof AbortController < "u" ? new AbortController() : void 0;
o.current.controller = a;
const m = s(o.current.controller);
return m === o.current.promise ? o.current.promise : (u && u.abort("updated"), e || h.setStateDeep(
(p) => v(
p.data
)
), m.then((p) => {
a != null && a.signal.aborted || h.setState(e ? p : B(p));
}).catch((p) => {
e || a != null && a.signal.aborted || h.setStateDeep(D(p));
}), m);
}, t && [...t, o.current.counter]), q(
() => () => {
const u = o.current.controller;
u && u.abort("destroyed");
},
[]
), bt(h).setPromise(o.current.promise);
};
class wt extends L {
constructor(t, e, r) {
super(
t,
(...i) => e(J(), ...i),
r
), this._get = e;
}
override(t) {
const e = vt(this.key, t || this._get, this._config);
return e._isOverride = !0, e;
}
}
const vt = (s, t, e) => new wt(s, t, e);
export {
E as AtomApi,
G as AtomInstance,
L as AtomTemplate,
wt as IonTemplate,
l as Store,
xt as actionFactory,
bt as api,
mt as atom,
jt as createReducer,
H as createStore,
Et as detailedTypeof,
O as doSubscribe,
ut as getMetaData,
Tt as injectPromise,
St as injectStore,
vt as ion,
b as is,
_ as isPlainObject,
at as removeAllMeta,
dt as removeMeta,
c as zeduxTypes
};