@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.
- package/CHANGELOG.md +12 -0
- package/README.md +197 -1
- package/dist/StoreProvider.mjs +44 -38
- package/dist/async/createAsync.mjs +8 -1
- package/dist/createStore/createStore.d.ts +11 -47
- package/dist/createStore/createStore.mjs +57 -39
- package/dist/createStore/helpers/PathTrie.d.ts +2 -0
- package/dist/createStore/helpers/PathTrie.mjs +55 -20
- package/dist/createStore/helpers/createChainReads.d.ts +1 -1
- package/dist/createStore/helpers/createChainReads.mjs +12 -13
- package/dist/createStore/helpers/createSetState.mjs +24 -33
- package/dist/createStore/helpers/writeByPath.mjs +1 -0
- package/dist/createStore/hooks/shared.d.ts +1 -2
- package/dist/createStore/hooks/shared.mjs +7 -18
- package/dist/createStore/hooks/useStore.d.ts +4 -49
- package/dist/createStore/hooks/useStore.mjs +19 -27
- package/dist/createStore/hooks/useStoreGetter.d.ts +2 -5
- package/dist/createStore/hooks/useStoreGetter.mjs +19 -22
- package/dist/createStore/hooks/useStoreSetter.mjs +2 -4
- package/dist/derived/createDerived.d.ts +1 -1
- package/dist/derived/createDerived.mjs +12 -9
- package/dist/entities/createEntityStore.d.ts +38 -0
- package/dist/entities/createEntityStore.mjs +102 -0
- package/dist/entities/index.d.ts +2 -0
- package/dist/entities/index.mjs +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +11 -9
- package/dist/middleware/historyMiddleware.d.ts +3 -3
- package/dist/middleware/historyMiddleware.mjs +22 -17
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/isDisabled.d.ts +2 -0
- package/dist/middleware/isDisabled.mjs +4 -0
- package/dist/middleware/loggerMiddleware.d.ts +2 -2
- package/dist/middleware/loggerMiddleware.mjs +14 -15
- package/dist/middleware/persistMiddleware.d.ts +7 -5
- package/dist/middleware/persistMiddleware.mjs +58 -26
- package/dist/middleware/reduxDevToolsMiddleware.d.ts +2 -2
- package/dist/middleware/reduxDevToolsMiddleware.mjs +26 -21
- package/dist/next/index.d.ts +26 -0
- package/dist/next/index.mjs +18 -0
- package/dist/rsc/index.d.ts +29 -0
- package/dist/rsc/index.mjs +18 -0
- package/dist/types/StoreTypes.d.ts +33 -21
- package/logo.svg +57 -0
- package/package.json +22 -10
package/CHANGELOG.md
CHANGED
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.
|
package/dist/StoreProvider.mjs
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
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
|
|
8
|
-
let
|
|
9
|
-
let e =
|
|
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
|
-
...
|
|
12
|
+
...g
|
|
13
13
|
};
|
|
14
|
+
return i(t) ? a(t) : t;
|
|
14
15
|
}, [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
]),
|
|
19
|
-
|
|
20
|
-
id:
|
|
21
|
-
parent:
|
|
22
|
-
middlewares:
|
|
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
|
|
25
|
-
id:
|
|
26
|
-
store:
|
|
27
|
-
parent:
|
|
28
|
-
} :
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}), [
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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 {
|
|
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) =>
|
|
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,
|
|
2
|
-
|
|
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
|
-
|
|
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>, "
|
|
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>, "
|
|
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
|
|
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
|
|
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
|
-
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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,
|
|
34
|
+
s = e, c = void 0, w();
|
|
33
35
|
},
|
|
34
36
|
mutateOwnKey: (e, t) => {
|
|
35
|
-
s[e] = t,
|
|
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:
|
|
44
|
+
reportError: y,
|
|
43
45
|
invalidateDescendants: m,
|
|
44
46
|
onDelegateToParent: void 0
|
|
45
|
-
}),
|
|
46
|
-
|
|
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
|
-
|
|
53
|
-
}, I = (
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
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(
|
|
60
|
-
let
|
|
59
|
+
s = typeof a == "function" ? a(j, S) : a;
|
|
60
|
+
let V = {
|
|
61
61
|
id: o?.id,
|
|
62
|
-
getState:
|
|
63
|
-
getPath:
|
|
64
|
-
setState:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
83
|
+
A = !0, F(), u.clear(), f.clear(), d.clear(), p.clear(), k?.();
|
|
71
84
|
},
|
|
72
85
|
reconnect: () => {
|
|
73
|
-
|
|
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(
|
|
79
|
-
t?.beforeChange && h.push(t.beforeChange), t?.onChange &&
|
|
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
|
|
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;
|