@plitzi/nexus 0.32.5 → 0.32.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +99 -1
- package/dist/createStore/createStore.d.ts +1 -0
- package/dist/createStore/createStore.mjs +6 -1
- package/dist/createStore/helpers/createSetState.d.ts +2 -0
- package/dist/createStore/helpers/createSetState.mjs +123 -84
- package/dist/createStore/helpers/scopeCollisions.mjs +10 -8
- package/dist/createStore/helpers/writeByPath.d.ts +1 -0
- package/dist/createStore/helpers/writeByPath.mjs +14 -2
- package/dist/devStoreRegistry.d.ts +11 -0
- package/dist/devStoreRegistry.mjs +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +2 -1
- package/dist/react/DevStoreScopeContext.d.ts +2 -0
- package/dist/react/DevStoreScopeContext.mjs +6 -0
- package/dist/react/StoreProvider.d.ts +2 -1
- package/dist/react/StoreProvider.mjs +52 -48
- package/dist/react/hooks/useStoreSync.mjs +3 -3
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.mjs +17 -16
- package/dist/types/StoreTypes.d.ts +12 -7
- package/package.json +14 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @plitzi/nexus
|
|
2
2
|
|
|
3
|
+
## 0.32.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- v0.32.6
|
|
8
|
+
|
|
3
9
|
## 0.32.5
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -40,6 +46,13 @@
|
|
|
40
46
|
`useStoreHistory`. `vue` is an optional peer dependency (`^3.4`).
|
|
41
47
|
- Added runnable examples (`examples/`) and integration docs (`docs/integrations/`) for React, Next.js, Astro 6 (LTS),
|
|
42
48
|
Astro 7, Vue and Svelte.
|
|
49
|
+
- **`unmount` write option.** Every write now takes an optional third argument `SetStateOptions = { canPropagate?;
|
|
50
|
+
unmount? }`. `set(path, undefined, { unmount: true })` **deletes** the key at `path` (splicing array indices) instead
|
|
51
|
+
of leaving a dead `undefined`, so registries keyed by dynamic id leave no stale entries. Nested deletes keep siblings
|
|
52
|
+
with structural sharing, interceptors can veto them, and writing a value back recreates the path.
|
|
53
|
+
- **Read-only paths.** `createStore(init, { readOnly: [...] })` freezes paths: a write to a read-only path — or to an
|
|
54
|
+
ancestor/descendant of one — throws in development and no-ops in production. Prefix-safe matching, enforced per scope
|
|
55
|
+
on that scope's own writes, zero cost when unused.
|
|
43
56
|
|
|
44
57
|
### Breaking Changes
|
|
45
58
|
|
package/README.md
CHANGED
|
@@ -52,9 +52,12 @@ store.get('user.name'); // 'Carlos' (one path, no full merge)
|
|
|
52
52
|
store.get(); // entire state
|
|
53
53
|
store.set('user.name', 'Ada'); // typed dot-path write
|
|
54
54
|
store.set('count', n => n + 1); // updater form
|
|
55
|
+
store.set('user.name', undefined, { unmount: true }); // DELETE the key (see "Removing a path")
|
|
55
56
|
const off = store.watch('user.name', name => render(name)); // fires only for this path
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
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).
|
|
60
|
+
|
|
58
61
|
## What each piece is for
|
|
59
62
|
|
|
60
63
|
### Core — the 90%
|
|
@@ -129,6 +132,9 @@ const store = createStore<MyState>({ count: 0 }, {
|
|
|
129
132
|
|
|
130
133
|
// With an id, so descendants can target it by id (see "Named stores" below)
|
|
131
134
|
const store = createStore<MyState>({ count: 0 }, { id: 'root' });
|
|
135
|
+
|
|
136
|
+
// Freeze paths against writes (see "Read-only paths" below)
|
|
137
|
+
const store = createStore<MyState>({ count: 0 }, { readOnly: ['config.theme'] });
|
|
132
138
|
```
|
|
133
139
|
|
|
134
140
|
`StoreApi` exposes `getState`, `getPath`, `setState`, `subscribe`, `subscribePath`, `subscribeChange`,
|
|
@@ -162,12 +168,20 @@ Wraps children with a store context. Creates a new store by default; pass `store
|
|
|
162
168
|
<StoreProvider id="root" value={builderState}>
|
|
163
169
|
<App />
|
|
164
170
|
</StoreProvider>
|
|
171
|
+
|
|
172
|
+
// Label it for devtools — cosmetic only, unlike `id` it carries no addressing and never collides
|
|
173
|
+
<StoreProvider name="Form:hero" inherit="live" value={{ record }}>
|
|
174
|
+
<Child />
|
|
175
|
+
</StoreProvider>
|
|
165
176
|
```
|
|
166
177
|
|
|
167
178
|
> **`inherit` modes:** `'snapshot'` copies parent keys **once** at init — isolated thereafter: writes stay
|
|
168
179
|
> local and parent updates do **not** propagate (use for draft/diverge editors). `'live'` keeps a **live
|
|
169
180
|
> link** — inherited keys stay in sync and writes delegate to the owning scope.
|
|
170
181
|
|
|
182
|
+
> **`name`** is a human label of where the store comes from, shown by the devtools store picker (see
|
|
183
|
+
> [DevTools integration](#devtools-integration)). Purely cosmetic — stripped from production.
|
|
184
|
+
|
|
171
185
|
## Scoped stores (live scope chain)
|
|
172
186
|
|
|
173
187
|
A store can have a `parent`. Reads resolve through the chain and writes target the owning scope. This
|
|
@@ -193,6 +207,17 @@ const item = createStore<S>({ record }, { parent: root });
|
|
|
193
207
|
const item = createStore<S>({ runtime: { sources: { record } } }, { parent: root });
|
|
194
208
|
item.getState().runtime.sources; // { variables: { a: 1 }, record } ← merged, not shadowed
|
|
195
209
|
```
|
|
210
|
+
- **Own layer vs merged view (`getOwnState`)** — `getState()` returns the full **merged** view (own +
|
|
211
|
+
inherited). `getOwnState()` returns **only this scope's own layer** — the keys it seeds/writes locally,
|
|
212
|
+
without the parent fall-through. For a root store the two are identical; for a scoped store `getOwnState()`
|
|
213
|
+
isolates the scope's contribution (what a devtools inspector shows to tell nested scopes apart). Both are
|
|
214
|
+
cached and reference-stable between changes.
|
|
215
|
+
```ts
|
|
216
|
+
const root = createStore<S>({ user, theme: 'dark' });
|
|
217
|
+
const item = createStore<S>({ record }, { parent: root });
|
|
218
|
+
item.getState(); // { user, theme: 'dark', record } ← merged
|
|
219
|
+
item.getOwnState(); // { record } ← own layer only
|
|
220
|
+
```
|
|
196
221
|
- **Shadowing** — a scope's own **leaf** value hides the parent's at that path (reads and subscriptions);
|
|
197
222
|
sibling leaves under a shared object branch are preserved (see deep-merge above).
|
|
198
223
|
```ts
|
|
@@ -371,6 +396,44 @@ setFlat(`${id}.attributes`, attrs); // sets schema.flat.${id}.attributes
|
|
|
371
396
|
setFlat(undefined, flatObj); // replaces schema.flat
|
|
372
397
|
```
|
|
373
398
|
|
|
399
|
+
## Removing a path (`unmount`)
|
|
400
|
+
|
|
401
|
+
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`.
|
|
402
|
+
|
|
403
|
+
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.
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
store.set('sources.abc', { id: 'abc', meta }); // register
|
|
407
|
+
store.set('sources.abc', undefined, { unmount: true }); // unregister — key is gone
|
|
408
|
+
Object.hasOwn(store.get('sources'), 'abc'); // false
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
- **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).
|
|
412
|
+
- A numeric leaf on an **array** is **spliced** out (later indices shift down), never left as a hole.
|
|
413
|
+
- Removing an **absent** key is a **no-op** — no change is emitted, no subscriber wakes.
|
|
414
|
+
- 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.
|
|
415
|
+
- `beforeChange` interceptors still run (with `value: undefined`), so a validation or [read-only](#read-only-paths) guard can veto the removal.
|
|
416
|
+
- `unmount` is **ignored** for a whole-state write (`set(undefined, next)`).
|
|
417
|
+
|
|
418
|
+
## Read-only paths
|
|
419
|
+
|
|
420
|
+
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).
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
const store = createStore<State>(initial, { readOnly: ['config.theme', 'license'] });
|
|
424
|
+
|
|
425
|
+
store.set('config.theme', 'dark'); // dev: throws · prod: no-op
|
|
426
|
+
store.set('config', { theme: 'x' }); // ancestor — also blocked (would replace the frozen subtree)
|
|
427
|
+
store.set('config.theme.shade', 'x'); // descendant — also blocked
|
|
428
|
+
store.set('config.other', 'ok'); // sibling — allowed
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
- **Prefix-safe matching**: `readOnly: ['config']` blocks `config` and `config.*` but never `configuration`; `['a.b']` never blocks `a.bc`.
|
|
432
|
+
- The **updater form** throws *before* the updater runs; an `unmount` of a protected path is blocked too.
|
|
433
|
+
- 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).
|
|
434
|
+
- 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`.
|
|
435
|
+
- The check is **skipped entirely** when `readOnly` is omitted — zero cost by default.
|
|
436
|
+
|
|
374
437
|
## `createStoreHook`
|
|
375
438
|
|
|
376
439
|
Factory that binds `TState` at the module level, giving fully-typed hooks without repeating the generic at every call site.
|
|
@@ -667,6 +730,40 @@ function HistoryPanel() {
|
|
|
667
730
|
|
|
668
731
|
`<StoreProvider history>` (or `history="schema"` to scope it to a subtree) starts recording from mount.
|
|
669
732
|
|
|
733
|
+
## DevTools integration
|
|
734
|
+
|
|
735
|
+
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.
|
|
736
|
+
|
|
737
|
+
Every `StoreProvider` registers its store on mount and removes it on unmount. Read the registry with `useSyncExternalStore`:
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
import { subscribeDevStores, getDevStoresSnapshot } from '@plitzi/nexus';
|
|
741
|
+
import type { DevStoreEntry } from '@plitzi/nexus';
|
|
742
|
+
|
|
743
|
+
// snapshot is a stable array (identity only changes when a store is added/removed)
|
|
744
|
+
const useDevStores = (): ReadonlyArray<DevStoreEntry> =>
|
|
745
|
+
useSyncExternalStore(subscribeDevStores, getDevStoresSnapshot, getDevStoresSnapshot);
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
Each `DevStoreEntry` is `{ uid, store, scopeId?, name? }`:
|
|
749
|
+
|
|
750
|
+
- **`uid`** — a stable id for selection in a picker.
|
|
751
|
+
- **`store`** — the `StoreApi`; inspect it with `getState()` (merged view) or `getOwnState()` (this scope's own layer — see [Scoped stores](#scoped-stores-live-scope-chain)).
|
|
752
|
+
- **`name`** — the `<StoreProvider name>` label, e.g. `"Form:hero"` — a human hint of where the store comes from.
|
|
753
|
+
- **`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.
|
|
754
|
+
|
|
755
|
+
**`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):
|
|
756
|
+
|
|
757
|
+
```tsx
|
|
758
|
+
import { DevStoreScopeContext } from '@plitzi/nexus/react';
|
|
759
|
+
|
|
760
|
+
<DevStoreScopeContext value={instanceId}>
|
|
761
|
+
<App /> {/* every StoreProvider below registers with scopeId = instanceId */}
|
|
762
|
+
</DevStoreScopeContext>
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
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.
|
|
766
|
+
|
|
670
767
|
## CSP & `new Function`
|
|
671
768
|
|
|
672
769
|
By default `@plitzi/nexus` uses a compiled codegen path (`new Function`) for structural-sharing writes, which is orders of magnitude faster than the recursive fallback for deep paths. When a strict [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) blocks `new Function`, the store auto-detects the error at first use and falls back to a recursive writer with identical behaviour — you **don't need to do anything** for CSP environments to work.
|
|
@@ -925,8 +1022,9 @@ All types live in `src/types/StoreTypes.ts`:
|
|
|
925
1022
|
| `PathSetter<T, P>` | Setter function for a single path |
|
|
926
1023
|
| `PathSetters<T, Paths>` | Tuple of setters for an array of paths |
|
|
927
1024
|
| `MultiPathReturn<T, Paths>` | `[values, ...setters]` tuple |
|
|
928
|
-
| `StoreApi<T>` | `{ getState, getPath, setState, subscribe, subscribePath, subscribeChange, destroy? }` |
|
|
1025
|
+
| `StoreApi<T>` | `{ getState, getOwnState, getPath, setState, subscribe, subscribePath, subscribeChange, destroy? }` |
|
|
929
1026
|
| `StoreChange<T>` | `{ path, prev, next }` — payload of `subscribeChange` / middleware `onChange` |
|
|
1027
|
+
| `DevStoreEntry` | `{ uid, store, scopeId?, name? }` — a store registered in the dev-only registry (see [DevTools integration](#devtools-integration)) |
|
|
930
1028
|
| `StoreMiddleware<T>` | `(api) => { beforeChange?, onChange? } \| void` — a middleware factory |
|
|
931
1029
|
| `WriteContext<T>` | `{ path, value, prev }` — payload of a `beforeChange` interceptor |
|
|
932
1030
|
| `WriteInterceptor<T>` | `(ctx: WriteContext<T>) => unknown` — return a value, `CANCEL`, or `undefined` |
|
|
@@ -5,6 +5,7 @@ export type CreateStoreOptions<TState extends object> = {
|
|
|
5
5
|
parent?: StoreApi<TState>;
|
|
6
6
|
exclusive?: ReadonlyArray<string>;
|
|
7
7
|
middlewares?: StoreMiddleware<TState>[];
|
|
8
|
+
readOnly?: ReadonlyArray<string>;
|
|
8
9
|
/** When true, hydrate handlers are collected but NOT run during creation.
|
|
9
10
|
* Call `store.hydrate()` manually (StoreProvider does this in a useEffect).
|
|
10
11
|
* Defaults to false (backward-compatible: standalone usage hydrates synchronously). */
|
|
@@ -31,11 +31,15 @@ function l(l, u) {
|
|
|
31
31
|
mutateOwnKey: (e, t) => {
|
|
32
32
|
d[e] = t, O(), f = void 0;
|
|
33
33
|
},
|
|
34
|
+
deleteOwnKey: (e) => {
|
|
35
|
+
delete d[e], O(), f = void 0;
|
|
36
|
+
},
|
|
34
37
|
parent: x,
|
|
35
38
|
listeners: p,
|
|
36
39
|
pathListeners: h,
|
|
37
40
|
changeListeners: m,
|
|
38
41
|
interceptors: v,
|
|
42
|
+
readOnly: u?.readOnly ?? [],
|
|
39
43
|
reportError: C,
|
|
40
44
|
invalidateDescendants: _,
|
|
41
45
|
onDelegateToParent: t && x ? (e) => x.scopeClaims?.claimDelegatedWrite(e, S) : void 0
|
|
@@ -56,13 +60,14 @@ function l(l, u) {
|
|
|
56
60
|
id: u?.id,
|
|
57
61
|
scopePath: u?.scopePath,
|
|
58
62
|
getState: E,
|
|
63
|
+
getOwnState: T,
|
|
59
64
|
getPath: D,
|
|
60
65
|
setState: F,
|
|
61
66
|
get: ((e) => e === void 0 ? E() : D(e)),
|
|
62
67
|
set: F,
|
|
63
68
|
watch: ((e, t) => typeof e == "function" ? H(e) : U(e, t)),
|
|
64
69
|
withBase: (e) => {
|
|
65
|
-
let t = (t, n) => F(t === void 0 ? e : `${e}.${t}`, n);
|
|
70
|
+
let t = (t, n, r) => F(t === void 0 ? e : `${e}.${t}`, n, r);
|
|
66
71
|
return {
|
|
67
72
|
getState: (t) => {
|
|
68
73
|
let n = D(e);
|
|
@@ -6,11 +6,13 @@ export type SetStateDeps<TState extends object> = {
|
|
|
6
6
|
getOwnSnapshot: () => TState;
|
|
7
7
|
setOwnState: (next: TState) => void;
|
|
8
8
|
mutateOwnKey: (key: string, value: unknown) => void;
|
|
9
|
+
deleteOwnKey: (key: string) => void;
|
|
9
10
|
parent: StoreApi<TState> | undefined;
|
|
10
11
|
listeners: Subscribers<Listener>;
|
|
11
12
|
changeListeners: Subscribers<ChangeListener<TState>>;
|
|
12
13
|
pathListeners: PathTrie;
|
|
13
14
|
interceptors: WriteInterceptor<TState>[];
|
|
15
|
+
readOnly: ReadonlyArray<string>;
|
|
14
16
|
reportError: StoreErrorReporter<TState>;
|
|
15
17
|
invalidateDescendants: () => void;
|
|
16
18
|
onDelegateToParent?: (path: string) => void;
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import e from "../../helpers/parsePath.mjs";
|
|
2
2
|
import t from "../../helpers/getByPath.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import i from "
|
|
5
|
-
import
|
|
3
|
+
import { isDev as n } from "../../env.mjs";
|
|
4
|
+
import { UNCHANGED as r, deleteByPath as i, writeByPath as a } from "./writeByPath.mjs";
|
|
5
|
+
import o from "../../helpers/setByPath.mjs";
|
|
6
|
+
import { CANCEL as s } from "../../types/StoreTypes.mjs";
|
|
6
7
|
//#region src/createStore/helpers/createSetState.ts
|
|
7
|
-
var
|
|
8
|
-
let r = 0, i =
|
|
8
|
+
var c = Symbol("no-error"), l = (e, t, n) => {
|
|
9
|
+
let r = 0, i = c;
|
|
9
10
|
for (; r < n;) try {
|
|
10
11
|
for (; r < n; r++) e[r](t);
|
|
11
12
|
} catch (e) {
|
|
12
|
-
i ===
|
|
13
|
+
i === c && (i = e), r++;
|
|
13
14
|
}
|
|
14
15
|
return i;
|
|
15
|
-
},
|
|
16
|
+
}, u = "__proto__", d = (e, t) => {
|
|
16
17
|
let n = e;
|
|
17
18
|
for (let e = 0, r = t.length; e < r; e++) {
|
|
18
19
|
if (typeof n != "object" || !n || !Object.hasOwn(n, t[e])) return !1;
|
|
@@ -20,137 +21,175 @@ var o = Symbol("no-error"), s = (e, t, n) => {
|
|
|
20
21
|
}
|
|
21
22
|
return !0;
|
|
22
23
|
};
|
|
23
|
-
function
|
|
24
|
-
let { getOwnState:
|
|
24
|
+
function f(f) {
|
|
25
|
+
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) => {
|
|
26
|
+
for (let t = 0, n = C.length; t < n; t++) {
|
|
27
|
+
let n = C[t];
|
|
28
|
+
if (e === n || e.startsWith(`${n}.`) || n.startsWith(`${e}.`)) return !0;
|
|
29
|
+
}
|
|
30
|
+
return !1;
|
|
31
|
+
}, O = (e) => {
|
|
32
|
+
if (C.length === 0 || !D(e)) return !1;
|
|
33
|
+
if (n) throw Error(`@plitzi/nexus: refused to write to read-only path "${e}"`);
|
|
34
|
+
return !0;
|
|
35
|
+
}, k = (e, t, n) => {
|
|
25
36
|
let r = t;
|
|
26
|
-
for (let t = 0, i =
|
|
37
|
+
for (let t = 0, i = S.length; t < i; t++) {
|
|
27
38
|
let i;
|
|
28
39
|
try {
|
|
29
|
-
i =
|
|
40
|
+
i = S[t]({
|
|
30
41
|
path: e,
|
|
31
42
|
value: r,
|
|
32
43
|
prev: n
|
|
33
44
|
});
|
|
34
45
|
} catch (t) {
|
|
35
|
-
return
|
|
46
|
+
return w(t, "beforeChange", e), s;
|
|
36
47
|
}
|
|
37
|
-
if (i ===
|
|
48
|
+
if (i === s) return s;
|
|
38
49
|
i !== void 0 && (r = i);
|
|
39
50
|
}
|
|
40
51
|
return r;
|
|
41
|
-
},
|
|
52
|
+
}, A = 0, j = /* @__PURE__ */ new Set(), M = (e, t) => {
|
|
42
53
|
let { items: n } = e;
|
|
43
|
-
if (
|
|
44
|
-
for (let e = 0, t = n.length; e < t; e++)
|
|
54
|
+
if (A > 0) {
|
|
55
|
+
for (let e = 0, t = n.length; e < t; e++) j.add(n[e]);
|
|
45
56
|
return;
|
|
46
57
|
}
|
|
47
58
|
if (n.length !== 0) {
|
|
48
59
|
e.begin();
|
|
49
60
|
try {
|
|
50
|
-
let e =
|
|
51
|
-
e !==
|
|
61
|
+
let e = l(n, t, n.length);
|
|
62
|
+
e !== c && w(e, "notify", t);
|
|
52
63
|
} finally {
|
|
53
64
|
e.end();
|
|
54
65
|
}
|
|
55
66
|
}
|
|
56
|
-
},
|
|
57
|
-
|
|
67
|
+
}, N = (e) => {
|
|
68
|
+
A++;
|
|
58
69
|
try {
|
|
59
70
|
return e();
|
|
60
71
|
} finally {
|
|
61
|
-
if (
|
|
62
|
-
let e = [...
|
|
63
|
-
|
|
64
|
-
let t =
|
|
65
|
-
t !==
|
|
72
|
+
if (A--, A === 0 && j.size > 0) {
|
|
73
|
+
let e = [...j];
|
|
74
|
+
j.clear();
|
|
75
|
+
let t = l(e, void 0, e.length);
|
|
76
|
+
t !== c && w(t, "notify", void 0);
|
|
66
77
|
}
|
|
67
78
|
}
|
|
68
|
-
},
|
|
79
|
+
}, P = (e, n, r) => {
|
|
69
80
|
let i = {
|
|
70
81
|
path: e,
|
|
71
82
|
prev: n,
|
|
72
83
|
next: r,
|
|
73
84
|
prevValue: e === void 0 ? n : t(n, e),
|
|
74
85
|
nextValue: e === void 0 ? r : t(r, e)
|
|
75
|
-
}, { items: a } =
|
|
76
|
-
|
|
86
|
+
}, { items: a } = x;
|
|
87
|
+
x.begin();
|
|
77
88
|
try {
|
|
78
|
-
let t =
|
|
79
|
-
t !==
|
|
89
|
+
let t = l(a, i, a.length);
|
|
90
|
+
t !== c && w(t, "onChange", e);
|
|
80
91
|
} finally {
|
|
81
|
-
|
|
92
|
+
x.end();
|
|
82
93
|
}
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
let o =
|
|
94
|
+
}, F = (e, t) => {
|
|
95
|
+
b.walkAncestors(t, (t) => M(t, e));
|
|
96
|
+
}, I = (n, r, i, a) => {
|
|
97
|
+
let o = b.getDescendants(n);
|
|
87
98
|
if (o) for (let s of o) {
|
|
88
|
-
let o =
|
|
99
|
+
let o = b.direct.get(s);
|
|
89
100
|
if (!o) continue;
|
|
90
101
|
let c = e(s).slice(a);
|
|
91
|
-
t(r, c) !== t(i, c) &&
|
|
102
|
+
t(r, c) !== t(i, c) && M(o, n);
|
|
92
103
|
}
|
|
93
|
-
},
|
|
94
|
-
let
|
|
95
|
-
if (e &&
|
|
96
|
-
let t =
|
|
97
|
-
if (t ===
|
|
98
|
-
|
|
104
|
+
}, L = (e, r, i, a) => {
|
|
105
|
+
let c = e ? t(i, e) : void 0, l = e ? typeof r == "function" ? r(c) : r : void 0;
|
|
106
|
+
if (e && S.length > 0) {
|
|
107
|
+
let t = k(e, l, c);
|
|
108
|
+
if (t === s) return;
|
|
109
|
+
l = t;
|
|
99
110
|
}
|
|
100
|
-
if (e &&
|
|
101
|
-
let
|
|
102
|
-
...
|
|
103
|
-
...
|
|
111
|
+
if (e && c === l) return;
|
|
112
|
+
let u = e ? o(i, e, l) : typeof r == "function" ? r(i) : {
|
|
113
|
+
...i,
|
|
114
|
+
...r
|
|
104
115
|
};
|
|
105
|
-
if (!e &&
|
|
106
|
-
let e =
|
|
107
|
-
if (e ===
|
|
108
|
-
|
|
116
|
+
if (!e && S.length > 0) {
|
|
117
|
+
let e = k(void 0, u, i);
|
|
118
|
+
if (e === s) return;
|
|
119
|
+
u = e;
|
|
120
|
+
}
|
|
121
|
+
if (u !== i) {
|
|
122
|
+
if (C.length > 0) for (let e = 0, r = C.length; e < r; e++) {
|
|
123
|
+
let r = C[e];
|
|
124
|
+
if (t(i, r) !== t(u, r)) {
|
|
125
|
+
if (n) throw Error(`@plitzi/nexus: refused to write to read-only path "${C[e]}"`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
h(u), x.length > 0 && P(e, i, u), T(), a && (M(y, e), b.size > 0 && b.direct.forEach((n, r) => {
|
|
130
|
+
t(i, r) !== t(u, r) && M(n, e);
|
|
131
|
+
}));
|
|
109
132
|
}
|
|
110
|
-
l !== r && (p(l), v.length > 0 && O(e, r, l), x(), o && (E(g, e), _.size > 0 && _.direct.forEach((n, i) => {
|
|
111
|
-
t(r, i) !== t(l, i) && E(n, e);
|
|
112
|
-
})));
|
|
113
133
|
};
|
|
114
134
|
return {
|
|
115
|
-
setState: (
|
|
116
|
-
let
|
|
117
|
-
if (typeof
|
|
118
|
-
if (
|
|
119
|
-
|
|
135
|
+
setState: (n, o, c = {}) => {
|
|
136
|
+
let { canPropagate: l = !0, unmount: f = !1 } = c, C = p();
|
|
137
|
+
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)`);
|
|
138
|
+
if (typeof n == "string" && O(n)) return;
|
|
139
|
+
if (v && typeof n == "string" && !(n.indexOf(".") === -1 ? Object.hasOwn(C, n) : d(C, e(n)))) {
|
|
140
|
+
E?.(n), v.setState(n, o, {
|
|
141
|
+
canPropagate: l,
|
|
142
|
+
unmount: f
|
|
143
|
+
});
|
|
120
144
|
return;
|
|
121
145
|
}
|
|
122
|
-
if (typeof
|
|
123
|
-
|
|
146
|
+
if (typeof n != "string") {
|
|
147
|
+
L(n, o, C, l);
|
|
124
148
|
return;
|
|
125
149
|
}
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
let
|
|
130
|
-
if (
|
|
131
|
-
|
|
150
|
+
if (n.indexOf(".") === -1) {
|
|
151
|
+
if (f) {
|
|
152
|
+
if (!Object.hasOwn(C, n)) return;
|
|
153
|
+
let e = C[n];
|
|
154
|
+
if (S.length > 0 && k(n, void 0, e) === s) return;
|
|
155
|
+
let t = x.length > 0 ? m() : void 0;
|
|
156
|
+
if (_(n), t !== void 0 && P(n, t, m()), l && (M(y, n), b.size > 0)) {
|
|
157
|
+
let t = b.direct.get(n);
|
|
158
|
+
t && M(t, n), I(n, e, void 0, 1);
|
|
159
|
+
}
|
|
160
|
+
T();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
let e = C[n], t = typeof o == "function" ? o(e) : o, r = t;
|
|
164
|
+
if (S.length > 0) {
|
|
165
|
+
let i = k(n, t, e);
|
|
166
|
+
if (i === s) return;
|
|
167
|
+
r = i;
|
|
132
168
|
}
|
|
133
|
-
if (e ===
|
|
134
|
-
let
|
|
135
|
-
if (
|
|
136
|
-
let t =
|
|
137
|
-
t &&
|
|
169
|
+
if (e === r) return;
|
|
170
|
+
let i = x.length > 0 ? m() : void 0;
|
|
171
|
+
if (g(n, r), i !== void 0 && P(n, i, m()), l && (M(y, n), b.size > 0)) {
|
|
172
|
+
let t = b.direct.get(n);
|
|
173
|
+
t && M(t, n), I(n, e, r, 1);
|
|
138
174
|
}
|
|
139
|
-
|
|
175
|
+
T();
|
|
140
176
|
return;
|
|
141
177
|
}
|
|
142
|
-
let
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
178
|
+
let w = e(n), D;
|
|
179
|
+
if (f) {
|
|
180
|
+
if (S.length > 0 && k(n, void 0, t(C, n)) === s) return;
|
|
181
|
+
D = i(C, w);
|
|
182
|
+
} else if (S.length > 0) {
|
|
183
|
+
let e = t(C, n), r = typeof o == "function" ? o(e) : o, i = k(n, r, e);
|
|
184
|
+
if (i === s) return;
|
|
185
|
+
D = a(C, n, w, i, !1);
|
|
186
|
+
} else D = a(C, n, w, o, typeof o == "function");
|
|
187
|
+
if (D === r) return;
|
|
188
|
+
let A = D;
|
|
189
|
+
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();
|
|
151
190
|
},
|
|
152
|
-
batch:
|
|
191
|
+
batch: N
|
|
153
192
|
};
|
|
154
193
|
}
|
|
155
194
|
//#endregion
|
|
156
|
-
export {
|
|
195
|
+
export { f as createSetState };
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import { isTest as e } from "../../env.mjs";
|
|
1
2
|
//#region src/createStore/helpers/scopeCollisions.ts
|
|
2
|
-
var e = () => {
|
|
3
|
-
let
|
|
4
|
-
return { claimDelegatedWrite(
|
|
5
|
-
let
|
|
6
|
-
if (
|
|
7
|
-
|
|
3
|
+
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 = () => {
|
|
4
|
+
let n = /* @__PURE__ */ new Map();
|
|
5
|
+
return { claimDelegatedWrite(r, i) {
|
|
6
|
+
let a = n.get(r);
|
|
7
|
+
if (a !== void 0 && a !== i) {
|
|
8
|
+
if (e) throw Error(t(r));
|
|
9
|
+
console.warn(t(r));
|
|
8
10
|
return;
|
|
9
11
|
}
|
|
10
|
-
|
|
12
|
+
n.set(r, i);
|
|
11
13
|
} };
|
|
12
14
|
};
|
|
13
15
|
//#endregion
|
|
14
|
-
export {
|
|
16
|
+
export { n as createScopeClaims };
|
|
@@ -8,4 +8,5 @@ export declare const UNCHANGED: unique symbol;
|
|
|
8
8
|
* - `true` — force codegen even if the probe fails (useful for testing).
|
|
9
9
|
*/
|
|
10
10
|
export declare const setCodegenEnabled: (enabled: boolean | undefined) => void;
|
|
11
|
+
export declare const deleteByPath: (root: unknown, segments: readonly string[]) => Record<string, unknown> | typeof UNCHANGED;
|
|
11
12
|
export declare const writeByPath: (root: unknown, path: string, segments: readonly string[], value: unknown, isFn: boolean) => Record<string, unknown> | typeof UNCHANGED;
|
|
@@ -40,7 +40,19 @@ var e = Symbol("unchanged"), t = (e) => /^\d+$/.test(e), n = (e) => Array.isArra
|
|
|
40
40
|
if (n.some(t)) return;
|
|
41
41
|
let i = s(n);
|
|
42
42
|
return f.size >= p && f.delete(f.keys().next().value), f.set(e, i), i;
|
|
43
|
-
}, h = (t,
|
|
43
|
+
}, h = (t, r, i) => {
|
|
44
|
+
if (typeof t != "object" || !t) return e;
|
|
45
|
+
let a = t, o = r[i];
|
|
46
|
+
if (!Object.hasOwn(a, o)) return e;
|
|
47
|
+
if (i === r.length - 1) {
|
|
48
|
+
let e = n(a);
|
|
49
|
+
return Array.isArray(e) ? e.splice(Number(o), 1) : delete e[o], e;
|
|
50
|
+
}
|
|
51
|
+
let s = h(a[o], r, i + 1);
|
|
52
|
+
if (s === e) return e;
|
|
53
|
+
let c = n(a);
|
|
54
|
+
return c[o] = s, c;
|
|
55
|
+
}, g = (e, t) => h(e, t, 0), _ = (t, n, i, a, o) => {
|
|
44
56
|
let s = m(n, i);
|
|
45
57
|
if (s) {
|
|
46
58
|
let n = s(t, a, o);
|
|
@@ -49,4 +61,4 @@ var e = Symbol("unchanged"), t = (e) => /^\d+$/.test(e), n = (e) => Array.isArra
|
|
|
49
61
|
return r(t, i, 0, a, o);
|
|
50
62
|
};
|
|
51
63
|
//#endregion
|
|
52
|
-
export { e as UNCHANGED, d as setCodegenEnabled,
|
|
64
|
+
export { e as UNCHANGED, g as deleteByPath, d as setCodegenEnabled, _ as writeByPath };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StoreApi } from './types';
|
|
2
|
+
export type DevStore = StoreApi<Record<string, unknown>>;
|
|
3
|
+
export type DevStoreEntry = {
|
|
4
|
+
uid: string;
|
|
5
|
+
store: DevStore;
|
|
6
|
+
scopeId?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const registerDevStore: (store: StoreApi<any>, scopeId?: string, name?: string) => (() => void);
|
|
10
|
+
export declare const subscribeDevStores: (listener: () => void) => (() => void);
|
|
11
|
+
export declare const getDevStoresSnapshot: () => ReadonlyArray<DevStoreEntry>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/devStoreRegistry.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set(), n = 0, r = [], i = () => {
|
|
3
|
+
r = [...e.values()];
|
|
4
|
+
for (let e of t) e();
|
|
5
|
+
}, a = (t, r, a) => {
|
|
6
|
+
let o = t;
|
|
7
|
+
return e.set(o, {
|
|
8
|
+
uid: `dev-store-${++n}`,
|
|
9
|
+
store: o,
|
|
10
|
+
scopeId: r,
|
|
11
|
+
name: a
|
|
12
|
+
}), i(), () => {
|
|
13
|
+
e.delete(o), i();
|
|
14
|
+
};
|
|
15
|
+
}, o = (e) => (t.add(e), () => {
|
|
16
|
+
t.delete(e);
|
|
17
|
+
}), s = () => r;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { s as getDevStoresSnapshot, a as registerDevStore, o as subscribeDevStores };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export { createRecorder } from './middleware/recorderMiddleware';
|
|
|
12
12
|
export { cascade } from './middleware/cascade';
|
|
13
13
|
export { getStoreHistory } from './middleware/historyMiddleware';
|
|
14
14
|
export { createServerSnapshot, isServerSnapshot } from './rsc';
|
|
15
|
+
export { registerDevStore, subscribeDevStores, getDevStoresSnapshot } from './devStoreRegistry';
|
|
16
|
+
export type { DevStore, DevStoreEntry } from './devStoreRegistry';
|
|
15
17
|
export * from './types';
|
|
16
18
|
export type { CreateStoreOptions } from './createStore/createStore';
|
|
17
19
|
export type { AsyncOptions, AsyncResource, AsyncSnapshot, AsyncStatus } from './async/createAsync';
|
package/dist/index.mjs
CHANGED
|
@@ -12,4 +12,5 @@ import { CANCEL as d } from "./types/StoreTypes.mjs";
|
|
|
12
12
|
import f from "./createStore/createStore.mjs";
|
|
13
13
|
import { createRecorder as p } from "./middleware/recorderMiddleware.mjs";
|
|
14
14
|
import { createServerSnapshot as m, isServerSnapshot as h } from "./rsc/index.mjs";
|
|
15
|
-
|
|
15
|
+
import { getDevStoresSnapshot as g, registerDevStore as _, subscribeDevStores as v } from "./devStoreRegistry.mjs";
|
|
16
|
+
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 };
|
|
@@ -19,8 +19,9 @@ export type StoreProviderProps<TState extends object = any> = {
|
|
|
19
19
|
inherit?: 'snapshot' | 'live';
|
|
20
20
|
autoSync?: boolean;
|
|
21
21
|
middlewares?: StoreMiddleware<TState>[];
|
|
22
|
+
name?: string;
|
|
22
23
|
children?: ReactNode;
|
|
23
24
|
};
|
|
24
|
-
declare const StoreProvider: <TState extends object = any>({ store, id, segment, isolate, path, value, inherit, autoSync, middlewares, children }: StoreProviderProps<TState>) => import("react").JSX.Element;
|
|
25
|
+
declare const StoreProvider: <TState extends object = any>({ store, id, segment, isolate, path, value, inherit, autoSync, middlewares, name, children }: StoreProviderProps<TState>) => import("react").JSX.Element;
|
|
25
26
|
export { StoreContext, StoreRegistryContext };
|
|
26
27
|
export default StoreProvider;
|
|
@@ -1,62 +1,66 @@
|
|
|
1
1
|
import { isDev as e } from "../env.mjs";
|
|
2
2
|
import t from "../createStore/index.mjs";
|
|
3
3
|
import { isServerSnapshot as n, stripServerFlag as r } from "../rsc/index.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
4
|
+
import { registerDevStore as i } from "../devStoreRegistry.mjs";
|
|
5
|
+
import a from "./DevStoreScopeContext.mjs";
|
|
6
|
+
import { StoreContext as o, StoreRegistryContext as s, findStoreInRegistry as c } from "./StoreContext.mjs";
|
|
7
|
+
import l from "./hooks/useStoreSync.mjs";
|
|
8
|
+
import { createContext as u, useContext as d, useEffect as f, useMemo as p, useRef as m } from "react";
|
|
9
|
+
import { jsx as h } from "react/jsx-runtime";
|
|
8
10
|
//#region src/react/StoreProvider.tsx
|
|
9
|
-
var
|
|
10
|
-
let
|
|
11
|
-
let e =
|
|
11
|
+
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 }) => {
|
|
12
|
+
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(() => {
|
|
13
|
+
let e = C === "snapshot" && O ? O.getState() : {}, t = typeof S == "function" ? S(e) : {
|
|
12
14
|
...e,
|
|
13
|
-
...
|
|
15
|
+
...S
|
|
14
16
|
};
|
|
15
17
|
return n(t) ? r(t) : t;
|
|
16
18
|
}, [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
]),
|
|
21
|
-
let e =
|
|
22
|
-
return e.length === 0 ?
|
|
23
|
-
}, [
|
|
24
|
-
|
|
25
|
-
id:
|
|
26
|
-
scopePath:
|
|
27
|
-
exclusive:
|
|
28
|
-
parent:
|
|
29
|
-
middlewares:
|
|
19
|
+
C,
|
|
20
|
+
O,
|
|
21
|
+
S
|
|
22
|
+
]), L = T ?? [], R = k ? [...k, ...L] : L, z = p(() => {
|
|
23
|
+
let e = L.filter(_);
|
|
24
|
+
return e.length === 0 ? k : [...k ?? [], ...e];
|
|
25
|
+
}, [k, T]);
|
|
26
|
+
P.current ||= u ?? t(() => I, {
|
|
27
|
+
id: v,
|
|
28
|
+
scopePath: N,
|
|
29
|
+
exclusive: F ? b : void 0,
|
|
30
|
+
parent: F ? O : void 0,
|
|
31
|
+
middlewares: R.length > 0 ? R : void 0,
|
|
30
32
|
deferHydrate: !0
|
|
31
33
|
});
|
|
32
|
-
let
|
|
33
|
-
id:
|
|
34
|
-
store:
|
|
35
|
-
parent:
|
|
36
|
-
} :
|
|
37
|
-
|
|
38
|
-
e &&
|
|
39
|
-
}, [
|
|
40
|
-
|
|
41
|
-
}), [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
let B = p(() => v ? {
|
|
35
|
+
id: v,
|
|
36
|
+
store: P.current,
|
|
37
|
+
parent: A
|
|
38
|
+
} : A, [v, A]), V = m(!1);
|
|
39
|
+
f(() => {
|
|
40
|
+
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.`));
|
|
41
|
+
}, [v, A]), f(() => (F && !u && P.current?.reconnect?.(), () => {
|
|
42
|
+
F && !u && P.current?.destroy?.();
|
|
43
|
+
}), [F, u]), f(() => {
|
|
44
|
+
if (e) return i(P.current, j, E);
|
|
45
|
+
}, [j, E]);
|
|
46
|
+
let H = m(!1);
|
|
47
|
+
f(() => {
|
|
48
|
+
!H.current && P.current?.hydrate && (P.current.hydrate(), H.current = !0);
|
|
49
|
+
}, []), l(x, x ? S : I, {
|
|
50
|
+
enabled: !!S && w,
|
|
51
|
+
store: P.current
|
|
48
52
|
});
|
|
49
|
-
let
|
|
50
|
-
value:
|
|
51
|
-
children:
|
|
53
|
+
let U = /* @__PURE__ */ h(o, {
|
|
54
|
+
value: P.current,
|
|
55
|
+
children: D
|
|
52
56
|
});
|
|
53
|
-
return
|
|
54
|
-
value:
|
|
55
|
-
children:
|
|
56
|
-
})),
|
|
57
|
-
value:
|
|
58
|
-
children:
|
|
59
|
-
})),
|
|
57
|
+
return B !== A && (U = /* @__PURE__ */ h(s, {
|
|
58
|
+
value: B,
|
|
59
|
+
children: U
|
|
60
|
+
})), z !== k && (U = /* @__PURE__ */ h(g, {
|
|
61
|
+
value: z,
|
|
62
|
+
children: U
|
|
63
|
+
})), U;
|
|
60
64
|
};
|
|
61
65
|
//#endregion
|
|
62
|
-
export {
|
|
66
|
+
export { o as StoreContext, s as StoreRegistryContext, v as default };
|
|
@@ -29,11 +29,11 @@ function a(e, i, a, o) {
|
|
|
29
29
|
if (m.current = a, s) e.setState(void 0, (e) => ({
|
|
30
30
|
...e,
|
|
31
31
|
...a
|
|
32
|
-
}), t);
|
|
32
|
+
}), { canPropagate: t });
|
|
33
33
|
else if (c) {
|
|
34
34
|
let n = i(e.getState());
|
|
35
|
-
e.setState(n, a, t);
|
|
36
|
-
} else e.setState(i, a, t);
|
|
35
|
+
e.setState(n, a, { canPropagate: t });
|
|
36
|
+
} else e.setState(i, a, { canPropagate: t });
|
|
37
37
|
};
|
|
38
38
|
p === "render" ? v && y() : (v && g && y(!1), n(() => {
|
|
39
39
|
v && !g && y();
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as StoreProvider, StoreContext, StoreRegistryContext } from './StoreProvider';
|
|
2
|
+
export { default as DevStoreScopeContext } from './DevStoreScopeContext';
|
|
2
3
|
export { findStoreInRegistry } from './StoreContext';
|
|
3
4
|
export { createStoreHook } from './createStoreHook';
|
|
4
5
|
export { default as useStore, defaultMultiEqualityFn } from './hooks/useStore';
|
|
@@ -12,6 +13,7 @@ export { useDerived } from './hooks/useDerived';
|
|
|
12
13
|
export { useStoreHistory } from './hooks/useStoreHistory';
|
|
13
14
|
export { useEntity, useEntityOne, useEntityIds, useEntityAll } from './hooks/useEntity';
|
|
14
15
|
export { default as useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
|
|
16
|
+
export type { StoreApi } from '../types';
|
|
15
17
|
export type { StoreProviderProps } from './StoreProvider';
|
|
16
18
|
export type { StoreRegistry } from './StoreContext';
|
|
17
19
|
export type { UseStoreHistoryReturn } from './hooks/useStoreHistory';
|
package/dist/react/index.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import i from "./
|
|
4
|
-
import a from "./
|
|
5
|
-
import o from "./
|
|
6
|
-
import s from "./
|
|
7
|
-
import c from "./hooks/
|
|
8
|
-
import l from "./hooks/
|
|
9
|
-
import
|
|
10
|
-
import d from "./
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
1
|
+
import e from "./DevStoreScopeContext.mjs";
|
|
2
|
+
import { StoreContext as t, StoreRegistryContext as n, findStoreInRegistry as r } from "./StoreContext.mjs";
|
|
3
|
+
import { defaultMultiEqualityFn as i } from "./hooks/shared.mjs";
|
|
4
|
+
import a from "./useIsomorphicLayoutEffect.mjs";
|
|
5
|
+
import o from "./hooks/useStoreSync.mjs";
|
|
6
|
+
import s from "./StoreProvider.mjs";
|
|
7
|
+
import c from "./hooks/useStore.mjs";
|
|
8
|
+
import l from "./hooks/useStoreGetter.mjs";
|
|
9
|
+
import u from "./hooks/useStoreSetter.mjs";
|
|
10
|
+
import { createStoreHook as d } from "./createStoreHook.mjs";
|
|
11
|
+
import f from "./hooks/useStoreById.mjs";
|
|
12
|
+
import { useAsync as p } from "./hooks/useAsync.mjs";
|
|
13
|
+
import { useAsyncValue as m } from "./hooks/useAsyncValue.mjs";
|
|
14
|
+
import { useDerived as h } from "./hooks/useDerived.mjs";
|
|
15
|
+
import { useStoreHistory as g } from "./hooks/useStoreHistory.mjs";
|
|
16
|
+
import { useEntity as _, useEntityAll as v, useEntityIds as y, useEntityOne as b } from "./hooks/useEntity.mjs";
|
|
17
|
+
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 };
|
|
@@ -56,9 +56,13 @@ export type MiddlewareOptions<T extends object> = {
|
|
|
56
56
|
enabled?: boolean | ((state: T) => boolean);
|
|
57
57
|
};
|
|
58
58
|
export type Listener = (changedPath?: Path) => void;
|
|
59
|
+
export type SetStateOptions = {
|
|
60
|
+
canPropagate?: boolean;
|
|
61
|
+
unmount?: boolean;
|
|
62
|
+
};
|
|
59
63
|
export type SetState<T> = {
|
|
60
|
-
(path: undefined, value: T | ((prev: T) => T),
|
|
61
|
-
<P extends PathOf<T>>(path: P, value: PathValue<T, P> | ((prev: PathValue<T, P>) => PathValue<T, P>),
|
|
64
|
+
(path: undefined, value: T | ((prev: T) => T), options?: SetStateOptions): void;
|
|
65
|
+
<P extends PathOf<T>>(path: P, value: PathValue<T, P> | ((prev: PathValue<T, P>) => PathValue<T, P>), options?: SetStateOptions): void;
|
|
62
66
|
};
|
|
63
67
|
export type GetState<T> = () => T;
|
|
64
68
|
export type BoundStore<TBase> = {
|
|
@@ -90,6 +94,7 @@ export type StoreApi<T> = {
|
|
|
90
94
|
id?: string;
|
|
91
95
|
scopePath?: string;
|
|
92
96
|
getState: GetState<T>;
|
|
97
|
+
getOwnState: () => T;
|
|
93
98
|
getPath: <P extends PathOf<T>>(path: P) => PathValue<T, P> | undefined;
|
|
94
99
|
setState: SetState<T>;
|
|
95
100
|
get: {
|
|
@@ -165,12 +170,12 @@ export type GetterTuple<TState extends object, Entries extends ReadonlyArray<Pat
|
|
|
165
170
|
};
|
|
166
171
|
export type UseStoreGetterOptions<TState extends object = object> = StoreHookBaseOptions<TState>;
|
|
167
172
|
export type SetStateFn<TState extends object> = {
|
|
168
|
-
(path: undefined, value: TState | ((prev: TState) => TState)): void;
|
|
169
|
-
<P extends PathOf<TState>>(path: P, value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)): void;
|
|
173
|
+
(path: undefined, value: TState | ((prev: TState) => TState), options?: SetStateOptions): void;
|
|
174
|
+
<P extends PathOf<TState>>(path: P, value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>), options?: SetStateOptions): void;
|
|
170
175
|
};
|
|
171
176
|
export type SetFromBaseFn<TBase> = TBase extends object ? {
|
|
172
|
-
(subPath: undefined, value: TBase | ((prev: TBase) => TBase)): void;
|
|
173
|
-
<SubP extends PathOf<TBase>>(subPath: SubP, value: PathValue<TBase, SubP> | ((prev: PathValue<TBase, SubP>) => PathValue<TBase, SubP>)): void;
|
|
174
|
-
} : (subPath: undefined, value: TBase) => void;
|
|
177
|
+
(subPath: undefined, value: TBase | ((prev: TBase) => TBase), options?: SetStateOptions): void;
|
|
178
|
+
<SubP extends PathOf<TBase>>(subPath: SubP, value: PathValue<TBase, SubP> | ((prev: PathValue<TBase, SubP>) => PathValue<TBase, SubP>), options?: SetStateOptions): void;
|
|
179
|
+
} : (subPath: undefined, value: TBase, options?: SetStateOptions) => void;
|
|
175
180
|
export type UseStoreSetterOptions<TState extends object = object> = StoreHookBaseOptions<TState>;
|
|
176
181
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plitzi/nexus",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.6",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"type": "module",
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"eslint": "^9.39.
|
|
27
|
-
"react": "^19.2.
|
|
28
|
-
"react-dom": "^19.2.
|
|
26
|
+
"eslint": "^9.39.5",
|
|
27
|
+
"react": "^19.2.8",
|
|
28
|
+
"react-dom": "^19.2.8",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
|
-
"vite": "^8.1.
|
|
30
|
+
"vite": "^8.1.5",
|
|
31
31
|
"vitest": "^4.1.10",
|
|
32
|
-
"vue": "^3.5.
|
|
32
|
+
"vue": "^3.5.40"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -128,6 +128,10 @@
|
|
|
128
128
|
"types": "./dist/derived/index.d.ts",
|
|
129
129
|
"import": "./dist/derived/index.mjs"
|
|
130
130
|
},
|
|
131
|
+
"./devStoreRegistry": {
|
|
132
|
+
"types": "./dist/devStoreRegistry.d.ts",
|
|
133
|
+
"import": "./dist/devStoreRegistry.mjs"
|
|
134
|
+
},
|
|
131
135
|
"./entities": {
|
|
132
136
|
"types": "./dist/entities/index.d.ts",
|
|
133
137
|
"import": "./dist/entities/index.mjs"
|
|
@@ -232,6 +236,10 @@
|
|
|
232
236
|
"types": "./dist/react/index.d.ts",
|
|
233
237
|
"import": "./dist/react/index.mjs"
|
|
234
238
|
},
|
|
239
|
+
"./react/DevStoreScopeContext": {
|
|
240
|
+
"types": "./dist/react/DevStoreScopeContext.d.ts",
|
|
241
|
+
"import": "./dist/react/DevStoreScopeContext.mjs"
|
|
242
|
+
},
|
|
235
243
|
"./react/StoreContext": {
|
|
236
244
|
"types": "./dist/react/StoreContext.d.ts",
|
|
237
245
|
"import": "./dist/react/StoreContext.mjs"
|