@plitzi/nexus 0.31.1 → 0.32.0

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +197 -1
  3. package/dist/StoreProvider.mjs +44 -38
  4. package/dist/async/createAsync.mjs +8 -1
  5. package/dist/createStore/createStore.d.ts +11 -47
  6. package/dist/createStore/createStore.mjs +57 -39
  7. package/dist/createStore/helpers/PathTrie.d.ts +2 -0
  8. package/dist/createStore/helpers/PathTrie.mjs +55 -20
  9. package/dist/createStore/helpers/createChainReads.d.ts +1 -1
  10. package/dist/createStore/helpers/createChainReads.mjs +12 -13
  11. package/dist/createStore/helpers/createSetState.mjs +24 -33
  12. package/dist/createStore/helpers/writeByPath.mjs +1 -0
  13. package/dist/createStore/hooks/shared.d.ts +1 -2
  14. package/dist/createStore/hooks/shared.mjs +7 -18
  15. package/dist/createStore/hooks/useStore.d.ts +4 -49
  16. package/dist/createStore/hooks/useStore.mjs +19 -27
  17. package/dist/createStore/hooks/useStoreGetter.d.ts +2 -5
  18. package/dist/createStore/hooks/useStoreGetter.mjs +19 -22
  19. package/dist/createStore/hooks/useStoreSetter.mjs +2 -4
  20. package/dist/derived/createDerived.d.ts +1 -1
  21. package/dist/derived/createDerived.mjs +12 -9
  22. package/dist/entities/createEntityStore.d.ts +38 -0
  23. package/dist/entities/createEntityStore.mjs +102 -0
  24. package/dist/entities/index.d.ts +2 -0
  25. package/dist/entities/index.mjs +2 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.mjs +11 -9
  28. package/dist/middleware/historyMiddleware.d.ts +3 -3
  29. package/dist/middleware/historyMiddleware.mjs +22 -17
  30. package/dist/middleware/index.d.ts +1 -1
  31. package/dist/middleware/isDisabled.d.ts +2 -0
  32. package/dist/middleware/isDisabled.mjs +4 -0
  33. package/dist/middleware/loggerMiddleware.d.ts +2 -2
  34. package/dist/middleware/loggerMiddleware.mjs +14 -15
  35. package/dist/middleware/persistMiddleware.d.ts +7 -5
  36. package/dist/middleware/persistMiddleware.mjs +58 -26
  37. package/dist/middleware/reduxDevToolsMiddleware.d.ts +2 -2
  38. package/dist/middleware/reduxDevToolsMiddleware.mjs +26 -21
  39. package/dist/next/index.d.ts +26 -0
  40. package/dist/next/index.mjs +18 -0
  41. package/dist/rsc/index.d.ts +29 -0
  42. package/dist/rsc/index.mjs +18 -0
  43. package/dist/types/StoreTypes.d.ts +33 -21
  44. package/logo.svg +57 -0
  45. package/package.json +22 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @plitzi/nexus
2
2
 
3
+ ## 0.32.0
4
+
5
+ ### Minor Changes
6
+
7
+ - v0.32.0
8
+
9
+ ## 0.31.2
10
+
11
+ ### Patch Changes
12
+
13
+ - v0.31.2
14
+
3
15
  ## 0.31.1
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
+ <p align="center">
2
+ <img src="./logo.svg" alt="@plitzi/nexus" width="640" />
3
+ </p>
4
+
1
5
  # @plitzi/nexus
2
6
 
3
- A lightweight, type-safe React store built on `useSyncExternalStore`. You subscribe to **dot-notation paths** and re-render only when that exact value changes — no selectors, no reducers, no action types. On top of that core it ships scoped stores, time-travel, derived values, an entity adapter, and a middleware pipeline (logger / persist / history).
7
+ A lightweight, type-safe React store built on `useSyncExternalStore`. You subscribe to **dot-notation paths** and re-render only when that exact value changes — no selectors, no reducers, no action types. On top of that core it ships scoped stores, time-travel, derived values, an entity adapter, and a middleware pipeline (logger / persist / history). Fully compatible with SSR, React Server Components, and Next.js App Router.
4
8
 
