🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@plitzi/nexus

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@plitzi/nexus - npm Package Compare versions

Comparing version
0.32.5
to
0.32.6
+11
dist/devStoreRegistry.d.ts
import { StoreApi } from './types';
export type DevStore = StoreApi<Record<string, unknown>>;
export type DevStoreEntry = {
uid: string;
store: DevStore;
scopeId?: string;
name?: string;
};
export declare const registerDevStore: (store: StoreApi<any>, scopeId?: string, name?: string) => (() => void);
export declare const subscribeDevStores: (listener: () => void) => (() => void);
export declare const getDevStoresSnapshot: () => ReadonlyArray<DevStoreEntry>;
//#region src/devStoreRegistry.ts
var e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set(), n = 0, r = [], i = () => {
r = [...e.values()];
for (let e of t) e();
}, a = (t, r, a) => {
let o = t;
return e.set(o, {
uid: `dev-store-${++n}`,
store: o,
scopeId: r,
name: a
}), i(), () => {
e.delete(o), i();
};
}, o = (e) => (t.add(e), () => {
t.delete(e);
}), s = () => r;
//#endregion
export { s as getDevStoresSnapshot, a as registerDevStore, o as subscribeDevStores };
declare const DevStoreScopeContext: import('react').Context<string | undefined>;
export default DevStoreScopeContext;
import { createContext as e } from "react";
//#region src/react/DevStoreScopeContext.ts
var t = e(void 0);
t.displayName = "DevStoreScopeContext";
//#endregion
export { t as default };
+13
-0
# @plitzi/nexus
## 0.32.6
### Patch Changes
- v0.32.6
## 0.32.5

@@ -43,2 +49,9 @@

Astro 7, Vue and Svelte.
- **`unmount` write option.** Every write now takes an optional third argument `SetStateOptions = { canPropagate?;
unmount? }`. `set(path, undefined, { unmount: true })` **deletes** the key at `path` (splicing array indices) instead
of leaving a dead `undefined`, so registries keyed by dynamic id leave no stale entries. Nested deletes keep siblings
with structural sharing, interceptors can veto them, and writing a value back recreates the path.
- **Read-only paths.** `createStore(init, { readOnly: [...] })` freezes paths: a write to a read-only path — or to an
ancestor/descendant of one — throws in development and no-ops in production. Prefix-safe matching, enforced per scope
on that scope's own writes, zero cost when unused.

@@ -45,0 +58,0 @@ ### Breaking Changes

+1
-0

@@ -8,2 +8,3 @@ import { GetState, SetState, StoreApi, StoreMiddleware } from '../types';

