@reatom/devtools
Version:
Reatom developer tools for states and actions inspecting
889 lines • 306 kB
JavaScript
const impossibleValue = Symbol(), callSafely = (fn, ...args) => {
try {
return fn(...args);
} catch (err) {
return setTimeout(() => {
throw err;
}), err instanceof Error ? err : err = new Error(err);
}
};
function throwReatomError(condition, message) {
if (condition) throw new Error(`Reatom error: ${message}`);
}
const isAtom = (thing) => (thing == null ? void 0 : thing.__reatom) !== void 0, isAction = (thing) => {
var _a2;
return ((_a2 = thing == null ? void 0 : thing.__reatom) == null ? void 0 : _a2.isAction) === !0;
}, isConnected$1 = (cache) => cache.subs.size + cache.listeners.size > 0;
function assertFunction(thing) {
throwReatomError(typeof thing != "function", `invalid "${typeof thing}", function expected`);
}
const getRootCause$1 = (cause) => cause.cause === null ? cause : getRootCause$1(cause.cause), isBrowser = () => typeof window == "object" && typeof document == "object";
let initiations = 0, CTX;
const createCtx = ({ callLateEffect = callSafely, callNearEffect = callSafely, restrictMultipleContexts = isBrowser() } = {}) => {
restrictMultipleContexts && initiations++ === 1 && console.warn("Reatom: multiple contexts detected, which is irrelevant in browser, you should use only one context");
let caches = /* @__PURE__ */ new WeakMap(), read = (proto) => caches.get(proto), logsListeners = /* @__PURE__ */ new Set(), nearEffects = [], lateEffects = [], inTr = !1, trError = null, trUpdates = [], trRollbacks = [], trLogs = [], trNearEffectsStart = 0, trLateEffectsStart = 0, effectsProcessing = !1, walkNearEffects = () => {
for (let effect of nearEffects) callNearEffect(effect, ctx2);
nearEffects = [];
}, walkLateEffects = () => {
if (!effectsProcessing) {
effectsProcessing = !0, walkNearEffects();
for (let effect of lateEffects)
callLateEffect(effect, ctx2), nearEffects.length > 0 && walkNearEffects();
lateEffects = [], effectsProcessing = !1;
}
}, addPatch = ({ state, proto, pubs, subs, listeners }, cause) => (proto.actual = !1, trLogs.push(proto.patch = {
state,
proto,
cause,
pubs,
subs,
listeners
}), proto.patch), enqueueComputers = (cache) => {
for (let subProto of cache.subs) {
let subCache = subProto.patch ?? read(subProto);
(!subProto.patch || subProto.actual) && addPatch(subCache, cache).listeners.size === 0 && enqueueComputers(subCache);
}
}, disconnect = (proto, pubPatch) => {
if (pubPatch.subs.delete(proto) && (trRollbacks.push(() => pubPatch.subs.add(proto)), !isConnected$1(pubPatch))) {
pubPatch.proto.disconnectHooks !== null && nearEffects.push(...pubPatch.proto.disconnectHooks);
for (let parentParent of pubPatch.pubs) disconnect(pubPatch.proto, parentParent);
}
}, connect = (proto, pubPatch) => {
if (!pubPatch.subs.has(proto)) {
let wasConnected = isConnected$1(pubPatch);
if (pubPatch.subs.add(proto), trRollbacks.push(() => pubPatch.subs.delete(proto)), !wasConnected) {
pubPatch.proto.connectHooks !== null && nearEffects.push(...pubPatch.proto.connectHooks);
for (let parentParentPatch of (pubPatch.proto.patch ?? read(pubPatch.proto)).pubs) connect(pubPatch.proto, parentParentPatch);
}
}
}, actualizePubs = (patchCtx, patch) => {
let { proto, pubs } = patch, isDepsChanged = !1;
if (pubs.length === 0 || pubs.some(({ proto: proto$1, state }) => !Object.is(state, (patch.cause = actualize(patchCtx, proto$1)).state))) {
let newPubs = [];
if (patchCtx.spy = ({ __reatom: depProto }, cb) => {
let depPatch = actualize(patchCtx, depProto), prevDepPatch = newPubs.push(depPatch) <= pubs.length ? pubs[newPubs.length - 1] : void 0, isDepChanged = (prevDepPatch == null ? void 0 : prevDepPatch.proto) !== depPatch.proto;
isDepsChanged || (isDepsChanged = isDepChanged);
let state = depProto.isAction && !isDepChanged ? depPatch.state.slice(prevDepPatch.state.length) : depPatch.state;
if (cb && (isDepChanged || !Object.is(state, prevDepPatch.state))) if (depProto.isAction) for (const call of state) cb(call);
else cb(state, isDepChanged || prevDepPatch == null ? void 0 : prevDepPatch.state);
else return state;
}, patch.state = patch.proto.computer(patchCtx, patch.state), patch.pubs = newPubs, (isDepsChanged || pubs.length > newPubs.length) && isConnected$1(patch)) {
for (let { proto: depProto } of pubs) newPubs.every((dep) => dep.proto !== depProto) && disconnect(proto, depProto.patch ?? read(depProto));
for (let { proto: depProto } of newPubs) pubs.every((dep) => dep.proto !== depProto) && connect(proto, depProto.patch ?? read(depProto));
}
patchCtx.spy = () => throwReatomError(!0, "async spy"), patch = proto = pubs = newPubs = null;
}
}, actualize = (ctx$12, proto, updater) => {
let { patch, actual } = proto, updating = updater !== void 0;
if (!updating && actual && (patch.pubs.length === 0 || isConnected$1(patch))) return patch;
let cache = patch ?? read(proto), isInt = !cache, cause = updating ? ctx$12.cause : read(__root);
if (isInt)
cache = {
state: proto.initState(ctx$12),
proto,
cause,
pubs: [],
subs: /* @__PURE__ */ new Set(),
listeners: /* @__PURE__ */ new Set()
}, updating && trLogs.push(cache);
else if (proto.computer === null && !updating) return cache;
(!patch || actual) && (patch = addPatch(cache, cause));
let { state } = patch, patchCtx = {
get: ctx$12.get,
spy: void 0,
schedule: ctx$12.schedule,
subscribe: ctx$12.subscribe,
cause: patch
};
try {
proto.computer && actualizePubs(patchCtx, patch), updating && (patch.cause = ctx$12.cause, updater(patchCtx, patch)), proto.actual = !0;
} catch (error) {
throw patch.error = error;
}
if (!Object.is(state, patch.state) && (patch.subs.size > 0 && (updating || patch.listeners.size > 0) && enqueueComputers(patch), proto.updateHooks)) {
let ctx$2 = {
get: patchCtx.get,
spy: void 0,
schedule: patchCtx.schedule,
subscribe: patchCtx.subscribe,
cause: patchCtx.cause
};
proto.updateHooks.forEach((hook) => trUpdates.push(() => hook(ctx$2, patch)));
}
return patch;
}, ctx2 = {
get(atomOrCb) {
if (throwReatomError(CTX && getRootCause$1(CTX.cause) !== read(__root), "cause collision"), isAtom(atomOrCb)) {
let proto = atomOrCb.__reatom;
if (inTr) return actualize(this, proto).state;
let cache = read(proto);
return cache !== void 0 && (proto.computer === null || isConnected$1(cache)) ? cache.state : this.get(() => actualize(this, proto).state);
}
if (throwReatomError(trError !== null, "tr failed"), inTr) return atomOrCb(read, actualize);
inTr = !0, trNearEffectsStart = nearEffects.length, trLateEffectsStart = lateEffects.length;
let start = CTX === void 0;
start && (CTX = this);
try {
var result = atomOrCb(read, actualize);
for (let i$12 = 0; i$12 < trLogs.length; i$12++) {
let { listeners, proto } = trLogs[i$12];
if (listeners.size > 0 && actualize(this, proto), trUpdates.length > 0) for (let commit of trUpdates.splice(0)) commit(this);
}
if (trLogs.length) for (let log of logsListeners) log(trLogs);
for (let patch of trLogs) {
let { proto, state } = patch;
if (proto.isAction && (patch.state = []), patch === proto.patch)
if (proto.patch = null, proto.actual = !1, caches.set(proto, patch), proto.isAction) {
if (state.length === 0) continue;
for (let cb of patch.listeners) nearEffects.push(() => cb(state));
} else for (let cb of patch.listeners) lateEffects.push(() => cb(read(proto).state));
}
} catch (e) {
trError = e = e instanceof Error ? e : new Error(String(e));
for (let log of logsListeners) log(trLogs, e);
for (let cb of trRollbacks) callSafely(cb, e);
for (let { proto } of trLogs)
proto.patch = null, proto.actual = !1;
throw nearEffects.length = trNearEffectsStart, lateEffects.length = trLateEffectsStart, e;
} finally {
inTr = !1, trError = null, trUpdates = [], trRollbacks = [], trLogs = [], trNearEffectsStart = 0, trLateEffectsStart = 0, start && (CTX = void 0);
}
return walkLateEffects(), result;
},
spy: void 0,
schedule(cb, step = 1) {
return assertFunction(cb), throwReatomError(!this, "missed context"), new Promise((res, rej) => {
step === -1 ? inTr && trRollbacks.push(cb) : step === 0 ? inTr && trUpdates.push(() => cb(this)) : ((step === 1 ? nearEffects : lateEffects).push(() => {
try {
let result = cb(this);
return result instanceof Promise ? result.then(res, rej) : res(result), result;
} catch (error) {
throw rej(error), error;
}
}), inTr || walkLateEffects());
});
},
subscribe(atom$1, cb = atom$1) {
if (assertFunction(cb), atom$1 === cb)
return logsListeners.add(cb), () => logsListeners.delete(cb);
throwReatomError(!isAtom(atom$1), "target subscriber isn't an atom");
let { __reatom: proto } = atom$1, lastState = impossibleValue, listener = (state) => Object.is(lastState, state) || cb(lastState = state), cache = read(proto);
return cache === void 0 || !isConnected$1(cache) ? this.get(() => {
cache = actualize(this, proto, (patchCtx, patch) => {
}), cache.listeners.add(listener), trRollbacks.push(() => proto.patch.listeners.delete(listener));
for (let pubPatch of cache.pubs) connect(proto, pubPatch);
proto.connectHooks !== null && nearEffects.push(...proto.connectHooks);
}) : cache.listeners.add(listener), lastState === impossibleValue && listener((proto.patch ?? read(proto)).state), () => {
if (cache.listeners.delete(listener) && !isConnected$1(cache)) {
proto.disconnectHooks && nearEffects.push(...proto.disconnectHooks);
for (let pubCache of read(proto).pubs) disconnect(proto, pubCache);
inTr || (trRollbacks.length = 0, walkLateEffects());
}
};
},
cause: void 0
};
return (ctx2.cause = ctx2.get(() => actualize(ctx2, __root))).cause = null, ctx2;
};
let i$1 = 0, __count = (name) => `${name}#${++i$1}`;
function pipe(...fns) {
return fns.reduce((acc, fn) => fn(acc), this);
}
function onChange(cb) {
var _a2;
const hook = (ctx2, patch) => cb(ctx2, patch.state);
return ((_a2 = this.__reatom).updateHooks ?? (_a2.updateHooks = /* @__PURE__ */ new Set())).add(hook), () => this.__reatom.updateHooks.delete(hook);
}
function onCall(cb) {
return this.onChange((ctx2, state) => {
const { params, payload } = state[state.length - 1];
cb(ctx2, payload, params);
});
}
function atom(initState2, name = __count("_atom")) {
let theAtom = (ctx2, update2) => ctx2.get((read, actualize) => actualize(ctx2, theAtom.__reatom, (patchCtx, patch) => {
patch.state = typeof update2 == "function" ? update2(patch.state, patchCtx) : update2;
}).state), computer = null;
return typeof initState2 == "function" && (theAtom = {}, computer = initState2, initState2 = void 0), theAtom.__reatom = {
name,
isAction: !1,
patch: null,
initState: () => initState2,
computer,
connectHooks: null,
disconnectHooks: null,
updateHooks: null,
actual: !1
}, theAtom.pipe = pipe, theAtom.onChange = onChange, experimental_PLUGINS.length === 0 ? theAtom : theAtom.pipe(...experimental_PLUGINS);
}
const action = (fn, name) => {
(fn === void 0 || typeof fn == "string") && (name = fn, fn = (ctx2, v) => v), assertFunction(fn);
let actionAtom = atom([], name ?? __count("_action"));
return actionAtom.__reatom.isAction = !0, actionAtom.__reatom.unstable_fn = fn, Object.assign((...params) => {
let state = actionAtom(params[0], (state$1, patchCtx) => (params[0] = patchCtx, [...state$1, {
params: params.slice(1),
payload: patchCtx.cause.proto.unstable_fn(...params)
}]));
return state[state.length - 1].payload;
}, actionAtom, { onCall });
}, experimental_PLUGINS = [], __root = atom(void 0, "root").__reatom, batch = (ctx2, cb) => ctx2.get(cb), noop = () => {
}, sleep = (ms = 0) => new Promise((r) => setTimeout$1(r, ms)), isObject = (thing) => typeof thing == "object" && thing !== null, isRec = (thing) => {
if (!isObject(thing)) return !1;
const proto = Reflect.getPrototypeOf(thing);
return !proto || !Reflect.getPrototypeOf(proto);
}, isShallowEqual = (a, b, is = Object.is) => {
if (Object.is(a, b)) return !0;
if (!isObject(a) || !isObject(b) || a.__proto__ !== b.__proto__ || a instanceof Error) return !1;
if (Symbol.iterator in a) {
let equal = a instanceof Map ? (a$1, b$1) => is(a$1[0], b$1[0]) && is(a$1[1], b$1[1]) : is, aIter = a[Symbol.iterator](), bIter = b[Symbol.iterator]();
for (; ; ) {
let aNext = aIter.next(), bNext = bIter.next();
if (aNext.done || bNext.done || !equal(aNext.value, bNext.value)) return aNext.done && bNext.done;
}
}
if (a instanceof Date) return a.getTime() === b.getTime();
if (a instanceof RegExp) return String(a) === String(b);
for (let k in a) if (!(k in b) || !is(a[k], b[k])) return !1;
return Object.keys(a).length === Object.keys(b).length;
}, assign = Object.assign, merge = (...a) => Object.assign({}, ...a), omit = (target, keys$1) => {
const result = {};
for (const key in target) keys$1.includes(key) || (result[key] = target[key]);
return result;
};
let _random = (min = 0, max = Number.MAX_SAFE_INTEGER - 1) => Math.floor(Math.random() * (max - min + 1)) + min;
const random = (min, max) => _random(min, max), { toString: toString$2 } = Object.prototype, { toString: toStringArray } = [], visited = /* @__PURE__ */ new WeakMap(), toStringKey = (thing, immutable = !0) => {
var _a2;
var tag = typeof thing;
if (tag === "symbol") return `[reatom Symbol]${thing.description || "symbol"}`;
if (tag !== "function" && (tag !== "object" || thing === null || thing instanceof Date || thing instanceof RegExp)) return `[reatom ${tag}]` + thing;
if (visited.has(thing)) return visited.get(thing);
var name = ((_a2 = Reflect.getPrototypeOf(thing)) == null ? void 0 : _a2.constructor.name) || toString$2.call(thing).slice(8, -1), result = `[reatom ${name}#${random()}]`;
if (tag === "function")
return visited.set(thing, result += thing.name), result;
visited.set(thing, result);
var proto = Reflect.getPrototypeOf(thing);
if (proto && Reflect.getPrototypeOf(proto) && thing.toString !== toStringArray && !(Symbol.iterator in thing)) return result;
var iterator = Symbol.iterator in thing ? thing : Object.entries(thing).sort(([a], [b]) => a.localeCompare(b));
for (let item of iterator) result += toStringKey(item, immutable);
return immutable ? visited.set(thing, result) : visited.delete(thing), result;
};
let i = 0;
const toAbortError = (reason) => {
if (!(reason instanceof Error) || reason.name !== "AbortError") {
if (reason instanceof Error) {
var options = { cause: reason };
reason = reason.message;
} else reason = isObject(reason) ? toString$2.call(reason) : String(reason);
reason += ` [${++i}]`, typeof DOMException > "u" ? (reason = new Error(reason, options), reason.name = "AbortError") : reason = assign(new DOMException(reason, "AbortError"), options);
}
return reason;
}, throwIfAborted = (controller) => {
if (controller != null && controller.signal.aborted) throw toAbortError(controller.signal.reason);
}, isAbort = (thing) => thing instanceof Error && thing.name === "AbortError", setTimeout$1 = Object.assign((...a) => {
const intervalId = globalThis.setTimeout(...a);
return typeof intervalId == "number" ? intervalId : Object.assign(intervalId, { toJSON() {
return -1;
} });
}, globalThis.setTimeout), MAX_SAFE_TIMEOUT = 2 ** 31 - 1;
var CauseContext = class extends WeakMap {
has(cause) {
return super.has(cause) || cause.cause !== null && this.has(cause.cause);
}
get(cause) {
for (; !super.has(cause) && cause.cause; ) cause = cause.cause;
return super.get(cause);
}
};
const abortCauseContext = new CauseContext(), getTopController = (patch) => abortCauseContext.get(patch) ?? null, onCtxAbort = (ctx2, cb) => {
const controller = getTopController(ctx2.cause);
if (controller) {
const handler = () => cb(toAbortError(controller.signal.reason)), cleanup = () => controller.signal.removeEventListener("abort", handler);
if (controller.signal.aborted) handler();
else
return controller.signal.addEventListener("abort", handler), cleanup;
}
}, CHAINS = /* @__PURE__ */ new WeakMap(), __thenReatomed = (ctx2, origin, onFulfill, onReject) => {
let chain = CHAINS.get(origin);
if (!chain) {
const promise = origin.then((value) => (ctx2.get((read, actualize) => chain.then.forEach((cb) => cb(value, read, actualize))), value), (error) => {
throw ctx2.get((read, actualize) => chain.catch.forEach((cb) => cb(error, read, actualize))), isAbort(error) && promise.catch(noop), error;
});
CHAINS.set(origin, chain = {
promise,
then: [],
catch: []
}), CHAINS.set(promise, chain);
}
return onFulfill && chain.then.push(onFulfill), onReject && chain.catch.push(onReject), chain.promise;
}, skip = Symbol(), take = (ctx2, anAtom, mapper = (ctx$12, v) => v, name) => {
name && (name = `${ctx2.cause.proto.name}.${name}`);
const cleanups = [];
return name && action(name)(ctx2), new Promise((res, rej) => {
cleanups.push(onCtxAbort(ctx2, rej) ?? noop, ctx2.subscribe(anAtom, async (state) => {
if (cleanups.length)
try {
anAtom.__reatom.isAction && (state = state[0].payload);
const value = await state, result = mapper(ctx2, value, skip);
result !== skip && (res(result), name && action(`${name}.resolve`)(ctx2, result));
} catch (error) {
rej(error), name && action(`${name}.reject`)(ctx2, error);
}
}));
}).finally(() => cleanups.forEach((cb) => cb()));
}, _isCausedBy = (cause, proto) => cause.cause !== null && (cause.cause.proto === proto || isCausedBy(cause.cause, proto)), isCausedBy = (caused, by) => _isCausedBy("subscribe" in caused ? caused.cause : caused, "__reatom" in by ? by.__reatom : by), withAbortableSchedule = (ctx2) => {
const { schedule } = ctx2;
return merge(ctx2, { schedule(cb, step = 1) {
if (step < 1) return schedule.call(this, cb, step);
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res, reject = rej;
}), unabort = onCtxAbort(this, (error) => {
promise.catch(noop), reject(error);
});
return schedule.call(this, async (_ctx) => {
try {
const controller = getTopController(this.cause);
throwIfAborted(controller);
const value = await cb(_ctx);
throwIfAborted(controller), resolve(value);
} catch (error) {
reject(error);
}
unabort == null || unabort();
}, step).catch((error) => {
reject(error), unabort == null || unabort();
}), promise;
} });
}, concurrentControllers = /* @__PURE__ */ new WeakMap(), concurrent = (fn, strategy = "last-in-win") => {
const abortControllerAtom = atom(null, `${__count("_concurrent")}.abortControllerAtom`), target = action((ctx2, topCtx, ...a) => {
const prevController = ctx2.get(abortControllerAtom), controller = new AbortController(), abort = toAbortError("concurrent " + ctx2.cause.proto.name);
if (strategy === "first-in-win") if (prevController) {
const rej = Promise.reject(abort);
return rej.catch(noop), rej;
} else abortControllerAtom(ctx2, controller);
strategy === "last-in-win" && (abortControllerAtom(ctx2, controller), prevController == null || prevController.abort(abort));
const unabort = onCtxAbort(topCtx, (error) => {
error !== abort && (result$1 instanceof Promise && result$1.catch(noop), controller.abort(error));
});
abortCauseContext.set(ctx2.cause, controller);
var result$1 = fn(withAbortableSchedule({
...ctx2,
spy: topCtx.spy
}), ...a);
return result$1 instanceof Promise ? (result$1 = result$1.finally(() => {
strategy === "first-in-win" && abortControllerAtom(ctx2, null), unabort == null || unabort(), controller.signal.aborted && result$1.catch(noop);
}), controller.signal.addEventListener("abort", () => {
result$1.catch(noop);
})) : throwReatomError(strategy === "first-in-win", `can't apply "first-in-win" strategy for non-async function`), result$1;
}, isAtom(fn) ? `${fn.__reatom.name}._concurrent` : __count("_concurrent")), result = Object.assign(
(ctx2, ...a) => target(ctx2, ctx2, ...a),
target,
// if the `fn` is an atom we need to assign all related properties
fn
);
return concurrentControllers.set(result, abortControllerAtom), result;
};
action((ctx2, fn, controller, ...args) => (abortCauseContext.set(ctx2.cause, controller), fn(ctx2, ...args)), "_spawn");
const getRootCause = (cause) => cause.cause === null ? cause : getRootCause(cause.cause), isSameCtx = (ctx1, ctx2) => getRootCause(ctx1.cause) === getRootCause(ctx2.cause), addOnConnect = (anAtom, cb) => {
var _a2;
return ((_a2 = anAtom.__reatom).connectHooks ?? (_a2.connectHooks = /* @__PURE__ */ new Set())).add(cb);
}, addOnDisconnect = (anAtom, cb) => {
var _a2;
return ((_a2 = anAtom.__reatom).disconnectHooks ?? (_a2.disconnectHooks = /* @__PURE__ */ new Set())).add(cb);
}, withInit = (createState) => (anAtom) => {
const { initState: initState2, isAction: isAction2 } = anAtom.__reatom;
return throwReatomError(isAction2, "action state is not manageable"), anAtom.__reatom.initState = (ctx2) => createState(ctx2, initState2), anAtom;
}, _onConnect = action((ctx2, anAtom, fn, controller) => {
ctx2.cause.cause = getRootCause(ctx2.cause), abortCauseContext.set(ctx2.cause, controller);
const result = fn(withAbortableSchedule({
...ctx2,
controller,
isConnected: () => isConnected(ctx2, anAtom)
}));
return result instanceof Promise && controller.signal.addEventListener("abort", () => result.catch(noop)), result;
}, "_onConnect"), onConnect = (anAtom, cb) => {
const connectHook = (ctx2) => {
const controller = new AbortController(), cleanup = _onConnect(ctx2, anAtom, cb, controller);
cleanup instanceof Promise && cleanup.catch(noop);
const cleanupHook = (_ctx) => {
isSameCtx(ctx2, _ctx) && disconnectHooks.delete(cleanupHook) && connectHooks.has(connectHook) && (controller.abort(toAbortError("disconnect " + anAtom.__reatom.name)), typeof cleanup == "function" && cleanup());
}, disconnectHooks = addOnDisconnect(anAtom, cleanupHook);
}, connectHooks = addOnConnect(anAtom, connectHook);
return () => connectHooks.delete(connectHook);
}, isConnected = (ctx2, { __reatom: proto }) => ctx2.get((read) => {
const cache = proto.patch ?? read(proto);
return !!cache && cache.subs.size + cache.listeners.size > 0;
}), initializations = atom(null, "initializations");
initializations.__reatom.initState = () => /* @__PURE__ */ new WeakMap();
const withAssign = (getProps) => (target) => assign(target, getProps(target, target.__reatom.name)), reatomBoolean = (init = !1, name) => atom(init, name).pipe(withAssign((target, name$1) => ({
toggle: action((ctx2) => target(ctx2, (prev) => !prev), `${name$1}.toggle`),
setTrue: action((ctx2) => target(ctx2, !0), `${name$1}.setTrue`),
setFalse: action((ctx2) => target(ctx2, !1), `${name$1}.setFalse`),
reset: action((ctx2) => target(ctx2, init), `${name$1}.reset`)
}))), reatomEnum = (variants, options = {}) => {
const { name, format: format2 = "camelCase", initState: initState2 = variants[0] } = typeof options == "string" ? { name: options } : options, stateAtom = atom(initState2, name), enumAtom = Object.assign((ctx2, update2) => {
const state = stateAtom(ctx2, update2);
return throwReatomError(!variants.includes(state), `invalid enum value "${state}" for "${name}" enum`), state;
}, stateAtom), cases = enumAtom.enum = {};
enumAtom.reset = action((ctx2) => enumAtom(ctx2, initState2), `${name}.reset`);
for (const variant of variants) {
cases[variant] = variant;
const setterName = variant.replace(/^./, (firstLetter) => "set" + (format2 === "camelCase" ? firstLetter.toUpperCase() : `_${firstLetter}`));
enumAtom[setterName] = action((ctx2) => enumAtom(ctx2, variant), `${name}.${setterName}`);
}
return enumAtom;
}, reatomMap = (initState2 = /* @__PURE__ */ new Map(), name) => {
const atomInitState = initState2 instanceof Map ? initState2 : new Map(initState2);
return atom(atomInitState, name).pipe(withAssign((target, name$1) => {
const getOrCreate = action((ctx2, key, value) => (actions.set(ctx2, key, value), value), `${name$1}.getOrCreate`), actions = {
get: (ctx2, key) => ctx2.get(target).get(key),
getOrCreate: (ctx2, key, creator) => actions.has(ctx2, key) ? actions.get(ctx2, key) : getOrCreate(ctx2, key, creator()),
has: (ctx2, key) => ctx2.get(target).has(key),
set: action((ctx2, key, value) => target(ctx2, (prev) => {
const valuePrev = prev.get(key);
return Object.is(valuePrev, value) && (value !== void 0 || prev.has(key)) ? prev : new Map(prev).set(key, value);
}), `${name$1}.set`),
delete: action((ctx2, key) => target(ctx2, (prev) => {
if (!prev.has(key)) return prev;
const next = new Map(prev);
return next.delete(key), next;
}), `${name$1}.delete`),
clear: action((ctx2) => target(ctx2, /* @__PURE__ */ new Map()), `${name$1}.clear`),
reset: action((ctx2) => target(ctx2, atomInitState), `${name$1}.reset`),
sizeAtom: atom((ctx2) => ctx2.spy(target).size, `${name$1}.size`)
};
return actions;
}));
}, readonly = (anAtom) => ({ ...anAtom }), LL_PREV = Symbol("Reatom linked list prev"), LL_NEXT = Symbol("Reatom linked list next"), addLL = (state, node, after) => {
node !== after && (after ? (node[LL_PREV] = after, node[LL_NEXT] = after[LL_NEXT], after[LL_NEXT] = node, state.tail === after && (state.tail = node)) : (node[LL_PREV] = null, node[LL_NEXT] = state.head, state.head && (state.head[LL_PREV] = node), state.tail || (state.tail = node), state.head = node), state.size++);
}, removeLL = (state, node) => {
state.head === node ? state.head = node[LL_NEXT] : node[LL_PREV] !== null && (node[LL_PREV][LL_NEXT] = node[LL_NEXT]), state.tail === node ? state.tail = node[LL_PREV] : node[LL_NEXT] !== null && (node[LL_NEXT][LL_PREV] = node[LL_PREV]), node[LL_PREV] = null, node[LL_NEXT] = null, state.size--;
}, swapLL = (state, a, b) => {
if (a === b) return;
if (state.head === b) return swapLL(state, b, a);
const prevA = a[LL_PREV], nextA = a[LL_NEXT], prevB = b[LL_PREV], nextB = b[LL_NEXT];
nextA === b ? (a[LL_NEXT] = nextB, b[LL_PREV] = prevA, b[LL_NEXT] = a, a[LL_PREV] = b, nextB && (nextB[LL_PREV] = a), prevA && (prevA[LL_NEXT] = b)) : nextB === a ? (b[LL_NEXT] = nextA, a[LL_PREV] = prevB, a[LL_NEXT] = b, b[LL_PREV] = a, nextA && (nextA[LL_PREV] = b), prevB && (prevB[LL_NEXT] = a)) : (prevA && (prevA[LL_NEXT] = b), nextA && (nextA[LL_PREV] = b), prevB && (prevB[LL_NEXT] = a), nextB && (nextB[LL_PREV] = a), a[LL_PREV] = prevB, a[LL_NEXT] = nextB, b[LL_PREV] = prevA, b[LL_NEXT] = nextA), state.head === a ? state.head = b : state.head === b && (state.head = a), state.tail === a ? state.tail = b : state.tail === b && (state.tail = a);
}, moveLL = (state, node, after) => {
removeLL(state, node), addLL(state, node, after);
}, clearLL = (state) => {
for (; state.tail; ) removeLL(state, state.tail);
}, toArray = (head, prev) => {
let arr = [], i2 = 0;
for (; head; )
prev !== void 0 && prev[i2] !== head && (prev = void 0), arr.push(head), head = head[LL_NEXT], i2++;
return arr.length === (prev == null ? void 0 : prev.length) ? prev : arr;
};
function reatomLinkedList(options, name = __count("reatomLinkedList")) {
const { create: userCreate = (ctx2, ...params) => params[0], key = void 0, ...restOptions } = typeof options == "function" ? { create: options } : Array.isArray(options) ? {
create: (ctx2, ...params) => params[0],
initState: options
} : options, _name = name, isLL = (node) => !!node && LL_NEXT in node && LL_PREV in node, throwModel = (node) => throwReatomError(isLL(node), "The data is already in a linked list."), throwNotModel = (node) => throwReatomError(!isLL(node), "The passed data is not a linked list node.");
let STATE = null;
const linkedList = atom(STATE, name);
linkedList.__reatom.initState = (ctx2) => {
try {
return "initState" in restOptions ? createLinkedList(restOptions.initState ?? []) : "initSnapshot" in restOptions ? createLinkedList(ctx2, restOptions.initSnapshot ?? []) : createLinkedList([]);
} finally {
STATE = null;
}
};
const createLinkedList = (ctxOrInitState, initSnapshot) => {
const initState2 = Array.isArray(ctxOrInitState) ? ctxOrInitState : initSnapshot.map((params) => userCreate(ctxOrInitState, ...params)), state = {
size: 0,
version: 1,
changes: [],
head: null,
tail: null
};
for (const node of initState2)
throwModel(node), addLL(state, node, state.tail);
return state;
}, batchFn = (ctx2, cb) => {
if (STATE) return cb(ctx2);
STATE = linkedList(ctx2, ({ head, tail, size, version: version2 }) => ({
size,
version: version2 + 1,
changes: [],
head,
tail
}));
try {
return cb(ctx2);
} finally {
STATE = null;
}
}, batch2 = action(batchFn, `${name}._batch`), create2 = action((ctx2, ...params) => batchFn(ctx2, () => {
const node = userCreate(ctx2, ...params);
return throwReatomError(!isObject(node) && typeof node != "function", `reatomLinkedList can operate only with objects or functions, received "${node}".`), throwModel(node), addLL(STATE, node, STATE.tail), STATE.changes.push({
kind: "create",
node
}), node;
}), `${name}.create`), remove = action((ctx2, node) => batchFn(ctx2, () => (throwNotModel(node), node[LL_PREV] === null && node[LL_NEXT] === null && STATE.tail !== node ? !1 : (removeLL(STATE, node), STATE.changes.push({
kind: "remove",
node
}), !0))), `${name}.remove`), swap = action((ctx2, a, b) => batchFn(ctx2, () => {
throwNotModel(a), throwNotModel(b), a !== b && (swapLL(STATE, a, b), STATE.changes.push({
kind: "swap",
a,
b
}));
}), `${name}.swap`), move = action((ctx2, node, after) => batchFn(ctx2, () => {
throwNotModel(node), moveLL(STATE, node, after), STATE.changes.push({
kind: "move",
node,
after
});
}), `${name}.move`), clear = action((ctx2) => batchFn(ctx2, () => {
clearLL(STATE), STATE.changes.push({ kind: "clear" });
}), `${name}.clear`), find = (ctx2, cb) => {
for (let { head } = ctx2.get(linkedList); head; head = head[LL_NEXT]) if (cb(head)) return head;
return null;
}, array = atom((ctx2, state = []) => toArray(ctx2.spy(linkedList).head, state), `${name}.array`), map = key ? atom((ctx2) => new Map(
// use array as it already memoized and simplifies the order tracking
ctx2.spy(array).map((node) => {
const keyValue = node[key];
return [isAtom(keyValue) ? ctx2.spy(keyValue) : keyValue, node];
})
)) : void 0;
return Object.assign(linkedList, {
batch: batch2,
create: create2,
remove,
swap,
move,
clear,
find,
array,
map,
initiate: createLinkedList,
reatomMap: (cb, options$1 = {}) => {
const { name: name$1 = __count(`${_name}.reatomMap`), ...hooks } = typeof options$1 == "string" ? { name: options$1 } : options$1, mapList = atom((ctx2, mapList$1) => {
var _a2, _b2, _c, _d, _e, _f, _g;
throwReatomError(STATE, "Can't compute the map of the linked list inside the batching.");
const ll = ctx2.spy(linkedList);
if (!mapList$1 || ll.version - 1 > mapList$1.version) {
mapList$1 && ((_a2 = hooks.onClear) == null || _a2.call(hooks, ctx2, mapList$1)), mapList$1 = {
size: ll.size,
version: ll.version,
changes: [],
head: null,
tail: null,
map: /* @__PURE__ */ new WeakMap()
};
for (let head = ll.head; head; head = head[LL_NEXT]) {
const node = cb(ctx2, head);
addLL(mapList$1, node, mapList$1.tail), mapList$1.map.set(head, node), (_b2 = hooks.onCreate) == null || _b2.call(hooks, ctx2, node);
}
mapList$1.size = ll.size;
} else {
mapList$1 = {
head: mapList$1.head,
tail: mapList$1.tail,
size: mapList$1.size,
version: ll.version,
changes: [],
map: mapList$1.map
};
for (const change of ll.changes) switch (change.kind) {
case "create": {
const node = cb(ctx2, change.node);
addLL(mapList$1, node, mapList$1.tail), mapList$1.map.set(change.node, node), mapList$1.changes.push({
kind: "create",
node
}), (_c = hooks.onCreate) == null || _c.call(hooks, ctx2, node);
break;
}
case "remove": {
const node = mapList$1.map.get(change.node);
removeLL(mapList$1, node), mapList$1.map.delete(change.node), mapList$1.changes.push({
kind: "remove",
node
}), (_d = hooks.onRemove) == null || _d.call(hooks, ctx2, node, change.node);
break;
}
case "swap": {
const a = mapList$1.map.get(change.a), b = mapList$1.map.get(change.b);
swapLL(mapList$1, a, b), mapList$1.changes.push({
kind: "swap",
a,
b
}), (_e = hooks.onSwap) == null || _e.call(hooks, ctx2, {
a,
b
});
break;
}
case "move": {
const node = mapList$1.map.get(change.node), after = change.after ? mapList$1.map.get(change.after) : null;
moveLL(mapList$1, node, after), mapList$1.changes.push({
kind: "move",
node,
after
}), (_f = hooks.onMove) == null || _f.call(hooks, ctx2, node);
break;
}
case "clear": {
(_g = hooks.onClear) == null || _g.call(hooks, ctx2, mapList$1), clearLL(mapList$1), mapList$1.changes.push({ kind: "clear" });
break;
}
default: {
const kind = change;
throw new Error(`Unhandled linked list change "${kind}"`);
}
}
}
return throwReatomError(mapList$1.size !== ll.size, "Inconsistent linked list, is's a bug, please report an issue"), mapList$1;
}, name$1), array$1 = atom((ctx2, state = []) => toArray(ctx2.spy(mapList).head, state), `${name$1}.array`);
return Object.assign(mapList, {
array: array$1,
__reatomLinkedList: !0
});
},
__reatomLinkedList: !0
}).pipe(readonly);
}
const isLinkedListAtom = (thing) => (thing == null ? void 0 : thing.__reatomLinkedList) === !0, reatomNumber = (initState2 = 0, name) => atom(initState2, name).pipe(withAssign((target, name$1) => ({
increment: action((ctx2, by = 1) => target(ctx2, (prev) => prev + by), `${name$1}.increment`),
decrement: action((ctx2, by = 1) => target(ctx2, (prev) => prev - by), `${name$1}.decrement`),
random: action((ctx2) => target(ctx2, Math.random()), `${name$1}.decrement`),
reset: action((ctx2) => target(ctx2, initState2), `${name$1}.reset`)
}))), reatomRecord = (initState2, name) => atom(initState2, name).pipe(withAssign((target) => ({
merge: action((ctx2, slice) => target(ctx2, (prev) => {
for (const key in prev) if (!Object.is(prev[key], slice[key])) return {
...prev,
...slice
};
return prev;
}), `${name}.merge`),
omit: action((ctx2, ...keys) => target(ctx2, (prev) => keys.some((key) => key in prev) ? omit(prev, keys) : prev), `${name}.omit`),
reset: action((ctx2, ...keys) => target(ctx2, (prev) => {
if (keys.length === 0) return initState2;
const next = {};
let changed = !1;
for (const key in prev) keys.includes(key) ? key in initState2 ? (next[key] = initState2[key], changed || (changed = !Object.is(prev[key], initState2[key]))) : changed || (changed = key in prev) : next[key] = prev[key];
return changed ? next : prev;
}), `${name}.reset`)
}))), reatomSet = (initState2 = /* @__PURE__ */ new Set(), name) => {
const atomInitState = initState2 instanceof Set ? initState2 : new Set(initState2);
return atom(atomInitState, name).pipe(withAssign((target, name$1) => ({
add: action((ctx2, el) => target(ctx2, (prev) => prev.has(el) ? prev : new Set(prev).add(el)), `${name$1}.add`),
set: action((ctx2, el) => target(ctx2, (prev) => prev.has(el) ? prev : new Set(prev).add(el)), `${name$1}.set`),
delete: action((ctx2, el) => target(ctx2, (prev) => {
if (!prev.has(el)) return prev;
const next = new Set(prev);
return next.delete(el), next;
}), `${name$1}.delete`),
clear: action((ctx2) => target(ctx2, (prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Set()), `${name$1}.clear`),
reset: action((ctx2) => target(ctx2, atomInitState), `${name$1}.reset`),
intersection: action((ctx2, set2) => target(ctx2, (prev) => prev.intersection(set2)), `${name$1}.intersection`),
union: action((ctx2, set2) => target(ctx2, (prev) => prev.union(set2)), `${name$1}.union`),
difference: action((ctx2, set2) => target(ctx2, (prev) => prev.difference(set2)), `${name$1}.difference`),
symmetricDifference: action((ctx2, set2) => target(ctx2, (prev) => prev.symmetricDifference(set2)), `${name$1}.symmetricDifference`),
toggle: action((ctx2, el) => target(ctx2, (prev) => {
if (!prev.has(el)) return new Set(prev).add(el);
const next = new Set(prev);
return next.delete(el), next;
}), `${name$1}.toggle`),
has: (ctx2, el) => ctx2.get(target).has(el),
isSubsetOf: (ctx2, set2) => ctx2.get(target).isSubsetOf(set2),
isSupersetOf: (ctx2, set2) => ctx2.get(target).isSupersetOf(set2),
isDisjointFrom: (ctx2, set2) => ctx2.get(target).isDisjointFrom(set2),
size: (ctx2) => ctx2.get(target).size,
sizeAtom: atom((ctx2) => ctx2.spy(target).size, `${name$1}.size`)
})));
}, withComputed = (computed) => (anAtom) => {
const prevComputed = anAtom.__reatom.computer;
return anAtom.__reatom.computer = (ctx2, state) => (prevComputed && (state = prevComputed(ctx2, state)), computed(ctx2, state)), anAtom;
}, handleEffect = (anAsync, params, { shouldPending = !0, shouldFulfill = !0, shouldReject = !0, effect = anAsync.__reatom.unstable_fn } = {}) => {
const pendingAtom = anAsync.pendingAtom, [ctx2] = params;
shouldPending && pendingAtom(ctx2, (s) => ++s);
const origin = ctx2.schedule(() => new Promise((res, rej) => {
throwIfAborted(ctx2.controller), effect(...params).then(res, rej), ctx2.controller.signal.addEventListener("abort", () => rej(toAbortError(ctx2.controller.signal.reason)));
}));
return assign(__thenReatomed(ctx2, origin, (v) => {
shouldFulfill && anAsync.onFulfill(ctx2, v), shouldPending && pendingAtom(ctx2, (s) => --s);
}, (e) => {
shouldReject && !isAbort(e) && anAsync.onReject(ctx2, e), shouldPending && pendingAtom(ctx2, (s) => --s);
}), { controller: ctx2.controller });
}, resolved = /* @__PURE__ */ new WeakSet(), reatomResource = (asyncComputed, name = __count("asyncAtom")) => {
const promises = new CauseContext(), theAsync = reatomAsync((ctx2) => {
const promise = promises.get(ctx2.cause);
return throwReatomError(!promise, "reaction manual call"), promise;
}, name), promiseAtom = atom((_ctx, state) => {
if (state && !_ctx.cause.pubs.length) return state;
const params = [], ctx2 = merge(_ctx, { spy(anAtom, cb) {
throwReatomError(cb, "spy reactions are unsupported in ResourceAtom");
const value = _ctx.spy(anAtom);
return params.push(value), value;
} }), abortError = toAbortError("concurrent " + name), controller = new AbortController(), unabort = onCtxAbort(ctx2, (error) => {
abortError !== error && !isConnected(ctx2, theReaction) && controller.abort(error);
});
unabort && controller.signal.addEventListener("abort", unabort), abortCauseContext.set(ctx2.cause, ctx2.controller = controller);
const computedPromise = asyncComputed(withAbortableSchedule(ctx2));
computedPromise.catch(noop), promises.set(ctx2.cause, computedPromise);
const pendingBefore = ctx2.get(theAsync.pendingAtom), fulfillCallsBefore = ctx2.get(theAsync.onFulfill);
let promise = theAsync(
ctx2,
...params
);
promise.controller.signal.addEventListener("abort", () => {
var _a2;
(_a2 = theReaction.cacheAtom) != null && _a2.options.ignoreAbort || controller.abort(promise.controller.signal.reason);
});
const cached = pendingBefore === ctx2.get(theAsync.pendingAtom), fulfillCalls = ctx2.get(theAsync.onFulfill);
return cached && controller.abort(toAbortError("cached " + name)), cached && fulfillCallsBefore !== fulfillCalls && (promise = Object.assign(Promise.resolve(fulfillCalls[fulfillCalls.length - 1].payload), { controller })), __thenReatomed(ctx2, promise, () => resolved.add(promise), () => resolved.add(promise)).catch(noop), state == null || state.controller.abort(abortError), promise;
}, `${name}._promiseAtom`);
onConnect(theAsync, (ctx2) => ctx2.subscribe(promiseAtom, noop)), onConnect(promiseAtom, (ctx2) => () => {
ctx2.get((read) => {
var _a2;
const state = (_a2 = read(promiseAtom.__reatom)) == null ? void 0 : _a2.state;
state == null || state.controller.abort(ctx2.controller.signal.reason), resolved.has(state) || reset(ctx2, promiseAtom.__reatom, ctx2.controller.signal.reason);
});
});
const theReaction = Object.assign((ctx2) => ctx2.get((read, actualize) => {
var _a2;
reset(ctx2, promiseAtom.__reatom, toAbortError("force " + name)), actualize(ctx2, promiseAtom.__reatom, noop);
const state = ctx2.get(theAsync), payload = (_a2 = state[state.length - 1]) == null ? void 0 : _a2.payload;
return throwReatomError(!payload, "unexpectedly failed invalidation. Please, report the issue"), payload;
}), theAsync, {
promiseAtom,
init(ctx2) {
return ctx2.subscribe(promiseAtom, noop);
},
reset: action((ctx2) => {
reset(ctx2, promiseAtom.__reatom, toAbortError("reset " + name));
}, `${name}.reset`)
});
return Object.defineProperty(theAsync, "_handleCache", { get() {
return theReaction._handleCache;
} }), theReaction;
}, reset = (ctx2, proto, reason) => ctx2.get((read, actualize) => {
if (read(proto)) {
const { computer } = proto;
proto.computer = null;
try {
actualize(ctx2, proto, (patchCtx, patch) => {
var _a2;
(_a2 = patch.state) == null || _a2.controller.abort(reason), patch.pubs = [], patch.state = void 0;
});
} finally {
proto.computer = computer;
}
}
}), reatomAsync = (effect, options = {}) => {
const { name = __count("async"), onEffect: onEffectHook, onFulfill: onFulfillHook, onReject: onRejectHook, onSettle: onSettleHook } = typeof options == "string" ? { name: options } : options, pendingAtom = atom(0, `${name}.pendingAtom`), theAsync = Object.assign(
// do not put this function inside `action` to not broke effect mocking
(...params) => params[0].get((read, actualize) => {
const { state } = actualize(params[0], theAsync.__reatom, (ctx2, patch) => {
abortCauseContext.set(ctx2.cause, ctx2.controller = new AbortController());
const unabort = onCtxAbort(params[0], (error) => {
payload == null || payload.catch(noop), ctx2.controller.abort(error);
});
unabort && ctx2.controller.signal.addEventListener("abort", unabort), params[0] = withAbortableSchedule(ctx2);
var payload = theAsync._handleCache ? theAsync._handleCache(...params) : handleEffect(theAsync, params);
__thenReatomed(ctx2, payload, void 0, () => {
onReject.__reatom.updateHooks.size > 1 && payload.catch(noop);
}), patch.state = [...patch.state, {
params: params.slice(1),
payload
}];
});
return state[state.length - 1].payload;
}),
action(
// @ts-expect-error TODO need a better way to pass a custom Ctx.
effect,
name
)
), onFulfill = action(`${name}.onFulfill`), onReject = action(`${name}.onReject`), onSettle = action(`${name}._onSettle`);
return onFulfill.onCall((ctx2) => onSettle(ctx2)), onReject.onCall((ctx2) => onSettle(ctx2)), onEffectHook && theAsync.onCall((ctx2, promise, params) => onEffectHook(ctx2, params, promise)), onFulfillHook && onFulfill.onCall(onFulfillHook), onRejectHook && onReject.onCall(onRejectHook), onSettleHook && onSettle.onCall(onSettleHook), onConnect(pendingAtom, (ctx2) => ctx2.subscribe(theAsync, noop)), assign(theAsync, {
onFulfill,
onReject,
onSettle,
pendingAtom
});
};
reatomAsync.from = (effect, options = {}) => (effect.name.length > 2 && (typeof options == "object" ? options.name ?? (options.name = effect.name) : options ?? (options = effect.name)), reatomAsync((ctx2, ...a) => effect(...a), options));
const withDataAtom = (initState2, mapFulfill) => (anAsync) => {
if (!anAsync.dataAtom) {
const dataAtom = anAsync.dataAtom = Object.assign(atom(initState2, `${anAsync.__reatom.name}.dataAtom`), {
reset: action((ctx2) => {
dataAtom(ctx2, initState2);
}, `${anAsync.__reatom.name}.dataAtom.reset`),
mapFulfill
});
dataAtom.__reatom.computer = (ctx2, state) => (ctx2.spy(anAsync.onFulfill, ({ payload }) => {
state = payload;
}), state), anAsync.onFulfill.onCall((ctx2) => {
ctx2.get(dataAtom);
}), onConnect(dataAtom, (ctx2) => ctx2.subscribe(anAsync, noop));
}
return anAsync;
}, ctxMap = /* @__PURE__ */ new WeakMap(), bind = (ctx2, fn) => {
let fnMap = ctxMap.get(ctx2);
fnMap || ctxMap.set(ctx2, fnMap = /* @__PURE__ */ new WeakMap());
let bfn = fnMap.get(fn);
return bfn || fnMap.set(fn, bfn = fn.bind(null, ctx2)), bfn;
}, parseAtoms = (ctx2, value) => {
if (isAction(value)) return value;
for (isLinkedListAtom(value) && (value = value.array); isAtom(value); ) value = ctx2.spy ? ctx2.spy(value) : ctx2.get(value);
if (typeof value != "object" || value === null) return value;
if (isRec(value)) {
const res = {};
for (const k in value) res[k] = parseAtoms(ctx2, value[k]);
return res;
}
if (Array.isArray(value)) {
const res = [];
for (const v of value) res.push(parseAtoms(ctx2, v));
return res;
}
if (value instanceof Map) {
const res = /* @__PURE__ */ new Map();
for (const [k, v] of value) res.set(k, parseAtoms(ctx2, v));
return res;
}
if (value instanceof Set) {
const res = /* @__PURE__ */ new Set();
for (const v of value) res.add(parseAtoms(ctx2, v));
return res;
}
return value;
}, mapAtom = atom(null, "select._map");
mapAtom.__reatom.initState = () => /* @__PURE__ */ new WeakMap();
const touchedMap = /* @__PURE__ */ new WeakMap(), select = (ctx2, cb, equal = () => !1) => {
let touched = touchedMap.get(ctx2);
touched || touchedMap.set(ctx2, touched = /* @__PURE__ */ new Set());
const map = ctx2.get(mapAtom);
let atoms = map.get(ctx2.cause.proto);
atoms || map.set(ctx2.cause.proto, atoms = /* @__PURE__ */ new Map());
const selectSource = cb.toString();
throwReatomError(touched.has(selectSource), 'multiple select with the same "toString" representation is not allowed'), touched.add(selectSource);
let selectAtom = atoms.get(selectSource);
if (!selectAtom) {
let isInit = !0;
atoms.set(selectSource, selectAtom = atom((ctx$12, prevState) => {
const newState = cb(ctx$12), resultState = isInit || !equal(prevState, newState) ? newState : prevState;
return isInit = !1, resultState;
}, __count(`${ctx2.cause.proto.name}._select`)));
}
return ctx2.spy(selectAtom);
}, reatomPersist = (storage) => {
const storageAtom = atom(storage, `storageAtom#${storage.name}`);
return Object.assign((options) => (anAtom) => {
const { key, fromSnapshot = (ctx2, data) => data, migration, subscribe = !!storage.subscribe, time = MAX_SAFE_TIMEOUT, toSnapshot = (ctx2, data) => data, version: version2 = 0 } = typeof options == "string" ? { key: options } : options, proto = anAtom.__reatom, { initState: initState2, isAction: isAction2 } = proto;
throwReatomError(isAction2, "cannot apply persist to an action");
const getPersistRecord = (ctx2, state = null) => {
const rec = ctx2.get(storageAtom).get(ctx2, key);
return (rec == null ? void 0 : rec.id) === (state == null ? void 0 : state.id) ? state : rec ?? state;
}, fromPersistRecord = (ctx2, rec = getPersistRecord(ctx2), state) => rec === null || rec.version !== version2 && migration === void 0 ? initState2(ctx2) : fromSnapshot(ctx2, rec.version !== version2 ? migration(ctx2, rec) : rec.data, state), toPersistRecord = (ctx2, state) => ({
data: toSnapshot(ctx2, state),
fromState: !0,
id: random(),
timestamp: Date.now(),
to: Date.now() + time,
version: version2
});
throwReatomError(!key, "missed key");
const persistRecordAtom = atom(null, `${anAtom.__reatom.name}._${storage.name}Atom`);
if (persistRecordAto