5
9
  ```bash
6
10
  npm install @plitzi/nexus # peer deps: react@^18 || ^19, react-dom@^18 || ^19
@@ -33,6 +37,10 @@ function Counter() {
33
37
  | `createDerived` / `useDerived` | A memoized value computed from store paths (reselect-style). |
34
38
  | `createEntityAdapter` | CRUD updaters + selectors for a normalized `Record<id, T>` map. |
35
39
  | `loggerMiddleware` / `persistMiddleware` / `historyMiddleware` / `reduxDevToolsMiddleware` | Middlewares: log, persist to storage, record time-travel, connect to Redux DevTools. |
40
+ | `setCodegenEnabled` | Force on/off the `new Function` codegen path (auto-detects CSP/SSR). |
41
+ | `createServerSnapshot` | Mark server-fetched data for RSC → Client handoff. |
42
+ | `isServerSnapshot` | Check if a value has the SSR marker flag. |
43
+ | `bindServerAction` | Optimistic updates + revalidation for Next.js Server Actions. |
36
44
  | `getStoreHistory` / `useStoreHistory` | Undo / redo / jump-to-snapshot action log (enabled by `historyMiddleware`). |
37
45
 
38
46
  ## Architecture
@@ -528,6 +536,194 @@ setCodegenEnabled(false);
528
536
 
529
537
  Call `setCodegenEnabled(undefined)` to restore auto-detection.
530
538
 
539
+ ## Server Components & SSR
540
+
541
+ Nexus supports React Server Components (App Router) and server-side rendering (Pages Router) with no additional setup.
542
+
543
+ ### Auto-detected SSR safety
544
+
545
+ When a store is created on the server (`typeof window === 'undefined'`), Nexus automatically:
546
+
547
+ - **Disables codegen** — `new Function` is never called, so a strict Content-Security-Policy won't break SSR. Falls back to the recursive writer with identical behaviour.
548
+ - **Disables localStorage** — `persistMiddleware` falls back to a no-op storage so `getItem`/`setItem` never throw.
549
+ - **Defers hydration** — `StoreProvider` runs `persistMiddleware` hydration in a `useEffect` after React hydration, preventing hydration mismatches.
550
+
551
+ You don't need to configure anything for SSR to work.
552
+
553
+ ### Server Components → Client data handoff
554
+
555
+ Wrap server-fetched data with `createServerSnapshot` to mark it as coming from the server:
556
+
557
+ ```tsx
558
+ // app/page.tsx — Server Component (App Router)
559
+ import { StoreProvider } from '@plitzi/nexus';
560
+ import { createServerSnapshot } from '@plitzi/nexus/rsc';
561
+
562
+ export default async function Page() {
563
+ const posts = await fetch('https://api.example.com/posts').then(r => r.json());
564
+
565
+ return (
566
+ <StoreProvider value={createServerSnapshot({ posts })}>
567
+ <ClientContent />
568
+ </StoreProvider>
569
+ );
570
+ }
571
+ ```
572
+
573
+ ```tsx
574
+ // app/ClientContent.tsx — Client Component
575
+ 'use client';
576
+ const { useStore } = createStoreHook<{ posts: Post[] }>();
577
+
578
+ function ClientContent() {
579
+ const [posts] = useStore('posts');
580
+ // posts is available without a loading state — it was already fetched on the server
581
+ }
582
+ ```
583
+
584
+ The SSR flag is a non-enumerable Symbol — invisible in spread/JSON. Using `createServerSnapshot` is optional; plain objects work too.
585
+
586
+ ### `rsc` subpath exports
587
+
588
+ | Import | What it's for |
589
+ |---|---|
590
+ | `createServerSnapshot` | Mark data as server-fetched (type-level marker) |
591
+ | `isServerSnapshot` | Check if a value has the SSR flag |
592
+ | `stripServerFlag` | Remove the SSR flag from a value |
593
+
594
+ Import from `@plitzi/nexus/rsc` or from the main entry.
595
+
596
+ ### App Router — full pattern
597
+
598
+ ```tsx
599
+ // app/providers.tsx
600
+ 'use client';
601
+ import { StoreProvider, createServerSnapshot } from '@plitzi/nexus';
602
+ import type { ReactNode } from 'react';
603
+
604
+ type AppState = {
605
+ user: { name: string; email: string } | null;
606
+ theme: 'light' | 'dark';
607
+ posts: Array<{ id: string; title: string }>;
608
+ };
609
+
610
+ export function AppProviders({
611
+ children,
612
+ initialState
613
+ }: {
614
+ children: ReactNode;
615
+ initialState: AppState;
616
+ }) {
617
+ return (
618
+ <StoreProvider value={createServerSnapshot(initialState)}>
619
+ {children}
620
+ </StoreProvider>
621
+ );
622
+ }
623
+
624
+ // app/layout.tsx — Server Component
625
+ import { AppProviders } from './providers';
626
+
627
+ export default async function RootLayout({ children }: { children: React.ReactNode }) {
628
+ const user = await getServerSession();
629
+ return (
630
+ <html>
631
+ <body>
632
+ <AppProviders initialState={{ user, theme: 'light', posts: [] }}>
633
+ {children}
634
+ </AppProviders>
635
+ </body>
636
+ </html>
637
+ );
638
+ }
639
+
640
+ // app/dashboard/page.tsx — Server Component
641
+ export default async function DashboardPage() {
642
+ const posts = await db.posts.findMany();
643
+ return <DashboardClient posts={posts} />;
644
+ }
645
+
646
+ // app/dashboard/DashboardClient.tsx — Client Component
647
+ 'use client';
648
+ import { useStoreSync, createStoreHook } from '@plitzi/nexus';
649
+
650
+ type State = { posts: Array<{ id: string; title: string }> };
651
+ const { useStore } = createStoreHook<State>();
652
+
653
+ export function DashboardClient({ posts }: { posts: State['posts'] }) {
654
+ // Sync server data on mount — avoids overwriting user edits on re-renders
655
+ useStoreSync('posts', posts, { mode: 'mount' });
656
+ const [localPosts] = useStore('posts');
657
+
658
+ return (
659
+ <div>
660
+ {localPosts.map(post => <div key={post.id}>{post.title}</div>)}
661
+ </div>
662
+ );
663
+ }
664
+ ```
665
+
666
+ ### Pages Router — full pattern
667
+
668
+ ```tsx
669
+ // pages/dashboard.tsx
670
+ import { createStoreHook, StoreProvider } from '@plitzi/nexus';
671
+ import type { InferGetServerSidePropsType } from 'next';
672
+
673
+ type State = { count: number; user: { name: string } };
674
+
675
+ export const getServerSideProps = async () => {
676
+ const user = await api.getUser();
677
+ return { props: { user } };
678
+ };
679
+
680
+ export default function DashboardPage({
681
+ user
682
+ }: InferGetServerSidePropsType<typeof getServerSideProps>) {
683
+ return (
684
+ <StoreProvider value={{ user, count: 0 }}>
685
+ <Dashboard />
686
+ </StoreProvider>
687
+ );
688
+ }
689
+
690
+ // components/Dashboard.tsx
691
+ 'use client';
692
+ const { useStore } = createStoreHook<State>();
693
+
694
+ function Dashboard() {
695
+ const [user] = useStore('user');
696
+ const [count, setCount] = useStore('count');
697
+ return <div>...</div>;
698
+ }
699
+ ```
700
+
701
+ ### Server Actions (`@plitzi/nexus/next`)
702
+
703
+ The `@plitzi/nexus/next` subpath exports a `bindServerAction` helper for optimistic updates
704
+ with automatic revalidation:
705
+
706
+ ```tsx
707
+ 'use client';
708
+ import { useStore } from '@plitzi/nexus';
709
+ import { bindServerAction } from '@plitzi/nexus/next';
710
+
711
+ function Likes({ store, updateLikes }: { store: StoreApi<State>; updateLikes: ServerAction }) {
712
+ const [likes, setLikes] = useStore('likes');
713
+ const syncLikes = bindServerAction(store, 'likes', updateLikes, { revalidatePath: '/dashboard' });
714
+
715
+ return <button onClick={() => syncLikes(n => n + 1)}>{likes}</button>;
716
+ }
717
+ ```
718
+
719
+ | Import | What it's for |
720
+ |---|---|
721
+ | `bindServerAction` | Optimistic update + rollback + revalidation for Next.js Server Actions |
722
+ | `ServerActionResult` | Return type of `bindServerAction` |
723
+
724
+ This module dynamically imports from `next/cache` — it only works within Next.js App Router.
725
+ It is **not** a peer dependency, just a compatibility layer.
726
+
531
727
  ## Performance
532
728
 
533
729
  Notification is `O(depth)` — a few `Map` lookups for the changed path's prefixes — **regardless of how many subscribers exist**, so a million watchers cost the same as one for an unrelated change. The *write* copies the containers on the changed path (immutable structural sharing, the same cost Redux / Zustand / Jotai pay), so model state as a **tree / normalized map** to keep each write touching a small path. Single-segment writes mutate the live working copy in place (O(1)); snapshots from `getState()` are always distinct clones, so they stay immutable for React.
@@ -1,51 +1,57 @@
1
1
  import { StoreContext as e, StoreRegistryContext as t } from "./StoreContext.mjs";
2
2
  import n from "./createStore/hooks/useStoreSync.mjs";
3
3
  import r from "./createStore/index.mjs";
4
- import { createContext as i, useContext as a, useEffect as o, useMemo as s, useRef as c } from "react";
5
- import { jsx as l } from "react/jsx-runtime";
4
+ import { isServerSnapshot as i, stripServerFlag as a } from "./rsc/index.mjs";
5
+ import { createContext as o, useContext as s, useEffect as c, useMemo as l, useRef as u } from "react";
6
+ import { jsx as d } from "react/jsx-runtime";
6
7
  //#region src/StoreProvider.tsx
7
- var u = i(void 0), d = (e) => e.cascade === !0, f = ({ store: i, id: f, path: p, value: m, inherit: h, autoSync: g = !0, middlewares: _, children: v }) => {
8
- let y = a(e), b = a(u), x = a(t), S = c(void 0), C = h === "live", w = s(() => {
9
- let e = h === "snapshot" && y ? y.getState() : {};
10
- return typeof m == "function" ? m(e) : {
8
+ var f = o(void 0), p = (e) => e.cascade === !0, m = ({ store: o, id: m, path: h, value: g, inherit: _, autoSync: v = !0, middlewares: y, children: b }) => {
9
+ let x = s(e), S = s(f), C = s(t), w = u(void 0), T = _ === "live", E = l(() => {
10
+ let e = _ === "snapshot" && x ? x.getState() : {}, t = typeof g == "function" ? g(e) : {
11
11
  ...e,
12
- ...m
12
+ ...g
13
13
  };
14
+ return i(t) ? a(t) : t;
14
15
  }, [
15
- h,
16
- y,
17
- m
18
- ]), T = _ ?? [], E = b ? [...b, ...T] : T, D = s(() => [...b ?? [], ...T.filter(d)], [b, _]);
19
- S.current ||= i ?? r(() => w, {
20
- id: f,
21
- parent: C ? y : void 0,
22
- middlewares: E.length > 0 ? E : void 0
16
+ _,
17
+ x,
18
+ g
19
+ ]), D = y ?? [], O = S ? [...S, ...D] : D, k = l(() => [...S ?? [], ...D.filter(p)], [S, y]);
20
+ w.current ||= o ?? r(() => E, {
21
+ id: m,
22
+ parent: T ? x : void 0,
23
+ middlewares: O.length > 0 ? O : void 0,
24
+ deferHydrate: !0
23
25
  });
24
- let O = s(() => f ? {
25
- id: f,
26
- store: S.current,
27
- parent: x
28
- } : x, [f, x]);
29
- c(!1), o(() => {}, [f, x]), o(() => (C && !i && S.current?.reconnect?.(), () => {
30
- C && !i && S.current?.destroy?.();
31
- }), [C, i]);
32
- let k = !!m && g;
33
- return n(p, p ? m : w, {
34
- enabled: k && !!p,
35
- store: S.current
36
- }), n(void 0, w, {
37
- enabled: k && !p,
38
- store: S.current
39
- }), /* @__PURE__ */ l(u, {
40
- value: D.length > 0 ? D : void 0,
41
- children: /* @__PURE__ */ l(t, {
42
- value: O,
43
- children: /* @__PURE__ */ l(e, {
44
- value: S.current,
45
- children: v
26
+ let A = l(() => m ? {
27
+ id: m,
28
+ store: w.current,
29
+ parent: C
30
+ } : C, [m, C]);
31
+ u(!1), c(() => {}, [m, C]), c(() => (T && !o && w.current?.reconnect?.(), () => {
32
+ T && !o && w.current?.destroy?.();
33
+ }), [T, o]);
34
+ let j = u(!1);
35
+ c(() => {
36
+ !j.current && w.current?.hydrate && (w.current.hydrate(), j.current = !0);
37
+ }, []);
38
+ let M = !!g && v;
39
+ return n(h, h ? g : E, {
40
+ enabled: M && !!h,
41
+ store: w.current
42
+ }), n(void 0, E, {
43
+ enabled: M && !h,
44
+ store: w.current
45
+ }), /* @__PURE__ */ d(f, {
46
+ value: k.length > 0 ? k : void 0,
47
+ children: /* @__PURE__ */ d(t, {
48
+ value: A,
49
+ children: /* @__PURE__ */ d(e, {
50
+ value: w.current,
51
+ children: b
46
52
  })
47
53
  })
48
54
  });
49
55
  };
50
56
  //#endregion
51
- export { f as default };
57
+ export { m as default };
@@ -11,7 +11,14 @@ function t(t, n, r, i = {}) {
11
11
  }, d = l.get, f = (...e) => {
12
12
  a = "pending", o = void 0;
13
13
  let i = Promise.resolve().then(() => r(...e));
14
- return s = i, c = i.then(() => void 0, () => void 0), u(), i.then((e) => (i === s && (s = void 0, c = void 0, a = "success", t.setState(n, e), u()), e), (e) => {
14
+ return s = i, c = i.then(() => void 0, () => void 0), u(), i.then((e) => {
15
+ if (i === s) {
16
+ s = void 0, c = void 0, a = "success";
17
+ let r = t.getPath(n);
18
+ t.setState(n, e), Object.is(r, e) && u();
19
+ }
20
+ return e;
21
+ }, (e) => {
15
22
  throw i === s && (s = void 0, c = void 0, a = "error", o = e, u()), e;
16
23
  });
17
24
  }, p = t.subscribePath(n, u);
@@ -1,70 +1,37 @@
1
- import { GetState, GetterTuple, GetValueFn, GetValueFromBaseFn, GetValueFromBaseWithDefaultFn, MultiPathReturn, PathOf, PathOrFn, PathOrFnSetters, PathOrFnValue, PathOrFnValues, PathSetters, PathSetter, PathValue, PathValues, SetFromBaseFn, SetState, SetStateFn, StoreApi, StoreMiddleware, UseStoreGetterOptions, UseStoreMultiOptions, UseStoreOptions, UseStoreSetterOptions, UseStoreSyncMultiOptions, UseStoreSyncOptions } from '../types';
2
- declare function createStore<TState extends object>(initializer: Partial<TState> | ((set: SetState<TState>, get: GetState<TState>) => Partial<TState>), storeOptions?: {
1
+ import { GetState, GetterTuple, GetValueFn, GetValueFromBaseFn, MultiPathReturn, PathOf, PathOrFn, PathOrFnSetters, PathOrFnValues, PathSetters, PathSetter, PathValue, PathValues, SetFromBaseFn, SetState, SetStateFn, StoreApi, StoreMiddleware, UseStoreGetterOptions, UseStoreMultiOptions, UseStoreOptions, UseStoreSetterOptions, UseStoreSyncMultiOptions, UseStoreSyncOptions } from '../types';
2
+ export type CreateStoreOptions<TState extends object> = {
3
3
  id?: string;
4
4
  parent?: StoreApi<TState>;
5
5
  middlewares?: StoreMiddleware<TState>[];
6
- }): StoreApi<TState>;
6
+ /** When true, hydrate handlers are collected but NOT run during creation.
7
+ * Call `store.hydrate()` manually (StoreProvider does this in a useEffect).
8
+ * Defaults to false (backward-compatible: standalone usage hydrates synchronously). */
9
+ deferHydrate?: boolean;
10
+ };
11
+ declare function createStore<TState extends object>(initializer: Partial<TState> | ((set: SetState<TState>, get: GetState<TState>) => Partial<TState>), storeOptions?: CreateStoreOptions<TState>): StoreApi<TState>;
7
12
  export declare const createStoreHook: <TState extends object>() => {
8
13
  useStore: {
9
14
  (options?: UseStoreOptions<TState, TState>): [TState, StoreApi<TState>["setState"]];
10
- <P extends PathOf<TState>>(path: P, options: Omit<UseStoreOptions<PathValue<TState, P>, TState>, "defaultValue"> & {
11
- defaultValue: undefined;
12
- transformer?: never;
13
- }): [PathValue<TState, P> | undefined, (value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)) => void];
14
15
  <P extends PathOf<TState>>(path: P, options?: UseStoreOptions<PathValue<TState, P>, TState> & {
15
- defaultValue?: never;
16
16
  transformer?: never;
17
17
  }): [PathValue<TState, P>, (value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)) => void];
18
- <P extends PathOf<TState>, D>(path: P, options: UseStoreOptions<PathValue<TState, P>, TState> & {
19
- defaultValue: D;
20
- transformer?: never;
21
- }): [NonNullable<PathValue<TState, P>> | D, (value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)) => void];
22
18
  <P extends PathOf<TState>, TResult>(path: P, options: UseStoreOptions<PathValue<TState, P>, TState> & {
23
19
  transformer: (value: PathValue<TState, P>) => TResult;
24
20
  }): [TResult, (value: PathValue<TState, P> | ((prev: PathValue<TState, P>) => PathValue<TState, P>)) => void];
25
- <P extends PathOf<TState>>(pathFn: (state: TState) => P, options: Omit<UseStoreOptions<PathValue<TState, P>, TState>, "defaultValue"> & {
26
- defaultValue: undefined;
27
- transformer?: never;
28
- }): [PathValue<TState, P> | undefined, PathSetter<TState, P>];
29
21
  <P extends PathOf<TState>>(pathFn: (state: TState) => P, options?: UseStoreOptions<PathValue<TState, P>, TState> & {
30
- defaultValue?: never;
31
22
  transformer?: never;
32
23
  }): [PathValue<TState, P>, PathSetter<TState, P>];
33
- <P extends PathOf<TState>, D_1>(pathFn: (state: TState) => P, options: UseStoreOptions<PathValue<TState, P>, TState> & {
34
- defaultValue: D_1;
35
- transformer?: never;
36
- }): [NonNullable<PathValue<TState, P>> | D_1, PathSetter<TState, P>];
37
24
  <P extends PathOf<TState>, TResult_1>(pathFn: (state: TState) => P, options: UseStoreOptions<PathValue<TState, P>, TState> & {
38
25
  transformer: (value: PathValue<TState, P>) => TResult_1;
39
26
  }): [TResult_1, PathSetter<TState, P>];
40
- <const Paths extends ReadonlyArray<PathOf<TState>>>(paths: Paths, options?: Omit<UseStoreMultiOptions<TState, Paths>, "defaultValue" | "transformer">): MultiPathReturn<TState, Paths>;
41
- <const Paths extends ReadonlyArray<PathOf<TState>>>(paths: Paths, options: UseStoreMultiOptions<TState, Paths> & {
42
- defaultValue: undefined;
43
- transformer?: never;
44
- }): MultiPathReturn<TState, Paths, undefined>;
45
- <const Paths extends ReadonlyArray<PathOf<TState>>, const TDefaultValue extends readonly (PathValue<TState, Paths[number]> | undefined)[]>(paths: Paths, options: UseStoreMultiOptions<TState, Paths, TDefaultValue> & {
46
- defaultValue: TDefaultValue;
47
- transformer?: never;
48
- }): MultiPathReturn<TState, Paths, TDefaultValue>;
49
- <const Paths extends ReadonlyArray<PathOf<TState>>, TDefaultValue_1 extends PathValue<TState, Paths[number]>>(paths: Paths, options: UseStoreMultiOptions<TState, Paths, TDefaultValue_1> & {
50
- defaultValue: TDefaultValue_1;
51
- transformer?: never;
52
- }): MultiPathReturn<TState, Paths, TDefaultValue_1>;
27
+ <const Paths extends ReadonlyArray<PathOf<TState>>>(paths: Paths, options?: Omit<UseStoreMultiOptions<TState, Paths>, "transformer">): MultiPathReturn<TState, Paths>;
53
28
  <const Paths extends ReadonlyArray<PathOf<TState>>, TResult_2>(paths: Paths, options: UseStoreMultiOptions<TState, Paths> & {
54
29
  transformer: (values: PathValues<TState, Paths>) => TResult_2;
55
30
  }): [TResult_2, ...PathSetters<TState, Paths>];
56
- <const Entries extends ReadonlyArray<PathOrFn<TState>>>(paths: Entries, options?: Omit<UseStoreMultiOptions<TState, any>, "defaultValue" | "transformer"> & {
31
+ <const Entries extends ReadonlyArray<PathOrFn<TState>>>(paths: Entries, options?: Omit<UseStoreMultiOptions<TState, any>, "transformer"> & {
57
32
  transformer?: never;
58
33
  }): [PathOrFnValues<TState, Entries>, ...PathOrFnSetters<TState, Entries>];
59
- <const Entries extends ReadonlyArray<PathOrFn<TState>>>(paths: Entries, options: Omit<UseStoreMultiOptions<TState, any>, "defaultValue" | "transformer"> & {
60
- defaultValue: undefined;
61
- transformer?: never;
62
- }): [{ [I in keyof Entries]: PathOrFnValue<TState, Entries[I]> | undefined; }, ...PathOrFnSetters<TState, Entries>];
63
- <const Entries extends ReadonlyArray<PathOrFn<TState>>, const TDefaultValue_2 extends readonly unknown[]>(paths: Entries, options: Omit<UseStoreMultiOptions<TState, any>, "defaultValue" | "transformer"> & {
64
- defaultValue: TDefaultValue_2;
65
- transformer?: never;
66
- }): [{ [I in keyof Entries]: I extends keyof TDefaultValue_2 ? TDefaultValue_2[I] extends undefined ? PathOrFnValue<TState, Entries[I]> | undefined : NonNullable<PathOrFnValue<TState, Entries[I]>> | TDefaultValue_2[I] : PathOrFnValue<TState, Entries[I]>; }, ...PathOrFnSetters<TState, Entries>];
67
- <const Entries extends ReadonlyArray<PathOrFn<TState>>, TResult_3>(paths: Entries, options: Omit<UseStoreMultiOptions<TState, any>, "defaultValue" | "transformer"> & {
34
+ <const Entries extends ReadonlyArray<PathOrFn<TState>>, TResult_3>(paths: Entries, options: Omit<UseStoreMultiOptions<TState, any>, "transformer"> & {
68
35
  transformer: (values: PathOrFnValues<TState, Entries>) => TResult_3;
69
36
  }): [TResult_3, ...PathOrFnSetters<TState, Entries>];
70
37
  };
@@ -77,9 +44,6 @@ export declare const createStoreHook: <TState extends object>() => {
77
44
  useStoreGetter: {
78
45
  (options?: UseStoreGetterOptions<TState>): GetValueFn<TState>;
79
46
  <P extends PathOf<TState>>(basePath: P, options?: UseStoreGetterOptions<TState>): GetValueFromBaseFn<PathValue<TState, P>>;
80
- <P extends PathOf<TState>, D_2>(basePath: P, options: UseStoreGetterOptions<TState, D_2> & {
81
- defaultValue: D_2;
82
- }): GetValueFromBaseWithDefaultFn<PathValue<TState, P>, D_2>;
83
47
  <const Entries extends ReadonlyArray<PathOf<TState> | ((state: TState) => unknown)>>(entries: Entries, options?: UseStoreGetterOptions<TState>): GetterTuple<TState, Entries>;
84
48
  };
85
49
  useStoreSetter: {
@@ -12,10 +12,10 @@ import c from "./hooks/useStoreSync.mjs";
12
12
  var l = 0;
13
13
  function u(a, o) {
14
14
  let s = {}, c, u = new r(), d = new r(), f = new i(), p = new r(), m = () => {
15
- p.forEach((e) => e());
16
- }, h = [], g = [], _ = o?.parent;
15
+ p.length !== 0 && p.forEach((e) => e());
16
+ }, h = [], g = [], _ = [], v = o?.parent;
17
17
  ++l;
18
- let v = (e, t, n) => {
18
+ let y = (e, t, n) => {
19
19
  if (g.length === 0) throw e;
20
20
  let r = {
21
21
  error: e,
@@ -23,62 +23,80 @@ function u(a, o) {
23
23
  path: n
24
24
  };
25
25
  for (let e = 0, t = g.length; e < t; e++) g[e](r);
26
- }, y = () => s, b = () => c ??= { ...s }, { getState: x, getPath: S, invalidate: C, setActive: w, getMergeCount: T } = e(y, b, _);
27
- _ && w(!1);
28
- let { setState: E, batch: D } = t({
29
- getOwnState: y,
30
- getOwnSnapshot: b,
26
+ }, b = () => s, x = () => c ??= { ...s }, { getState: S, getPath: C, invalidate: w, resetCache: T, getMergeCount: E } = e(b, x, v), D = () => {
27
+ w(), m();
28
+ }, O, k, A = !1;
29
+ v && (T(), k = v.subscribeInvalidate?.(D));
30
+ let { setState: j, batch: M } = t({
31
+ getOwnState: b,
32
+ getOwnSnapshot: x,
31
33
  setOwnState: (e) => {
32
- s = e, c = void 0, C();
34
+ s = e, c = void 0, w();
33
35
  },
34
36
  mutateOwnKey: (e, t) => {
35
- s[e] = t, C(), c = void 0;
37
+ s[e] = t, w(), c = void 0;
36
38
  },
37
- parent: _,
39
+ parent: v,
38
40
  listeners: u,
39
41
  pathListeners: f,
40
42
  changeListeners: d,
41
43
  interceptors: h,
42
- reportError: v,
44
+ reportError: y,
43
45
  invalidateDescendants: m,
44
46
  onDelegateToParent: void 0
45
- }), O = () => {
46
- C(), m();
47
- }, k, A, j = !1, M = () => u.length > 0 || f.size > 0 || d.length > 0, N = () => {
48
- k || !_ || (C(), w(!0), k = n(_, u, f, d, x, v, C), A = _.subscribeInvalidate?.(O), d.length > 0 && k.seedBaseline());
49
- }, P = () => {
50
- k && (k.unsubscribe(), k = void 0, A?.(), A = void 0, w(!1));
47
+ }), N = () => u.length > 0 || f.size > 0 || d.length > 0, P = () => {
48
+ O || !v || (w(), T(), O = n(v, u, f, d, S, y, w), d.length > 0 && O.seedBaseline());
51
49
  }, F = () => {
52
- _ && (!j && M() ? N() : P());
53
- }, I = (e) => (F(), () => {
54
- e(), F();
55
- }), L = (e) => I(u.add(e)), R = (e, t) => I(f.add(e, t)), z = (e) => {
56
- let t = I(d.add(e));
57
- return k?.seedBaseline(), t;
50
+ O && (O.unsubscribe(), O = void 0, T());
51
+ }, I = () => {
52
+ v && (!A && N() ? P() : F());
53
+ }, L = (e) => (I(), () => {
54
+ e(), I();
55
+ }), R = (e) => L(u.add(e)), z = (e, t) => L(f.add(e, t)), B = (e) => {
56
+ let t = L(d.add(e));
57
+ return O?.seedBaseline(), t;
58
58
  };
59
- s = typeof a == "function" ? a(E, x) : a;
60
- let B = {
59
+ s = typeof a == "function" ? a(j, S) : a;
60
+ let V = {
61
61
  id: o?.id,
62
- getState: x,
63
- getPath: S,
64
- setState: E,
65
- batch: D,
66
- subscribe: L,
67
- subscribePath: R,
68
- subscribeChange: z,
62
+ getState: S,
63
+ getPath: C,
64
+ setState: j,
65
+ withBase: (e) => ({
66
+ getState: (t) => {
67
+ let n = C(e);
68
+ return n === void 0 && t !== void 0 ? t : n;
69
+ },
70
+ getPath: (t, n) => {
71
+ let r = C(`${e}.${t}`);
72
+ return r === void 0 && n !== void 0 ? n : r;
73
+ },
74
+ setState: (t, n) => j(t === void 0 ? e : `${e}.${t}`, n),
75
+ subscribe: (t) => z(e, t),
76
+ subscribePath: (t, n) => z(`${e}.${t}`, n)
77
+ }),
78
+ batch: M,
79
+ subscribe: R,
80
+ subscribePath: z,
81
+ subscribeChange: B,
69
82
  destroy: () => {
70
- j = !0, P(), u.clear(), f.clear(), d.clear(), p.clear();
83
+ A = !0, F(), u.clear(), f.clear(), d.clear(), p.clear(), k?.();
71
84
  },
72
85
  reconnect: () => {
73
- j = !1, F();
86
+ A = !1, v && (k?.(), k = v.subscribeInvalidate?.(D)), I();
74
87
  },
75
- subscribeInvalidate: (e) => p.add(e)
88
+ subscribeInvalidate: (e) => p.add(e),
89
+ hydrate: () => {
90
+ for (let e of _) e();
91
+ }
76
92
  };
77
93
  if (o?.middlewares) for (let e of o.middlewares) {
78
- let t = e(B);
79
- t?.beforeChange && h.push(t.beforeChange), t?.onChange && z(t.onChange), t?.onError && g.push(t.onError);
94
+ let t = e(V);
95
+ t?.beforeChange && h.push(t.beforeChange), t?.onChange && B(t.onChange), t?.onError && g.push(t.onError);
96
+ let n = t?.hydrate;
97
+ n && (o.deferHydrate ? _.push(() => n(V)) : n(V));
80
98
  }
81
- return B;
99
+ return V;
82
100
  }
83
101
  var d = () => {
84
102
  function e(e, t) {
@@ -3,9 +3,11 @@ import { Listener, Path } from '../../types';
3
3
  declare class PathTrie {
4
4
  readonly direct: Map<string, Subscribers<Listener>>;
5
5
  private readonly descendants;
6
+ private readonly root;
6
7
  size: number;
7
8
  add(path: string, listener: Listener): () => void;
8
9
  private remove;
10
+ walkAncestors(segments: readonly string[], cb: (subs: Subscribers<Listener>) => void): void;
9
11
  getDescendants(path: string): Set<string> | undefined;
10
12
  forEachAffected(changedPath: Path | undefined, cb: (listener: Listener) => void, onError?: (error: unknown) => void): void;
11
13
  clear(): void;