middlewares?: StoreMiddleware<TState>[];
readOnly?: ReadonlyArray<string>;
/** When true, hydrate handlers are collected but NOT run during creation.

@@ -10,0 +11,0 @@ * Call `store.hydrate()` manually (StoreProvider does this in a useEffect).

@@ -34,2 +34,5 @@ import e from "./helpers/Subscribers.mjs";

},
deleteOwnKey: (e) => {
delete d[e], O(), f = void 0;
},
parent: x,

@@ -40,2 +43,3 @@ listeners: p,

interceptors: v,
readOnly: u?.readOnly ?? [],
reportError: C,

@@ -61,2 +65,3 @@ invalidateDescendants: _,

getState: E,
getOwnState: T,
getPath: D,

@@ -68,3 +73,3 @@ setState: F,

withBase: (e) => {
let t = (t, n) => F(t === void 0 ? e : `${e}.${t}`, n);
let t = (t, n, r) => F(t === void 0 ? e : `${e}.${t}`, n, r);
return {

@@ -71,0 +76,0 @@ getState: (t) => {

@@ -9,2 +9,3 @@ import { default as PathTrie } from './PathTrie';

mutateOwnKey: (key: string, value: unknown) => void;
deleteOwnKey: (key: string) => void;
parent: StoreApi<TState> | undefined;

@@ -15,2 +16,3 @@ listeners: Subscribers<Listener>;

interceptors: WriteInterceptor<TState>[];
readOnly: ReadonlyArray<string>;
reportError: StoreErrorReporter<TState>;

@@ -17,0 +19,0 @@ invalidateDescendants: () => void;

+123
-84
import e from "../../helpers/parsePath.mjs";
import t from "../../helpers/getByPath.mjs";
import { UNCHANGED as n, writeByPath as r } from "./writeByPath.mjs";
import i from "../../helpers/setByPath.mjs";
import { CANCEL as a } from "../../types/StoreTypes.mjs";
import { isDev as n } from "../../env.mjs";
import { UNCHANGED as r, deleteByPath as i, writeByPath as a } from "./writeByPath.mjs";
import o from "../../helpers/setByPath.mjs";
import { CANCEL as s } from "../../types/StoreTypes.mjs";
//#region src/createStore/helpers/createSetState.ts
var o = Symbol("no-error"), s = (e, t, n) => {
let r = 0, i = o;
var c = Symbol("no-error"), l = (e, t, n) => {
let r = 0, i = c;
for (; r < n;) try {
for (; r < n; r++) e[r](t);
} catch (e) {
i === o && (i = e), r++;
i === c && (i = e), r++;
}
return i;
}, c = "__proto__", l = (e, t) => {
}, u = "__proto__", d = (e, t) => {
let n = e;

@@ -23,9 +24,19 @@ for (let e = 0, r = t.length; e < r; e++) {

};
function u(u) {
let { getOwnState: d, getOwnSnapshot: f, setOwnState: p, mutateOwnKey: m, parent: h, listeners: g, pathListeners: _, changeListeners: v, interceptors: y, reportError: b, invalidateDescendants: x, onDelegateToParent: S } = u, C = (e, t, n) => {
function f(f) {
let { getOwnState: p, getOwnSnapshot: m, setOwnState: h, mutateOwnKey: g, deleteOwnKey: _, parent: v, listeners: y, pathListeners: b, changeListeners: x, interceptors: S, readOnly: C, reportError: w, invalidateDescendants: T, onDelegateToParent: E } = f, D = (e) => {
for (let t = 0, n = C.length; t < n; t++) {
let n = C[t];
if (e === n || e.startsWith(`${n}.`) || n.startsWith(`${e}.`)) return !0;
}
return !1;
}, O = (e) => {
if (C.length === 0 || !D(e)) return !1;
if (n) throw Error(`@plitzi/nexus: refused to write to read-only path "${e}"`);
return !0;
}, k = (e, t, n) => {
let r = t;
for (let t = 0, i = y.length; t < i; t++) {
for (let t = 0, i = S.length; t < i; t++) {
let i;
try {
i = y[t]({
i = S[t]({
path: e,

@@ -36,12 +47,12 @@ value: r,

} catch (t) {
return b(t, "beforeChange", e), a;
return w(t, "beforeChange", e), s;
}
if (i === a) return a;
if (i === s) return s;
i !== void 0 && (r = i);
}
return r;
}, w = 0, T = /* @__PURE__ */ new Set(), E = (e, t) => {
}, A = 0, j = /* @__PURE__ */ new Set(), M = (e, t) => {
let { items: n } = e;
if (w > 0) {
for (let e = 0, t = n.length; e < t; e++) T.add(n[e]);
if (A > 0) {
for (let e = 0, t = n.length; e < t; e++) j.add(n[e]);
return;

@@ -52,4 +63,4 @@ }

try {
let e = s(n, t, n.length);
e !== o && b(e, "notify", t);
let e = l(n, t, n.length);
e !== c && w(e, "notify", t);
} finally {

@@ -59,15 +70,15 @@ e.end();

}
}, D = (e) => {
w++;
}, N = (e) => {
A++;
try {
return e();
} finally {
if (w--, w === 0 && T.size > 0) {
let e = [...T];
T.clear();
let t = s(e, void 0, e.length);
t !== o && b(t, "notify", void 0);
if (A--, A === 0 && j.size > 0) {
let e = [...j];
j.clear();
let t = l(e, void 0, e.length);
t !== c && w(t, "notify", void 0);
}
}
}, O = (e, n, r) => {
}, P = (e, n, r) => {
let i = {

@@ -79,83 +90,111 @@ path: e,

nextValue: e === void 0 ? r : t(r, e)
}, { items: a } = v;
v.begin();
}, { items: a } = x;
x.begin();
try {
let t = s(a, i, a.length);
t !== o && b(t, "onChange", e);
let t = l(a, i, a.length);
t !== c && w(t, "onChange", e);
} finally {
v.end();
x.end();
}
}, k = (e, t) => {
_.walkAncestors(t, (t) => E(t, e));
}, A = (n, r, i, a) => {
let o = _.getDescendants(n);
}, F = (e, t) => {
b.walkAncestors(t, (t) => M(t, e));
}, I = (n, r, i, a) => {
let o = b.getDescendants(n);
if (o) for (let s of o) {
let o = _.direct.get(s);
let o = b.direct.get(s);
if (!o) continue;
let c = e(s).slice(a);
t(r, c) !== t(i, c) && E(o, n);
t(r, c) !== t(i, c) && M(o, n);
}
}, j = (e, n, r, o) => {
let s = e ? t(r, e) : void 0, c = e ? typeof n == "function" ? n(s) : n : void 0;
if (e && y.length > 0) {
let t = C(e, c, s);
if (t === a) return;
c = t;
}, L = (e, r, i, a) => {
let c = e ? t(i, e) : void 0, l = e ? typeof r == "function" ? r(c) : r : void 0;
if (e && S.length > 0) {
let t = k(e, l, c);
if (t === s) return;
l = t;
}
if (e && s === c) return;
let l = e ? i(r, e, c) : typeof n == "function" ? n(r) : {
...r,
...n
if (e && c === l) return;
let u = e ? o(i, e, l) : typeof r == "function" ? r(i) : {
...i,
...r
};
if (!e && y.length > 0) {
let e = C(void 0, l, r);
if (e === a) return;
l = e;
if (!e && S.length > 0) {
let e = k(void 0, u, i);
if (e === s) return;
u = e;
}
l !== r && (p(l), v.length > 0 && O(e, r, l), x(), o && (E(g, e), _.size > 0 && _.direct.forEach((n, i) => {
t(r, i) !== t(l, i) && E(n, e);
})));
if (u !== i) {
if (C.length > 0) for (let e = 0, r = C.length; e < r; e++) {
let r = C[e];
if (t(i, r) !== t(u, r)) {
if (n) throw Error(`@plitzi/nexus: refused to write to read-only path "${C[e]}"`);
return;
}
}
h(u), x.length > 0 && P(e, i, u), T(), a && (M(y, e), b.size > 0 && b.direct.forEach((n, r) => {
t(i, r) !== t(u, r) && M(n, e);
}));
}
};
return {
setState: (i, o, s = !0) => {
let u = d();
if (typeof i == "string" && i.indexOf(c) !== -1 && e(i).indexOf(c) !== -1) throw Error(`@plitzi/nexus: refused to write to unsafe path "${i}" (\`__proto__\` segment)`);
if (h && typeof i == "string" && !(i.indexOf(".") === -1 ? Object.hasOwn(u, i) : l(u, e(i)))) {
S?.(i), h.setState(i, o, s);
setState: (n, o, c = {}) => {
let { canPropagate: l = !0, unmount: f = !1 } = c, C = p();
if (typeof n == "string" && n.indexOf(u) !== -1 && e(n).indexOf(u) !== -1) throw Error(`@plitzi/nexus: refused to write to unsafe path "${n}" (\`__proto__\` segment)`);
if (typeof n == "string" && O(n)) return;
if (v && typeof n == "string" && !(n.indexOf(".") === -1 ? Object.hasOwn(C, n) : d(C, e(n)))) {
E?.(n), v.setState(n, o, {
canPropagate: l,
unmount: f
});
return;
}
if (typeof i != "string") {
j(i, o, u, s);
if (typeof n != "string") {
L(n, o, C, l);
return;
}
if (i.indexOf(".") === -1) {
let e = u[i], t = typeof o == "function" ? o(e) : o, n = t;
if (y.length > 0) {
let r = C(i, t, e);
if (r === a) return;
n = r;
if (n.indexOf(".") === -1) {
if (f) {
if (!Object.hasOwn(C, n)) return;
let e = C[n];
if (S.length > 0 && k(n, void 0, e) === s) return;
let t = x.length > 0 ? m() : void 0;
if (_(n), t !== void 0 && P(n, t, m()), l && (M(y, n), b.size > 0)) {
let t = b.direct.get(n);
t && M(t, n), I(n, e, void 0, 1);
}
T();
return;
}
if (e === n) return;
let r = v.length > 0 ? f() : void 0;
if (m(i, n), r !== void 0 && O(i, r, f()), s && (E(g, i), _.size > 0)) {
let t = _.direct.get(i);
t && E(t, i), A(i, e, n, 1);
let e = C[n], t = typeof o == "function" ? o(e) : o, r = t;
if (S.length > 0) {
let i = k(n, t, e);
if (i === s) return;
r = i;
}
x();
if (e === r) return;
let i = x.length > 0 ? m() : void 0;
if (g(n, r), i !== void 0 && P(n, i, m()), l && (M(y, n), b.size > 0)) {
let t = b.direct.get(n);
t && M(t, n), I(n, e, r, 1);
}
T();
return;
}
let b = e(i), w;
if (y.length > 0) {
let e = t(u, i), n = typeof o == "function" ? o(e) : o, s = C(i, n, e);
if (s === a) return;
w = r(u, i, b, s, !1);
} else w = r(u, i, b, o, typeof o == "function");
if (w === n) return;
let T = w;
p(T), v.length > 0 && O(i, u, T), s && (E(g, i), _.size > 0 && (k(i, b), A(i, u, T, 0))), x();
let w = e(n), D;
if (f) {
if (S.length > 0 && k(n, void 0, t(C, n)) === s) return;
D = i(C, w);
} else if (S.length > 0) {
let e = t(C, n), r = typeof o == "function" ? o(e) : o, i = k(n, r, e);
if (i === s) return;
D = a(C, n, w, i, !1);
} else D = a(C, n, w, o, typeof o == "function");
if (D === r) return;
let A = D;
h(A), x.length > 0 && P(n, C, A), l && (M(y, n), b.size > 0 && (F(n, w), I(n, C, A, 0))), T();
},
batch: D
batch: N
};
}
//#endregion
export { u as createSetState };
export { f as createSetState };

@@ -0,14 +1,16 @@

import { isTest as e } from "../../env.mjs";
//#region src/createStore/helpers/scopeCollisions.ts
var e = () => {
let e = /* @__PURE__ */ new Map();
return { claimDelegatedWrite(t, n) {
let r = e.get(t);
if (r !== void 0 && r !== n) {
console.warn(`@plitzi/nexus: scope collision — two sibling scopes under the same parent both delegate a write to "${t}", clobbering each other through the shared parent. Write to a path each scope owns, or move the shared value into the parent and update it there.`);
var t = (e) => `@plitzi/nexus: scope collision — two sibling scopes under the same parent both delegate a write to "${e}", clobbering each other through the shared parent. Write to a path each scope owns, or move the shared value into the parent and update it there.`, n = () => {
let n = /* @__PURE__ */ new Map();
return { claimDelegatedWrite(r, i) {
let a = n.get(r);
if (a !== void 0 && a !== i) {
if (e) throw Error(t(r));
console.warn(t(r));
return;
}
e.set(t, n);
n.set(r, i);
} };
};
//#endregion
export { e as createScopeClaims };
export { n as createScopeClaims };

@@ -11,2 +11,3 @@ export declare const UNCHANGED: unique symbol;

export declare const setCodegenEnabled: (enabled: boolean | undefined) => void;
export declare const deleteByPath: (root: unknown, segments: readonly string[]) => Record<string, unknown> | typeof UNCHANGED;
export declare const writeByPath: (root: unknown, path: string, segments: readonly string[], value: unknown, isFn: boolean) => Record<string, unknown> | typeof UNCHANGED;

@@ -43,3 +43,15 @@ //#region src/createStore/helpers/writeByPath.ts

return f.size >= p && f.delete(f.keys().next().value), f.set(e, i), i;
}, h = (t, n, i, a, o) => {
}, h = (t, r, i) => {
if (typeof t != "object" || !t) return e;
let a = t, o = r[i];
if (!Object.hasOwn(a, o)) return e;
if (i === r.length - 1) {
let e = n(a);
return Array.isArray(e) ? e.splice(Number(o), 1) : delete e[o], e;
}
let s = h(a[o], r, i + 1);
if (s === e) return e;
let c = n(a);
return c[o] = s, c;
}, g = (e, t) => h(e, t, 0), _ = (t, n, i, a, o) => {
let s = m(n, i);

@@ -53,2 +65,2 @@ if (s) {

//#endregion
export { e as UNCHANGED, d as setCodegenEnabled, h as writeByPath };
export { e as UNCHANGED, g as deleteByPath, d as setCodegenEnabled, _ as writeByPath };

@@ -15,2 +15,4 @@ export { default as createStore } from './createStore/createStore';

export { createServerSnapshot, isServerSnapshot } from './rsc';
export { registerDevStore, subscribeDevStores, getDevStoresSnapshot } from './devStoreRegistry';
export type { DevStore, DevStoreEntry } from './devStoreRegistry';
export * from './types';

@@ -17,0 +19,0 @@ export type { CreateStoreOptions } from './createStore/createStore';

@@ -15,2 +15,3 @@ import { createAsync as e } from "./async/createAsync.mjs";

import { createServerSnapshot as m, isServerSnapshot as h } from "./rsc/index.mjs";
export { d as CANCEL, l as cascade, e as createAsync, t as createDerived, n as createEntityAdapter, r as createEntityStore, p as createRecorder, m as createServerSnapshot, f as createStore, i as getStoreHistory, a as historyMiddleware, h as isServerSnapshot, o as loggerMiddleware, s as persistMiddleware, c as reduxDevToolsMiddleware, u as setCodegenEnabled };
import { getDevStoresSnapshot as g, registerDevStore as _, subscribeDevStores as v } from "./devStoreRegistry.mjs";
export { d as CANCEL, l as cascade, e as createAsync, t as createDerived, n as createEntityAdapter, r as createEntityStore, p as createRecorder, m as createServerSnapshot, f as createStore, g as getDevStoresSnapshot, i as getStoreHistory, a as historyMiddleware, h as isServerSnapshot, o as loggerMiddleware, s as persistMiddleware, c as reduxDevToolsMiddleware, _ as registerDevStore, u as setCodegenEnabled, v as subscribeDevStores };

@@ -32,7 +32,7 @@ import { useResolvedStore as e } from "./shared.mjs";

...a
}), t);
}), { canPropagate: t });
else if (c) {
let n = i(e.getState());
e.setState(n, a, t);
} else e.setState(i, a, t);
e.setState(n, a, { canPropagate: t });
} else e.setState(i, a, { canPropagate: t });
};

@@ -39,0 +39,0 @@ p === "render" ? v && y() : (v && g && y(!1), n(() => {

export { default as StoreProvider, StoreContext, StoreRegistryContext } from './StoreProvider';
export { default as DevStoreScopeContext } from './DevStoreScopeContext';
export { findStoreInRegistry } from './StoreContext';

@@ -15,4 +16,5 @@ export { createStoreHook } from './createStoreHook';

export { default as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
export type { StoreApi } from '../types';
export type { StoreProviderProps } from './StoreProvider';
export type { StoreRegistry } from './StoreContext';
export type { UseStoreHistoryReturn } from './hooks/useStoreHistory';

@@ -1,16 +0,17 @@

import { StoreContext as e, StoreRegistryContext as t, findStoreInRegistry as n } from "./StoreContext.mjs";
import { defaultMultiEqualityFn as r } from "./hooks/shared.mjs";
import i from "./useIsomorphicLayoutEffect.mjs";
import a from "./hooks/useStoreSync.mjs";
import o from "./StoreProvider.mjs";
import s from "./hooks/useStore.mjs";
import c from "./hooks/useStoreGetter.mjs";
import l from "./hooks/useStoreSetter.mjs";
import { createStoreHook as u } from "./createStoreHook.mjs";
import d from "./hooks/useStoreById.mjs";
import { useAsync as f } from "./hooks/useAsync.mjs";
import { useAsyncValue as p } from "./hooks/useAsyncValue.mjs";
import { useDerived as m } from "./hooks/useDerived.mjs";
import { useStoreHistory as h } from "./hooks/useStoreHistory.mjs";
import { useEntity as g, useEntityAll as _, useEntityIds as v, useEntityOne as y } from "./hooks/useEntity.mjs";
export { e as StoreContext, o as StoreProvider, t as StoreRegistryContext, u as createStoreHook, r as defaultMultiEqualityFn, n as findStoreInRegistry, f as useAsync, p as useAsyncValue, m as useDerived, g as useEntity, _ as useEntityAll, v as useEntityIds, y as useEntityOne, i as useIsomorphicLayoutEffect, s as useStore, d as useStoreById, c as useStoreGetter, h as useStoreHistory, l as useStoreSetter, a as useStoreSync };
import e from "./DevStoreScopeContext.mjs";
import { StoreContext as t, StoreRegistryContext as n, findStoreInRegistry as r } from "./StoreContext.mjs";
import { defaultMultiEqualityFn as i } from "./hooks/shared.mjs";
import a from "./useIsomorphicLayoutEffect.mjs";
import o from "./hooks/useStoreSync.mjs";
import s from "./StoreProvider.mjs";
import c from "./hooks/useStore.mjs";
import l from "./hooks/useStoreGetter.mjs";
import u from "./hooks/useStoreSetter.mjs";
import { createStoreHook as d } from "./createStoreHook.mjs";
import f from "./hooks/useStoreById.mjs";
import { useAsync as p } from "./hooks/useAsync.mjs";
import { useAsyncValue as m } from "./hooks/useAsyncValue.mjs";
import { useDerived as h } from "./hooks/useDerived.mjs";
import { useStoreHistory as g } from "./hooks/useStoreHistory.mjs";
import { useEntity as _, useEntityAll as v, useEntityIds as y, useEntityOne as b } from "./hooks/useEntity.mjs";
export { e as DevStoreScopeContext, t as StoreContext, s as StoreProvider, n as StoreRegistryContext, d as createStoreHook, i as defaultMultiEqualityFn, r as findStoreInRegistry, p as useAsync, m as useAsyncValue, h as useDerived, _ as useEntity, v as useEntityAll, y as useEntityIds, b as useEntityOne, a as useIsomorphicLayoutEffect, c as useStore, f as useStoreById, l as useStoreGetter, g as useStoreHistory, u as useStoreSetter, o as useStoreSync };

@@ -22,6 +22,7 @@ import { StoreContext, StoreRegistryContext } from './StoreContext';

middlewares?: StoreMiddleware<TState>[];
name?: string;
children?: ReactNode;
};
declare const StoreProvider: <TState extends object = any>({ store, id, segment, isolate, path, value, inherit, autoSync, middlewares, children }: StoreProviderProps<TState>) => import("react").JSX.Element;
declare const StoreProvider: <TState extends object = any>({ store, id, segment, isolate, path, value, inherit, autoSync, middlewares, name, children }: StoreProviderProps<TState>) => import("react").JSX.Element;
export { StoreContext, StoreRegistryContext };
export default StoreProvider;
import { isDev as e } from "../env.mjs";
import t from "../createStore/index.mjs";
import { isServerSnapshot as n, stripServerFlag as r } from "../rsc/index.mjs";
import { StoreContext as i, StoreRegistryContext as a, findStoreInRegistry as o } from "./StoreContext.mjs";
import s from "./hooks/useStoreSync.mjs";
import { createContext as c, useContext as l, useEffect as u, useMemo as d, useRef as f } from "react";
import { jsx as p } from "react/jsx-runtime";
import { registerDevStore as i } from "../devStoreRegistry.mjs";
import a from "./DevStoreScopeContext.mjs";
import { StoreContext as o, StoreRegistryContext as s, findStoreInRegistry as c } from "./StoreContext.mjs";
import l from "./hooks/useStoreSync.mjs";
import { createContext as u, useContext as d, useEffect as f, useMemo as p, useRef as m } from "react";
import { jsx as h } from "react/jsx-runtime";
//#region src/react/StoreProvider.tsx
var m = c(void 0), h = (e) => e.cascade === !0, g = ({ store: c, id: g, segment: _, isolate: v, path: y, value: b, inherit: x, autoSync: S = !0, middlewares: C, children: w }) => {
let T = l(i), E = l(m), D = l(a), O = T?.scopePath ?? "", k = d(() => _ === void 0 ? O : O ? `${O}/${_}` : _, [O, _]), A = f(void 0), j = x === "live", M = d(() => {
let e = x === "snapshot" && T ? T.getState() : {}, t = typeof b == "function" ? b(e) : {
var g = u(void 0), _ = (e) => e.cascade === !0, v = ({ store: u, id: v, segment: y, isolate: b, path: x, value: S, inherit: C, autoSync: w = !0, middlewares: T, name: E, children: D }) => {
let O = d(o), k = d(g), A = d(s), j = d(a), M = O?.scopePath ?? "", N = p(() => y === void 0 ? M : M ? `${M}/${y}` : y, [M, y]), P = m(void 0), F = C === "live", I = p(() => {
let e = C === "snapshot" && O ? O.getState() : {}, t = typeof S == "function" ? S(e) : {
...e,
...b
...S
};
return n(t) ? r(t) : t;
}, [
x,
T,
b
]), N = C ?? [], P = E ? [...E, ...N] : N, F = d(() => {
let e = N.filter(h);
return e.length === 0 ? E : [...E ?? [], ...e];
}, [E, C]);
A.current ||= c ?? t(() => M, {
id: g,
scopePath: k,
exclusive: j ? v : void 0,
parent: j ? T : void 0,
middlewares: P.length > 0 ? P : void 0,
C,
O,
S
]), L = T ?? [], R = k ? [...k, ...L] : L, z = p(() => {
let e = L.filter(_);
return e.length === 0 ? k : [...k ?? [], ...e];
}, [k, T]);
P.current ||= u ?? t(() => I, {
id: v,
scopePath: N,
exclusive: F ? b : void 0,
parent: F ? O : void 0,
middlewares: R.length > 0 ? R : void 0,
deferHydrate: !0
});
let I = d(() => g ? {
id: g,
store: A.current,
parent: D
} : D, [g, D]), L = f(!1);
u(() => {
e && g && !L.current && o(D, g) && (L.current = !0, console.warn(`@plitzi/nexus: duplicate StoreProvider id "${g}" — it shadows an ancestor provider with the same id, so a descendant's { storeId: "${g}" } or useStoreById("${g}") resolves to this (nearer) store. Use a distinct id, or remove one of the providers.`));
}, [g, D]), u(() => (j && !c && A.current?.reconnect?.(), () => {
j && !c && A.current?.destroy?.();
}), [j, c]);
let R = f(!1);
u(() => {
!R.current && A.current?.hydrate && (A.current.hydrate(), R.current = !0);
}, []), s(y, y ? b : M, {
enabled: !!b && S,
store: A.current
let B = p(() => v ? {
id: v,
store: P.current,
parent: A
} : A, [v, A]), V = m(!1);
f(() => {
e && v && !V.current && c(A, v) && (V.current = !0, console.warn(`@plitzi/nexus: duplicate StoreProvider id "${v}" — it shadows an ancestor provider with the same id, so a descendant's { storeId: "${v}" } or useStoreById("${v}") resolves to this (nearer) store. Use a distinct id, or remove one of the providers.`));
}, [v, A]), f(() => (F && !u && P.current?.reconnect?.(), () => {
F && !u && P.current?.destroy?.();
}), [F, u]), f(() => {
if (e) return i(P.current, j, E);
}, [j, E]);
let H = m(!1);
f(() => {
!H.current && P.current?.hydrate && (P.current.hydrate(), H.current = !0);
}, []), l(x, x ? S : I, {
enabled: !!S && w,
store: P.current
});
let z = /* @__PURE__ */ p(i, {
value: A.current,
children: w
let U = /* @__PURE__ */ h(o, {
value: P.current,
children: D
});
return I !== D && (z = /* @__PURE__ */ p(a, {
value: I,
children: z
})), F !== E && (z = /* @__PURE__ */ p(m, {
value: F,
children: z
})), z;
return B !== A && (U = /* @__PURE__ */ h(s, {
value: B,
children: U
})), z !== k && (U = /* @__PURE__ */ h(g, {
value: z,
children: U
})), U;
};
//#endregion
export { i as StoreContext, a as StoreRegistryContext, g as default };
export { o as StoreContext, s as StoreRegistryContext, v as default };

@@ -59,5 +59,9 @@ import { default as PathTrie } from '../createStore/helpers/PathTrie';

export type Listener = (changedPath?: Path) => void;
export type SetStateOptions = {
canPropagate?: boolean;
unmount?: boolean;
};
export type SetState<T> = {
(path: undefined, value: T | ((prev: T) => T), canPropagate?: boolean): void;
<P extends PathOf<T>>(path: P, value: PathValue<T, P> | ((prev: PathValue<T, P>) => PathValue<T, P>), canPropagate?: boolean): void;
(path: undefined, value: T | ((prev: T) => T), options?: SetStateOptions): void;
<P extends PathOf<T>>(path: P, value: PathValue<T, P> | ((prev: PathValue<T, P>) => PathValue<T, P>), options?: SetStateOptions): void;
};

@@ -94,2 +98,3 @@ export type GetState<T> = () => T;

getState: GetState<T>;
getOwnState: () => T;
getPath: <P extends PathOf<T>>(path: P) => PathValue<T, P> | undefined;

@@ -170,10 +175,10 @@ setState: SetState<T>;

export type SetStateFn<TState extends object> = {
(path: undefined, value: TState | ((prev: TState) => TState)): void;
<P extends PathOf<TState>>(path: P, value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)): void;
(path: undefined, value: TState | ((prev: TState) => TState), options?: SetStateOptions): void;
<P extends PathOf<TState>>(path: P, value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>), options?: SetStateOptions): void;
};
export type SetFromBaseFn<TBase> = TBase extends object ? {
(subPath: undefined, value: TBase | ((prev: TBase) => TBase)): void;
<SubP extends PathOf<TBase>>(subPath: SubP, value: PathValue<TBase, SubP> | ((prev: PathValue<TBase, SubP>) => PathValue<TBase, SubP>)): void;
} : (subPath: undefined, value: TBase) => void;
(subPath: undefined, value: TBase | ((prev: TBase) => TBase), options?: SetStateOptions): void;
<SubP extends PathOf<TBase>>(subPath: SubP, value: PathValue<TBase, SubP> | ((prev: PathValue<TBase, SubP>) => PathValue<TBase, SubP>), options?: SetStateOptions): void;
} : (subPath: undefined, value: TBase, options?: SetStateOptions) => void;
export type UseStoreSetterOptions<TState extends object = object> = StoreHookBaseOptions<TState>;
export {};
{
"name": "@plitzi/nexus",
"version": "0.32.5",
"version": "0.32.6",
"license": "Apache-2.0",

@@ -26,9 +26,9 @@ "files": [

"devDependencies": {
"eslint": "^9.39.4",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"eslint": "^9.39.5",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"typescript": "^6.0.3",
"vite": "^8.1.4",
"vite": "^8.1.5",
"vitest": "^4.1.10",
"vue": "^3.5.39"
"vue": "^3.5.40"
},

@@ -132,2 +132,6 @@ "peerDependencies": {

},
"./devStoreRegistry": {
"types": "./dist/devStoreRegistry.d.ts",
"import": "./dist/devStoreRegistry.mjs"
},
"./entities": {

@@ -237,2 +241,6 @@ "types": "./dist/entities/index.d.ts",

},
"./react/DevStoreScopeContext": {
"types": "./dist/react/DevStoreScopeContext.d.ts",
"import": "./dist/react/DevStoreScopeContext.mjs"
},
"./react/StoreContext": {

@@ -239,0 +247,0 @@ "types": "./dist/react/StoreContext.d.ts",

@@ -55,5 +55,8 @@ <p align="center">

store.set('count', n => n + 1); // updater form
store.set('user.name', undefined, { unmount: true }); // DELETE the key (see "Removing a path")
const off = store.watch('user.name', name => render(name)); // fires only for this path
```
Every write takes an optional third argument, `SetStateOptions = { canPropagate?; unmount? }` — see [Removing a path](#removing-a-path-unmount). To freeze paths against writes, see [Read-only paths](#read-only-paths).
## What each piece is for

@@ -133,2 +136,5 @@

const store = createStore<MyState>({ count: 0 }, { id: 'root' });
// Freeze paths against writes (see "Read-only paths" below)
const store = createStore<MyState>({ count: 0 }, { readOnly: ['config.theme'] });
```

@@ -167,2 +173,7 @@

</StoreProvider>
// Label it for devtools — cosmetic only, unlike `id` it carries no addressing and never collides
<StoreProvider name="Form:hero" inherit="live" value={{ record }}>
<Child />
</StoreProvider>
```

@@ -174,2 +185,5 @@

> **`name`** is a human label of where the store comes from, shown by the devtools store picker (see
> [DevTools integration](#devtools-integration)). Purely cosmetic — stripped from production.
## Scoped stores (live scope chain)

@@ -200,2 +214,13 @@

```
- **Own layer vs merged view (`getOwnState`)** — `getState()` returns the full **merged** view (own +
inherited). `getOwnState()` returns **only this scope's own layer** — the keys it seeds/writes locally,
without the parent fall-through. For a root store the two are identical; for a scoped store `getOwnState()`
isolates the scope's contribution (what a devtools inspector shows to tell nested scopes apart). Both are
cached and reference-stable between changes.
```ts
const root = createStore<S>({ user, theme: 'dark' });
const item = createStore<S>({ record }, { parent: root });
item.getState(); // { user, theme: 'dark', record } ← merged
item.getOwnState(); // { record } ← own layer only
```
- **Shadowing** — a scope's own **leaf** value hides the parent's at that path (reads and subscriptions);

@@ -379,2 +404,40 @@ sibling leaves under a shared object branch are preserved (see deep-merge above).

## Removing a path (`unmount`)
Every write takes an optional third argument: `SetStateOptions = { canPropagate?; unmount? }`. `canPropagate: false` commits silently (no subscriber wakes); `unmount: true` **deletes** the key at `path` instead of writing `undefined`, so the path leaves no dead entry — an object key or array slot that would otherwise linger as `undefined`.
Reach for it whenever you register/unregister things under a dynamic key (a source registry, a per-id cache) and don't want `Object.keys` / `Object.values` to see stale `undefined` holes.
```ts
store.set('sources.abc', { id: 'abc', meta }); // register
store.set('sources.abc', undefined, { unmount: true }); // unregister — key is gone
Object.hasOwn(store.get('sources'), 'abc'); // false
```
- **Nested paths** delete only the leaf and keep siblings, with structural sharing (`a.b` removed → `a` is a new object; untouched subtrees are shared by reference).
- A numeric leaf on an **array** is **spliced** out (later indices shift down), never left as a hole.
- Removing an **absent** key is a **no-op** — no change is emitted, no subscriber wakes.
- Writing a value back later **recreates** the path, rebuilding any container the delete had emptied. In a scope chain the re-write delegates to the owning scope just like the original write.
- `beforeChange` interceptors still run (with `value: undefined`), so a validation or [read-only](#read-only-paths) guard can veto the removal.
- `unmount` is **ignored** for a whole-state write (`set(undefined, next)`).
## Read-only paths
Pass `readOnly` to `createStore` to freeze one or more paths. A write to a read-only path — or to an **ancestor** or **descendant** of one — **throws in development** (surfacing the bug at its source) and is **silently dropped in production** (so it never crashes a render).
```ts
const store = createStore<State>(initial, { readOnly: ['config.theme', 'license'] });
store.set('config.theme', 'dark'); // dev: throws · prod: no-op
store.set('config', { theme: 'x' }); // ancestor — also blocked (would replace the frozen subtree)
store.set('config.theme.shade', 'x'); // descendant — also blocked
store.set('config.other', 'ok'); // sibling — allowed
```
- **Prefix-safe matching**: `readOnly: ['config']` blocks `config` and `config.*` but never `configuration`; `['a.b']` never blocks `a.bc`.
- The **updater form** throws *before* the updater runs; an `unmount` of a protected path is blocked too.
- A **whole-state replace** (`set(undefined, next)`) is checked per read-only path by **reference** — blocked if the value at that path changes identity (rebuilding an equal-but-new object still counts as a change).
- Enforcement is **per scope, on that scope's own writes**. A child that delegates a write up is rejected by the parent's `readOnly`; a key the child owns locally is not governed by an ancestor's `readOnly`.
- The check is **skipped entirely** when `readOnly` is omitted — zero cost by default.
## `createStoreHook`

@@ -676,2 +739,36 @@

## DevTools integration
A **dev-only** global registry lets a devtools panel enumerate and inspect every store — including scoped stores mounted **below** the panel, where React context can't reach them. Everything here is stripped from production builds (guarded by `isDev`), so it carries no runtime cost when shipped.
Every `StoreProvider` registers its store on mount and removes it on unmount. Read the registry with `useSyncExternalStore`:
```ts
import { subscribeDevStores, getDevStoresSnapshot } from '@plitzi/nexus';
import type { DevStoreEntry } from '@plitzi/nexus';
// snapshot is a stable array (identity only changes when a store is added/removed)
const useDevStores = (): ReadonlyArray<DevStoreEntry> =>
useSyncExternalStore(subscribeDevStores, getDevStoresSnapshot, getDevStoresSnapshot);
```
Each `DevStoreEntry` is `{ uid, store, scopeId?, name? }`:
- **`uid`** — a stable id for selection in a picker.
- **`store`** — the `StoreApi`; inspect it with `getState()` (merged view) or `getOwnState()` (this scope's own layer — see [Scoped stores](#scoped-stores-live-scope-chain)).
- **`name`** — the `<StoreProvider name>` label, e.g. `"Form:hero"` — a human hint of where the store comes from.
- **`scopeId`** — an app-defined grouping tag (see `DevStoreScopeContext` below), e.g. the app/SDK instance the store belongs to, so a panel can group stores by origin.
**`DevStoreScopeContext`** tags every store registered beneath it with a `scopeId`. Wrap a subtree to attribute its stores to one origin (a panel then groups by it):
```tsx
import { DevStoreScopeContext } from '@plitzi/nexus/react';
<DevStoreScopeContext value={instanceId}>
<App /> {/* every StoreProvider below registers with scopeId = instanceId */}
</DevStoreScopeContext>
```
Combine the three — `name` (where it comes from), `getOwnState()` (what it uniquely holds) and `scopeId` (which app owns it) — to build a store picker that tells otherwise-identical nested scopes apart. This is exactly what the Plitzi `sdk-dev-tools` Store tab does.
## CSP & `new Function`

@@ -935,4 +1032,5 @@

| `MultiPathReturn<T, Paths>` | `[values, ...setters]` tuple |
| `StoreApi<T>` | `{ getState, getPath, setState, subscribe, subscribePath, subscribeChange, destroy? }` |
| `StoreApi<T>` | `{ getState, getOwnState, getPath, setState, subscribe, subscribePath, subscribeChange, destroy? }` |
| `StoreChange<T>` | `{ path, prev, next }` — payload of `subscribeChange` / middleware `onChange` |
| `DevStoreEntry` | `{ uid, store, scopeId?, name? }` — a store registered in the dev-only registry (see [DevTools integration](#devtools-integration)) |
| `StoreMiddleware<T>` | `(api) => { beforeChange?, onChange? } \| void` — a middleware factory |

@@ -939,0 +1037,0 @@ | `WriteContext<T>` | `{ path, value, prev }` — payload of a `beforeChange` interceptor |