@nice-code/state 0.10.0 → 0.11.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/build/{Store-B65MojT2.d.ts → Store-B65MojT2.d.cts} +1 -1
- package/build/Store-B65MojT2.d.mts +201 -0
- package/build/{Store-CI9N0P6I.js → Store-CI9N0P6I.cjs} +1 -1
- package/build/Store-CI9N0P6I.cjs.map +1 -0
- package/build/{Store-PjfFkZ2I.js → Store-PjfFkZ2I.mjs} +1 -1
- package/build/Store-PjfFkZ2I.mjs.map +1 -0
- package/build/devtools/browser/index.cjs +2821 -0
- package/build/devtools/browser/index.cjs.map +1 -0
- package/build/devtools/browser/{index.d.ts → index.d.cts} +2 -2
- package/build/devtools/browser/index.d.mts +120 -0
- package/build/devtools/browser/{index.js → index.mjs} +1 -1
- package/build/devtools/browser/index.mjs.map +1 -0
- package/build/index.cjs +5 -0
- package/build/{index.d.ts → index.d.cts} +1 -1
- package/build/index.d.mts +2 -0
- package/build/{index.js → index.mjs} +1 -1
- package/build/react/index.cjs +72 -0
- package/build/react/index.cjs.map +1 -0
- package/build/react/{index.d.ts → index.d.cts} +2 -2
- package/build/react/index.d.mts +58 -0
- package/build/react/{index.js → index.mjs} +2 -2
- package/build/react/index.mjs.map +1 -0
- package/package.json +28 -9
- package/build/Store-CI9N0P6I.js.map +0 -1
- package/build/Store-PjfFkZ2I.js.map +0 -1
- package/build/devtools/browser/index.js.map +0 -1
- package/build/react/index.js.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { r as Store } from "../Store-B65MojT2.mjs";
|
|
2
|
+
import { ReactElement } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/react/useStoreState.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Compares the previously selected value against the next one. Returning `true`
|
|
7
|
+
* tells the hook the value is unchanged, so React is handed the *same*
|
|
8
|
+
* reference and no re-render is scheduled.
|
|
9
|
+
*/
|
|
10
|
+
type TEqualityFn<SS> = (a: SS, b: SS) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Subscribe a React component to a store, optionally narrowing to a derived
|
|
13
|
+
* slice.
|
|
14
|
+
*
|
|
15
|
+
* Built on `useSyncExternalStore`, so it is tear-free under React 18+
|
|
16
|
+
* concurrent rendering with no manual `useState`/`useEffect` subscription loop.
|
|
17
|
+
*
|
|
18
|
+
* A `useRef` cache holds the last selected value. On every store emission the
|
|
19
|
+
* selector is re-evaluated and the result is run through a strict-reference
|
|
20
|
+
* fast-path first; only if the reference differs is `equalityFn` consulted. A
|
|
21
|
+
* new reference is handed back to React exclusively when a genuine change is
|
|
22
|
+
* detected, so equal-but-new selector results never trigger a render.
|
|
23
|
+
*/
|
|
24
|
+
declare function useStoreState<S extends object>(store: Store<S>): S;
|
|
25
|
+
declare function useStoreState<S extends object, SS>(store: Store<S>, getSubState: (state: S) => SS, equalityFn?: TEqualityFn<SS>): SS;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/react/InjectStoreState.d.ts
|
|
28
|
+
interface IPropsInjectStoreState<S extends object, SS> {
|
|
29
|
+
store: Store<S>;
|
|
30
|
+
on?: (state: S) => SS;
|
|
31
|
+
/**
|
|
32
|
+
* Optional equality function for the selected slice. Defaults to a strict
|
|
33
|
+
* reference check; pass `deepEqual` from `fast-equals` for inline objects.
|
|
34
|
+
*/
|
|
35
|
+
equalityFn?: TEqualityFn<SS>;
|
|
36
|
+
children: (output: SS) => ReactElement;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Render-prop binding: subscribes to `store` (optionally narrowed by `on`) and
|
|
40
|
+
* renders `children` with the selected slice.
|
|
41
|
+
*/
|
|
42
|
+
declare function InjectStoreState<S extends object, SS = S>({
|
|
43
|
+
store,
|
|
44
|
+
on,
|
|
45
|
+
equalityFn,
|
|
46
|
+
children
|
|
47
|
+
}: IPropsInjectStoreState<S, SS>): ReactElement;
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/react/useLocalStore.d.ts
|
|
50
|
+
/**
|
|
51
|
+
* Create a component-local {@link Store} that persists across renders. Passing a
|
|
52
|
+
* `deps` array re-creates the store (with a fresh initial state) whenever the
|
|
53
|
+
* dependencies change by shallow comparison.
|
|
54
|
+
*/
|
|
55
|
+
declare function useLocalStore<S extends object>(initialState: (() => S) | S, deps?: ReadonlyArray<unknown>): Store<S>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { type IPropsInjectStoreState, InjectStoreState, type TEqualityFn, useLocalStore, useStoreState };
|
|
58
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Store } from "../Store-PjfFkZ2I.
|
|
1
|
+
import { t as Store } from "../Store-PjfFkZ2I.mjs";
|
|
2
2
|
import { useCallback, useRef, useSyncExternalStore } from "react";
|
|
3
3
|
//#region src/react/useStoreState.ts
|
|
4
4
|
function strictEqual(a, b) {
|
|
@@ -66,4 +66,4 @@ function useLocalStore(initialState, deps) {
|
|
|
66
66
|
//#endregion
|
|
67
67
|
export { InjectStoreState, useLocalStore, useStoreState };
|
|
68
68
|
|
|
69
|
-
//# sourceMappingURL=index.
|
|
69
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/react/useStoreState.ts","../../src/react/InjectStoreState.ts","../../src/react/useLocalStore.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\r\nimport type { Store } from \"../core/Store\";\r\n\r\n/**\r\n * Compares the previously selected value against the next one. Returning `true`\r\n * tells the hook the value is unchanged, so React is handed the *same*\r\n * reference and no re-render is scheduled.\r\n */\r\nexport type TEqualityFn<SS> = (a: SS, b: SS) => boolean;\r\n\r\n// Default equality is a strict reference check — the fastest possible path, and\r\n// exactly right when selectors return state branches (Immer's structural\r\n// sharing keeps unchanged branches referentially stable). Pass `deepEqual` from\r\n// `fast-equals` when a selector builds a fresh object/array each call.\r\nfunction strictEqual(a: unknown, b: unknown): boolean {\r\n return a === b;\r\n}\r\n\r\ninterface ISelectionCache<R> {\r\n value: R;\r\n}\r\n\r\n/**\r\n * Subscribe a React component to a store, optionally narrowing to a derived\r\n * slice.\r\n *\r\n * Built on `useSyncExternalStore`, so it is tear-free under React 18+\r\n * concurrent rendering with no manual `useState`/`useEffect` subscription loop.\r\n *\r\n * A `useRef` cache holds the last selected value. On every store emission the\r\n * selector is re-evaluated and the result is run through a strict-reference\r\n * fast-path first; only if the reference differs is `equalityFn` consulted. A\r\n * new reference is handed back to React exclusively when a genuine change is\r\n * detected, so equal-but-new selector results never trigger a render.\r\n */\r\nfunction useStoreState<S extends object>(store: Store<S>): S;\r\nfunction useStoreState<S extends object, SS>(\r\n store: Store<S>,\r\n getSubState: (state: S) => SS,\r\n equalityFn?: TEqualityFn<SS>,\r\n): SS;\r\nfunction useStoreState<S extends object, SS>(\r\n store: Store<S>,\r\n getSubState?: (state: S) => SS,\r\n equalityFn: (a: S | SS, b: S | SS) => boolean = strictEqual,\r\n): S | SS {\r\n // Keep the latest selector/equality without forcing a resubscribe when a\r\n // caller passes inline functions. The store-emission cache below guarantees\r\n // referential stability regardless of identity churn here.\r\n const selectorRef = useRef(getSubState);\r\n const equalityRef = useRef(equalityFn);\r\n selectorRef.current = getSubState;\r\n equalityRef.current = equalityFn;\r\n\r\n const cacheRef = useRef<ISelectionCache<S | SS> | null>(null);\r\n\r\n const getSnapshot = useCallback((): S | SS => {\r\n const rawState = store.getRawState();\r\n const selector = selectorRef.current;\r\n const nextValue: S | SS = selector ? selector(rawState) : rawState;\r\n\r\n const cache = cacheRef.current;\r\n\r\n if (cache === null) {\r\n cacheRef.current = { value: nextValue };\r\n return nextValue;\r\n }\r\n\r\n const lastValue = cache.value;\r\n\r\n // Fast-path: reference is identical → return the cached value untouched.\r\n if (nextValue === lastValue) {\r\n return lastValue;\r\n }\r\n\r\n // Reference changed → consult the configurable equality function. When it\r\n // reports equality, keep the old reference so React skips the render.\r\n if (equalityRef.current(lastValue, nextValue)) {\r\n return lastValue;\r\n }\r\n\r\n cache.value = nextValue;\r\n return nextValue;\r\n }, [store]);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void): (() => void) => store.subscribe(onStoreChange),\r\n [store],\r\n );\r\n\r\n // Same snapshot getter serves the server: it reads the store's current value,\r\n // which on the server is the SSR-seeded state.\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n\r\nexport { useStoreState };\r\n","import type { ReactElement } from \"react\";\r\nimport type { Store } from \"../core/Store\";\r\nimport { type TEqualityFn, useStoreState } from \"./useStoreState\";\r\n\r\nexport interface IPropsInjectStoreState<S extends object, SS> {\r\n store: Store<S>;\r\n on?: (state: S) => SS;\r\n /**\r\n * Optional equality function for the selected slice. Defaults to a strict\r\n * reference check; pass `deepEqual` from `fast-equals` for inline objects.\r\n */\r\n equalityFn?: TEqualityFn<SS>;\r\n children: (output: SS) => ReactElement;\r\n}\r\n\r\n/**\r\n * Render-prop binding: subscribes to `store` (optionally narrowed by `on`) and\r\n * renders `children` with the selected slice.\r\n */\r\nexport function InjectStoreState<S extends object, SS = S>({\r\n store,\r\n on,\r\n equalityFn,\r\n children,\r\n}: IPropsInjectStoreState<S, SS>): ReactElement {\r\n const state = useStoreState(store, on ?? ((s: S) => s as unknown as SS), equalityFn);\r\n return children(state);\r\n}\r\n","import { useRef } from \"react\";\r\nimport { Store } from \"../core/Store\";\r\n\r\n/**\r\n * Standard shallow comparison of dependency arrays — the same semantics React\r\n * uses for its own hook dependency lists. No deep traversal.\r\n */\r\nfunction shallowEqualDeps(\r\n a: ReadonlyArray<unknown> | undefined,\r\n b: ReadonlyArray<unknown> | undefined,\r\n): boolean {\r\n if (a === b) {\r\n return true;\r\n }\r\n if (a == null || b == null || a.length !== b.length) {\r\n return false;\r\n }\r\n for (let i = 0; i < a.length; i++) {\r\n if (a[i] !== b[i]) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Create a component-local {@link Store} that persists across renders. Passing a\r\n * `deps` array re-creates the store (with a fresh initial state) whenever the\r\n * dependencies change by shallow comparison.\r\n */\r\nfunction useLocalStore<S extends object>(\r\n initialState: (() => S) | S,\r\n deps?: ReadonlyArray<unknown>,\r\n): Store<S> {\r\n const storeRef = useRef<Store<S> | null>(null);\r\n const depsRef = useRef<ReadonlyArray<unknown> | undefined>(deps);\r\n\r\n if (storeRef.current === null) {\r\n storeRef.current = new Store(initialState);\r\n } else if (deps !== undefined && !shallowEqualDeps(depsRef.current, deps)) {\r\n storeRef.current = new Store(initialState);\r\n depsRef.current = deps;\r\n }\r\n\r\n return storeRef.current;\r\n}\r\n\r\nexport { useLocalStore };\r\n"],"mappings":";;;AAcA,SAAS,YAAY,GAAY,GAAqB;CACpD,OAAO,MAAM;AACf;AAyBA,SAAS,cACP,OACA,aACA,aAAgD,aACxC;CAIR,MAAM,cAAc,OAAO,WAAW;CACtC,MAAM,cAAc,OAAO,UAAU;CACrC,YAAY,UAAU;CACtB,YAAY,UAAU;CAEtB,MAAM,WAAW,OAAuC,IAAI;CAE5D,MAAM,cAAc,kBAA0B;EAC5C,MAAM,WAAW,MAAM,YAAY;EACnC,MAAM,WAAW,YAAY;EAC7B,MAAM,YAAoB,WAAW,SAAS,QAAQ,IAAI;EAE1D,MAAM,QAAQ,SAAS;EAEvB,IAAI,UAAU,MAAM;GAClB,SAAS,UAAU,EAAE,OAAO,UAAU;GACtC,OAAO;EACT;EAEA,MAAM,YAAY,MAAM;EAGxB,IAAI,cAAc,WAChB,OAAO;EAKT,IAAI,YAAY,QAAQ,WAAW,SAAS,GAC1C,OAAO;EAGT,MAAM,QAAQ;EACd,OAAO;CACT,GAAG,CAAC,KAAK,CAAC;CASV,OAAO,qBAPW,aACf,kBAA4C,MAAM,UAAU,aAAa,GAC1E,CAAC,KAAK,CAK4B,GAAG,aAAa,WAAW;AACjE;;;;;;;AC1EA,SAAgB,iBAA2C,EACzD,OACA,IACA,YACA,YAC8C;CAE9C,OAAO,SADO,cAAc,OAAO,QAAQ,MAAS,IAAqB,UACrD,CAAC;AACvB;;;;;;;ACpBA,SAAS,iBACP,GACA,GACS;CACT,IAAI,MAAM,GACR,OAAO;CAET,IAAI,KAAK,QAAQ,KAAK,QAAQ,EAAE,WAAW,EAAE,QAC3C,OAAO;CAET,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAC5B,IAAI,EAAE,OAAO,EAAE,IACb,OAAO;CAGX,OAAO;AACT;;;;;;AAOA,SAAS,cACP,cACA,MACU;CACV,MAAM,WAAW,OAAwB,IAAI;CAC7C,MAAM,UAAU,OAA2C,IAAI;CAE/D,IAAI,SAAS,YAAY,MACvB,SAAS,UAAU,IAAI,MAAM,YAAY;MACpC,IAAI,SAAS,KAAA,KAAa,CAAC,iBAAiB,QAAQ,SAAS,IAAI,GAAG;EACzE,SAAS,UAAU,IAAI,MAAM,YAAY;EACzC,QAAQ,UAAU;CACpB;CAEA,OAAO,SAAS;AAClB"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nice-code/state",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"main": "./build/index.cjs",
|
|
5
|
+
"module": "./build/index.mjs",
|
|
6
|
+
"types": "./build/index.d.cts",
|
|
4
7
|
"exports": {
|
|
5
8
|
".": {
|
|
6
9
|
"source": "./src/index.ts",
|
|
7
|
-
"import":
|
|
8
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./build/index.d.mts",
|
|
12
|
+
"default": "./build/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./build/index.d.cts",
|
|
16
|
+
"default": "./build/index.cjs"
|
|
17
|
+
}
|
|
9
18
|
},
|
|
10
19
|
"./devtools/browser": {
|
|
11
20
|
"source": "./src/devtools/browser/index.ts",
|
|
12
|
-
"import":
|
|
13
|
-
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./build/devtools/browser/index.d.mts",
|
|
23
|
+
"default": "./build/devtools/browser/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./build/devtools/browser/index.d.cts",
|
|
27
|
+
"default": "./build/devtools/browser/index.cjs"
|
|
28
|
+
}
|
|
14
29
|
},
|
|
15
30
|
"./react": {
|
|
16
31
|
"source": "./src/react/index.ts",
|
|
17
|
-
"import":
|
|
18
|
-
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./build/react/index.d.mts",
|
|
34
|
+
"default": "./build/react/index.mjs"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./build/react/index.d.cts",
|
|
38
|
+
"default": "./build/react/index.cjs"
|
|
39
|
+
}
|
|
19
40
|
}
|
|
20
41
|
},
|
|
21
42
|
"files": [
|
|
@@ -36,9 +57,7 @@
|
|
|
36
57
|
"access": "public"
|
|
37
58
|
},
|
|
38
59
|
"scripts": {
|
|
39
|
-
"build-bun": "bun run clean-build && bun run build.ts && bun run build-types",
|
|
40
60
|
"build": "bun run clean-build && tsdown",
|
|
41
|
-
"build-types": "tsc --project tsconfig.build.json",
|
|
42
61
|
"build-watch": "bun run clean-build && bun run build.ts --watch && bun run build-types --watch",
|
|
43
62
|
"clean-build": "bunx rimraf build",
|
|
44
63
|
"type-check": "bunx tsc --noEmit",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Store-CI9N0P6I.js","names":[],"sources":["../src/core/Store.ts"],"sourcesContent":["import { deepEqual } from \"fast-equals\";\r\nimport {\r\n applyPatches,\r\n type Draft,\r\n enablePatches,\r\n type Patch,\r\n type PatchListener,\r\n produce,\r\n produceWithPatches,\r\n} from \"immer\";\r\n\r\n// Immer emits JSON patches for `produceWithPatches`, which the store exposes via\r\n// `listenToPatches`. This must run once, before any patch-producing update.\r\nenablePatches();\r\n\r\n/**\r\n * A plain pub/sub listener. Fired (in the order added) every time the store's\r\n * root state reference changes. This is the vanilla integration point that any\r\n * ecosystem — including the React adapter's `useSyncExternalStore` — builds on.\r\n */\r\nexport type TUpdateListener = () => void;\r\n\r\n/**\r\n * @typeParam S The store's state\r\n * @param draft The mutable draft to change during this update (Immer proxy).\r\n * @param original A readonly snapshot of the state as it was before this update.\r\n */\r\nexport type TUpdateFunction<S> = (draft: Draft<S>, original: S) => void;\r\n\r\n/**\r\n * A selector that derives a watched slice `T` from the full store state `S`.\r\n */\r\nexport type TStoreWatch<S extends object, T> = (state: S) => T;\r\n\r\n/**\r\n * Fired by {@link Store.watch} whenever the watched slice changes structurally.\r\n */\r\nexport type TStoreSubscriptionListener<S extends object, T> = (\r\n watched: T,\r\n allState: S,\r\n previousWatched: T,\r\n) => void;\r\n\r\n/**\r\n * Runs inside an Immer `produce` whenever a watched slice changes, letting the\r\n * store derive further state from its own mutations.\r\n */\r\nexport type TReactionFunction<S extends object, T> = (\r\n watched: T,\r\n draft: Draft<S>,\r\n original: S,\r\n previousWatched: T,\r\n) => void;\r\n\r\nexport type TStoreActionUpdate<S extends object> = (\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n patchesCallback?: TPatchesCallback,\r\n) => void;\r\n\r\nexport type TStoreAction<S extends object> = (update: TStoreActionUpdate<S>) => void;\r\n\r\nexport type TPatchesCallback = (patches: Patch[], inversePatches: Patch[]) => void;\r\n\r\n/**\r\n * @internal\r\n * Drives a registered reaction. `forceRun` bypasses the change-detection\r\n * fast-path (used when a reaction is created with `runNow`).\r\n */\r\ntype TRunReactionFunction = (forceRun?: boolean) => void;\r\n\r\n/**\r\n * @internal\r\n * Drives a registered selector subscription on every store emission.\r\n */\r\ntype TRunSubscriptionFunction = () => void;\r\n\r\n/**\r\n * @internal\r\n * Binds a reaction definition to a concrete store instance.\r\n */\r\ntype TReactionCreator<S extends object> = (store: Store<S>) => TRunReactionFunction;\r\n\r\nexport interface IStoreInternalOptions<S extends object> {\r\n ssr: boolean;\r\n reactionCreators?: TReactionCreator<S>[];\r\n}\r\n\r\nexport interface ICreateReactionOptions {\r\n runNow?: boolean;\r\n runNowWithSideEffects?: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Builds the per-emission runner for a selector subscription.\r\n *\r\n * Change detection follows the \"Fast-Path\" rule: Immer's structural sharing\r\n * means an untouched branch keeps its exact reference, so a strict `===` check\r\n * resolves the overwhelmingly common \"nothing changed\" case in 0ms. Only when\r\n * the reference actually changes do we pay for a `deepEqual` traversal to\r\n * confirm the change is structural and not just a new-but-equal reference.\r\n */\r\nfunction makeSubscriptionFunction<S extends object, T>(\r\n store: Store<S>,\r\n watch: TStoreWatch<S, T>,\r\n listener: TStoreSubscriptionListener<S, T>,\r\n): TRunSubscriptionFunction {\r\n let lastWatchState: T = watch(store.getRawState());\r\n\r\n return () => {\r\n const currentState = store.getRawState();\r\n const nextWatchState = watch(currentState);\r\n\r\n // Fast-path: reference is identical → the watched branch was never touched.\r\n if (nextWatchState === lastWatchState) {\r\n return;\r\n }\r\n\r\n // Reference changed — fall back to deep equality to confirm real change.\r\n if (deepEqual(nextWatchState, lastWatchState)) {\r\n // Structurally equal: adopt the new reference so the fast-path stays hot,\r\n // but do not notify — nothing the watcher cares about actually changed.\r\n lastWatchState = nextWatchState;\r\n return;\r\n }\r\n\r\n const previousWatched = lastWatchState;\r\n lastWatchState = nextWatchState;\r\n listener(nextWatchState, currentState, previousWatched);\r\n };\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Builds a reaction creator. Reactions follow the same Fast-Path rule as\r\n * subscriptions, then run their recipe inside Immer to derive further state.\r\n */\r\nfunction makeReactionFunctionCreator<S extends object, T>(\r\n watch: TStoreWatch<S, T>,\r\n reaction: TReactionFunction<S, T>,\r\n): TReactionCreator<S> {\r\n return (store) => {\r\n let lastWatchState: T = watch(store.getRawState());\r\n\r\n return (forceRun = false) => {\r\n const currentState = store.getRawState();\r\n const nextWatchState = watch(currentState);\r\n\r\n if (!forceRun) {\r\n // Fast-path: identical reference → skip entirely.\r\n if (nextWatchState === lastWatchState) {\r\n return;\r\n }\r\n\r\n // New reference but structurally equal → adopt and skip the recipe.\r\n if (deepEqual(nextWatchState, lastWatchState)) {\r\n lastWatchState = nextWatchState;\r\n return;\r\n }\r\n }\r\n\r\n const previousWatched = lastWatchState;\r\n lastWatchState = nextWatchState;\r\n\r\n // Reactions mutate via Immer but must not re-enter the reaction loop, so\r\n // they write back through the no-reaction update path.\r\n if (store._hasPatchListeners()) {\r\n const [nextState, patches, inversePatches] = produceWithPatches(\r\n currentState,\r\n (draft: Draft<S>) => {\r\n reaction(nextWatchState, draft, currentState, previousWatched);\r\n },\r\n );\r\n\r\n store._updateStateWithoutReaction(nextState);\r\n\r\n if (patches.length > 0) {\r\n store._emitPatches(patches, inversePatches);\r\n }\r\n } else {\r\n const nextState = produce(currentState, (draft: Draft<S>) => {\r\n reaction(nextWatchState, draft, currentState, previousWatched);\r\n });\r\n store._updateStateWithoutReaction(nextState);\r\n }\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * A framework-agnostic, Immer-backed state container.\r\n *\r\n * The store owns a single immutable state value and a `Set` of plain\r\n * listeners. Every mutation runs through Immer's `produce`, and listeners are\r\n * only notified when the resulting root reference actually changes — making\r\n * \"no-op\" updates genuinely free for subscribers.\r\n *\r\n * @typeParam S Your store's state interface.\r\n */\r\nexport class Store<S extends object = object> {\r\n private currentState: S;\r\n private readonly createInitialState: () => S;\r\n private ssr = false;\r\n\r\n /** Plain pub/sub listeners — a Set both dedupes and dispatches fast. */\r\n private readonly listeners = new Set<TUpdateListener>();\r\n\r\n private reactionCreators: TReactionCreator<S>[] = [];\r\n private reactions: TRunReactionFunction[] = [];\r\n private clientSubscriptions: TRunSubscriptionFunction[] = [];\r\n\r\n /**\r\n * @internal\r\n */\r\n public _patchListeners: PatchListener[] = [];\r\n\r\n constructor(initialState: S | (() => S)) {\r\n if (initialState instanceof Function) {\r\n this.createInitialState = initialState;\r\n this.currentState = initialState();\r\n } else {\r\n this.createInitialState = () => initialState;\r\n this.currentState = initialState;\r\n }\r\n }\r\n\r\n get state(): S {\r\n return Object.freeze(this.currentState);\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _setInternalOptions({ ssr, reactionCreators = [] }: IStoreInternalOptions<S>) {\r\n this.ssr = ssr;\r\n this.reactionCreators = reactionCreators;\r\n this.reactions = reactionCreators.map((rc) => rc(this));\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _getReactionCreators(): TReactionCreator<S>[] {\r\n return this.reactionCreators;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _instantiateReactions() {\r\n this.reactions = this.reactionCreators.map((rc) => rc(this));\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _getInitialState(): S {\r\n return this.createInitialState();\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _hasPatchListeners(): boolean {\r\n return this._patchListeners.length > 0;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _emitPatches(patches: Patch[], inversePatches: Patch[]) {\r\n for (const listener of this._patchListeners) {\r\n listener(patches, inversePatches);\r\n }\r\n }\r\n\r\n /**\r\n * @internal\r\n *\r\n * Writes a new state value without running reactions. Used by reactions\r\n * themselves to avoid re-entrancy.\r\n */\r\n _updateStateWithoutReaction(nextState: S) {\r\n this.currentState = nextState;\r\n }\r\n\r\n /**\r\n * @internal\r\n *\r\n * Commits a new root state, runs reactions, then dispatches to all\r\n * subscribers. Callers are responsible for the `nextState !== currentState`\r\n * reference guard before invoking this.\r\n */\r\n _updateState(nextState: S) {\r\n this.currentState = nextState;\r\n\r\n // Reactions run first and may derive further state (without re-triggering).\r\n for (const runReaction of this.reactions) {\r\n runReaction();\r\n }\r\n\r\n if (this.ssr) {\r\n return;\r\n }\r\n\r\n for (const runSubscription of this.clientSubscriptions) {\r\n runSubscription();\r\n }\r\n\r\n for (const listener of this.listeners) {\r\n listener();\r\n }\r\n }\r\n\r\n /**\r\n * Returns the raw state object contained within this store at this moment.\r\n *\r\n * ---\r\n * ** WARNING **\r\n *\r\n * Most of the time, if you're using this in your app, there's probably a\r\n * better way to do it (a selector subscription or the React adapter).\r\n * ---\r\n */\r\n getRawState(): S {\r\n return this.currentState;\r\n }\r\n\r\n /**\r\n * Subscribe a plain listener to store mutations. The listener fires once per\r\n * committed update (root reference change) and receives no arguments — read\r\n * the latest value with {@link getRawState}.\r\n *\r\n * This is the low-level primitive that vanilla code and framework adapters\r\n * (e.g. React's `useSyncExternalStore`) build upon.\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n subscribe(listener: TUpdateListener): () => void {\r\n this.listeners.add(listener);\r\n return () => {\r\n this.listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to a derived slice of state. The `listener` only fires when the\r\n * watched value changes structurally (per the Fast-Path rule).\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n watch<T>(watch: TStoreWatch<S, T>, listener: TStoreSubscriptionListener<S, T>): () => void {\r\n if (this.ssr) {\r\n return () => {\r\n console.warn(\r\n `@nice-code/state: Subscriptions made on the server side are not registered, so this unsubscribe call does nothing.`,\r\n );\r\n };\r\n }\r\n\r\n const run = makeSubscriptionFunction(this, watch, listener);\r\n this.clientSubscriptions.push(run);\r\n\r\n return () => {\r\n this.clientSubscriptions = this.clientSubscriptions.filter((f) => f !== run);\r\n };\r\n }\r\n\r\n /**\r\n * Register a reaction: when the watched slice changes, the `reaction` recipe\r\n * runs inside Immer to derive further state on the same store.\r\n *\r\n * @returns A function that removes the reaction.\r\n */\r\n createReaction<T>(\r\n watch: TStoreWatch<S, T>,\r\n reaction: TReactionFunction<S, T>,\r\n { runNow = false, runNowWithSideEffects = false }: ICreateReactionOptions = {},\r\n ): () => void {\r\n const creator = makeReactionFunctionCreator(watch, reaction);\r\n this.reactionCreators.push(creator);\r\n\r\n const run = creator(this);\r\n this.reactions.push(run);\r\n\r\n if (runNow || runNowWithSideEffects) {\r\n run(true);\r\n\r\n if (runNowWithSideEffects && !this.ssr) {\r\n this._updateState(this.currentState);\r\n }\r\n }\r\n\r\n return () => {\r\n this.reactions = this.reactions.filter((f) => f !== run);\r\n this.reactionCreators = this.reactionCreators.filter((f) => f !== creator);\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to the Immer patches produced by each update.\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n listenToPatches(patchListener: PatchListener): () => void {\r\n this._patchListeners.push(patchListener);\r\n return () => {\r\n this._patchListeners = this._patchListeners.filter((f) => f !== patchListener);\r\n };\r\n }\r\n\r\n /**\r\n * Mutate the store via one or more Immer update functions.\r\n *\r\n * @param updater A single update function, or an array applied in order.\r\n * @param patchesCallback Optional callback receiving the patches for this update.\r\n */\r\n update(updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback) {\r\n update(this, updater, patchesCallback);\r\n }\r\n\r\n /**\r\n * Replace the store's state entirely with a new state value.\r\n */\r\n replace(newState: S) {\r\n if (newState !== this.currentState) {\r\n this._updateState(newState);\r\n }\r\n }\r\n\r\n /**\r\n * Replace the store's state by mapping from the current state.\r\n */\r\n replaceFromCurrent(replacer: (state: S) => S) {\r\n const nextState = replacer(this.currentState);\r\n if (nextState !== this.currentState) {\r\n this._updateState(nextState);\r\n }\r\n }\r\n\r\n /**\r\n * Apply a set of Immer patches to the store.\r\n */\r\n applyPatches(patches: Patch[]) {\r\n applyPatchesToStore(this, patches);\r\n }\r\n}\r\n\r\n/**\r\n * Apply Immer patches to a store, committing only if the root reference changes.\r\n */\r\nexport function applyPatchesToStore<S extends object = object>(store: Store<S>, patches: Patch[]) {\r\n const currentState = store.getRawState();\r\n const nextState = applyPatches(currentState, patches);\r\n if (nextState !== currentState) {\r\n store._updateState(nextState);\r\n }\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Runs an updater (or array of updaters) through Immer, collecting patches.\r\n */\r\nfunction applyUpdaterWithPatches<S extends object>(\r\n currentState: S,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n): [S, Patch[], Patch[]] {\r\n if (typeof updater === \"function\") {\r\n const [next, patches, inversePatches] = produceWithPatches(currentState, (draft: Draft<S>) => {\r\n updater(draft, currentState);\r\n });\r\n return [next, patches, inversePatches];\r\n }\r\n\r\n let state = currentState;\r\n const patches: Patch[] = [];\r\n const inversePatches: Patch[] = [];\r\n\r\n for (const single of updater) {\r\n const [next, p, ip] = produceWithPatches(state, (draft: Draft<S>) => {\r\n single(draft, state);\r\n });\r\n state = next;\r\n patches.push(...p);\r\n inversePatches.push(...ip);\r\n }\r\n\r\n return [state, patches, inversePatches];\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Runs an updater (or array of updaters) through Immer without tracking patches.\r\n */\r\nfunction applyUpdater<S extends object>(\r\n currentState: S,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n): S {\r\n if (typeof updater === \"function\") {\r\n return produce(currentState, (draft: Draft<S>) => {\r\n updater(draft, currentState);\r\n });\r\n }\r\n\r\n return updater.reduce<S>(\r\n (previousState, single) =>\r\n produce(previousState, (draft: Draft<S>) => {\r\n single(draft, previousState);\r\n }),\r\n currentState,\r\n );\r\n}\r\n\r\n/**\r\n * Mutate a store via one or more Immer update functions.\r\n *\r\n * Patches are only computed when there's a consumer for them (a registered\r\n * patch listener or a `patchesCallback`), keeping the common path allocation-free.\r\n * Listeners are notified only when the root reference actually changes.\r\n *\r\n * @param store The store to update.\r\n * @param updater A single update function, or an array applied in order.\r\n * @param patchesCallback Optional callback receiving the patches for this update.\r\n */\r\nexport function update<S extends object = object>(\r\n store: Store<S>,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n patchesCallback?: TPatchesCallback,\r\n) {\r\n const currentState = store.getRawState();\r\n\r\n let nextState: S;\r\n\r\n if (store._hasPatchListeners() || patchesCallback != null) {\r\n const [next, patches, inversePatches] = applyUpdaterWithPatches(currentState, updater);\r\n\r\n if (patches.length > 0) {\r\n if (patchesCallback != null) {\r\n patchesCallback(patches, inversePatches);\r\n }\r\n store._emitPatches(patches, inversePatches);\r\n }\r\n\r\n nextState = next;\r\n } else {\r\n nextState = applyUpdater(currentState, updater);\r\n }\r\n\r\n // Reference guard: an updater that mutated nothing yields the same reference,\r\n // so we skip the dispatch entirely.\r\n if (nextState !== currentState) {\r\n store._updateState(nextState);\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Store-PjfFkZ2I.js","names":[],"sources":["../src/core/Store.ts"],"sourcesContent":["import { deepEqual } from \"fast-equals\";\r\nimport {\r\n applyPatches,\r\n type Draft,\r\n enablePatches,\r\n type Patch,\r\n type PatchListener,\r\n produce,\r\n produceWithPatches,\r\n} from \"immer\";\r\n\r\n// Immer emits JSON patches for `produceWithPatches`, which the store exposes via\r\n// `listenToPatches`. This must run once, before any patch-producing update.\r\nenablePatches();\r\n\r\n/**\r\n * A plain pub/sub listener. Fired (in the order added) every time the store's\r\n * root state reference changes. This is the vanilla integration point that any\r\n * ecosystem — including the React adapter's `useSyncExternalStore` — builds on.\r\n */\r\nexport type TUpdateListener = () => void;\r\n\r\n/**\r\n * @typeParam S The store's state\r\n * @param draft The mutable draft to change during this update (Immer proxy).\r\n * @param original A readonly snapshot of the state as it was before this update.\r\n */\r\nexport type TUpdateFunction<S> = (draft: Draft<S>, original: S) => void;\r\n\r\n/**\r\n * A selector that derives a watched slice `T` from the full store state `S`.\r\n */\r\nexport type TStoreWatch<S extends object, T> = (state: S) => T;\r\n\r\n/**\r\n * Fired by {@link Store.watch} whenever the watched slice changes structurally.\r\n */\r\nexport type TStoreSubscriptionListener<S extends object, T> = (\r\n watched: T,\r\n allState: S,\r\n previousWatched: T,\r\n) => void;\r\n\r\n/**\r\n * Runs inside an Immer `produce` whenever a watched slice changes, letting the\r\n * store derive further state from its own mutations.\r\n */\r\nexport type TReactionFunction<S extends object, T> = (\r\n watched: T,\r\n draft: Draft<S>,\r\n original: S,\r\n previousWatched: T,\r\n) => void;\r\n\r\nexport type TStoreActionUpdate<S extends object> = (\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n patchesCallback?: TPatchesCallback,\r\n) => void;\r\n\r\nexport type TStoreAction<S extends object> = (update: TStoreActionUpdate<S>) => void;\r\n\r\nexport type TPatchesCallback = (patches: Patch[], inversePatches: Patch[]) => void;\r\n\r\n/**\r\n * @internal\r\n * Drives a registered reaction. `forceRun` bypasses the change-detection\r\n * fast-path (used when a reaction is created with `runNow`).\r\n */\r\ntype TRunReactionFunction = (forceRun?: boolean) => void;\r\n\r\n/**\r\n * @internal\r\n * Drives a registered selector subscription on every store emission.\r\n */\r\ntype TRunSubscriptionFunction = () => void;\r\n\r\n/**\r\n * @internal\r\n * Binds a reaction definition to a concrete store instance.\r\n */\r\ntype TReactionCreator<S extends object> = (store: Store<S>) => TRunReactionFunction;\r\n\r\nexport interface IStoreInternalOptions<S extends object> {\r\n ssr: boolean;\r\n reactionCreators?: TReactionCreator<S>[];\r\n}\r\n\r\nexport interface ICreateReactionOptions {\r\n runNow?: boolean;\r\n runNowWithSideEffects?: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Builds the per-emission runner for a selector subscription.\r\n *\r\n * Change detection follows the \"Fast-Path\" rule: Immer's structural sharing\r\n * means an untouched branch keeps its exact reference, so a strict `===` check\r\n * resolves the overwhelmingly common \"nothing changed\" case in 0ms. Only when\r\n * the reference actually changes do we pay for a `deepEqual` traversal to\r\n * confirm the change is structural and not just a new-but-equal reference.\r\n */\r\nfunction makeSubscriptionFunction<S extends object, T>(\r\n store: Store<S>,\r\n watch: TStoreWatch<S, T>,\r\n listener: TStoreSubscriptionListener<S, T>,\r\n): TRunSubscriptionFunction {\r\n let lastWatchState: T = watch(store.getRawState());\r\n\r\n return () => {\r\n const currentState = store.getRawState();\r\n const nextWatchState = watch(currentState);\r\n\r\n // Fast-path: reference is identical → the watched branch was never touched.\r\n if (nextWatchState === lastWatchState) {\r\n return;\r\n }\r\n\r\n // Reference changed — fall back to deep equality to confirm real change.\r\n if (deepEqual(nextWatchState, lastWatchState)) {\r\n // Structurally equal: adopt the new reference so the fast-path stays hot,\r\n // but do not notify — nothing the watcher cares about actually changed.\r\n lastWatchState = nextWatchState;\r\n return;\r\n }\r\n\r\n const previousWatched = lastWatchState;\r\n lastWatchState = nextWatchState;\r\n listener(nextWatchState, currentState, previousWatched);\r\n };\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Builds a reaction creator. Reactions follow the same Fast-Path rule as\r\n * subscriptions, then run their recipe inside Immer to derive further state.\r\n */\r\nfunction makeReactionFunctionCreator<S extends object, T>(\r\n watch: TStoreWatch<S, T>,\r\n reaction: TReactionFunction<S, T>,\r\n): TReactionCreator<S> {\r\n return (store) => {\r\n let lastWatchState: T = watch(store.getRawState());\r\n\r\n return (forceRun = false) => {\r\n const currentState = store.getRawState();\r\n const nextWatchState = watch(currentState);\r\n\r\n if (!forceRun) {\r\n // Fast-path: identical reference → skip entirely.\r\n if (nextWatchState === lastWatchState) {\r\n return;\r\n }\r\n\r\n // New reference but structurally equal → adopt and skip the recipe.\r\n if (deepEqual(nextWatchState, lastWatchState)) {\r\n lastWatchState = nextWatchState;\r\n return;\r\n }\r\n }\r\n\r\n const previousWatched = lastWatchState;\r\n lastWatchState = nextWatchState;\r\n\r\n // Reactions mutate via Immer but must not re-enter the reaction loop, so\r\n // they write back through the no-reaction update path.\r\n if (store._hasPatchListeners()) {\r\n const [nextState, patches, inversePatches] = produceWithPatches(\r\n currentState,\r\n (draft: Draft<S>) => {\r\n reaction(nextWatchState, draft, currentState, previousWatched);\r\n },\r\n );\r\n\r\n store._updateStateWithoutReaction(nextState);\r\n\r\n if (patches.length > 0) {\r\n store._emitPatches(patches, inversePatches);\r\n }\r\n } else {\r\n const nextState = produce(currentState, (draft: Draft<S>) => {\r\n reaction(nextWatchState, draft, currentState, previousWatched);\r\n });\r\n store._updateStateWithoutReaction(nextState);\r\n }\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * A framework-agnostic, Immer-backed state container.\r\n *\r\n * The store owns a single immutable state value and a `Set` of plain\r\n * listeners. Every mutation runs through Immer's `produce`, and listeners are\r\n * only notified when the resulting root reference actually changes — making\r\n * \"no-op\" updates genuinely free for subscribers.\r\n *\r\n * @typeParam S Your store's state interface.\r\n */\r\nexport class Store<S extends object = object> {\r\n private currentState: S;\r\n private readonly createInitialState: () => S;\r\n private ssr = false;\r\n\r\n /** Plain pub/sub listeners — a Set both dedupes and dispatches fast. */\r\n private readonly listeners = new Set<TUpdateListener>();\r\n\r\n private reactionCreators: TReactionCreator<S>[] = [];\r\n private reactions: TRunReactionFunction[] = [];\r\n private clientSubscriptions: TRunSubscriptionFunction[] = [];\r\n\r\n /**\r\n * @internal\r\n */\r\n public _patchListeners: PatchListener[] = [];\r\n\r\n constructor(initialState: S | (() => S)) {\r\n if (initialState instanceof Function) {\r\n this.createInitialState = initialState;\r\n this.currentState = initialState();\r\n } else {\r\n this.createInitialState = () => initialState;\r\n this.currentState = initialState;\r\n }\r\n }\r\n\r\n get state(): S {\r\n return Object.freeze(this.currentState);\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _setInternalOptions({ ssr, reactionCreators = [] }: IStoreInternalOptions<S>) {\r\n this.ssr = ssr;\r\n this.reactionCreators = reactionCreators;\r\n this.reactions = reactionCreators.map((rc) => rc(this));\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _getReactionCreators(): TReactionCreator<S>[] {\r\n return this.reactionCreators;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _instantiateReactions() {\r\n this.reactions = this.reactionCreators.map((rc) => rc(this));\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _getInitialState(): S {\r\n return this.createInitialState();\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _hasPatchListeners(): boolean {\r\n return this._patchListeners.length > 0;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n _emitPatches(patches: Patch[], inversePatches: Patch[]) {\r\n for (const listener of this._patchListeners) {\r\n listener(patches, inversePatches);\r\n }\r\n }\r\n\r\n /**\r\n * @internal\r\n *\r\n * Writes a new state value without running reactions. Used by reactions\r\n * themselves to avoid re-entrancy.\r\n */\r\n _updateStateWithoutReaction(nextState: S) {\r\n this.currentState = nextState;\r\n }\r\n\r\n /**\r\n * @internal\r\n *\r\n * Commits a new root state, runs reactions, then dispatches to all\r\n * subscribers. Callers are responsible for the `nextState !== currentState`\r\n * reference guard before invoking this.\r\n */\r\n _updateState(nextState: S) {\r\n this.currentState = nextState;\r\n\r\n // Reactions run first and may derive further state (without re-triggering).\r\n for (const runReaction of this.reactions) {\r\n runReaction();\r\n }\r\n\r\n if (this.ssr) {\r\n return;\r\n }\r\n\r\n for (const runSubscription of this.clientSubscriptions) {\r\n runSubscription();\r\n }\r\n\r\n for (const listener of this.listeners) {\r\n listener();\r\n }\r\n }\r\n\r\n /**\r\n * Returns the raw state object contained within this store at this moment.\r\n *\r\n * ---\r\n * ** WARNING **\r\n *\r\n * Most of the time, if you're using this in your app, there's probably a\r\n * better way to do it (a selector subscription or the React adapter).\r\n * ---\r\n */\r\n getRawState(): S {\r\n return this.currentState;\r\n }\r\n\r\n /**\r\n * Subscribe a plain listener to store mutations. The listener fires once per\r\n * committed update (root reference change) and receives no arguments — read\r\n * the latest value with {@link getRawState}.\r\n *\r\n * This is the low-level primitive that vanilla code and framework adapters\r\n * (e.g. React's `useSyncExternalStore`) build upon.\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n subscribe(listener: TUpdateListener): () => void {\r\n this.listeners.add(listener);\r\n return () => {\r\n this.listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to a derived slice of state. The `listener` only fires when the\r\n * watched value changes structurally (per the Fast-Path rule).\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n watch<T>(watch: TStoreWatch<S, T>, listener: TStoreSubscriptionListener<S, T>): () => void {\r\n if (this.ssr) {\r\n return () => {\r\n console.warn(\r\n `@nice-code/state: Subscriptions made on the server side are not registered, so this unsubscribe call does nothing.`,\r\n );\r\n };\r\n }\r\n\r\n const run = makeSubscriptionFunction(this, watch, listener);\r\n this.clientSubscriptions.push(run);\r\n\r\n return () => {\r\n this.clientSubscriptions = this.clientSubscriptions.filter((f) => f !== run);\r\n };\r\n }\r\n\r\n /**\r\n * Register a reaction: when the watched slice changes, the `reaction` recipe\r\n * runs inside Immer to derive further state on the same store.\r\n *\r\n * @returns A function that removes the reaction.\r\n */\r\n createReaction<T>(\r\n watch: TStoreWatch<S, T>,\r\n reaction: TReactionFunction<S, T>,\r\n { runNow = false, runNowWithSideEffects = false }: ICreateReactionOptions = {},\r\n ): () => void {\r\n const creator = makeReactionFunctionCreator(watch, reaction);\r\n this.reactionCreators.push(creator);\r\n\r\n const run = creator(this);\r\n this.reactions.push(run);\r\n\r\n if (runNow || runNowWithSideEffects) {\r\n run(true);\r\n\r\n if (runNowWithSideEffects && !this.ssr) {\r\n this._updateState(this.currentState);\r\n }\r\n }\r\n\r\n return () => {\r\n this.reactions = this.reactions.filter((f) => f !== run);\r\n this.reactionCreators = this.reactionCreators.filter((f) => f !== creator);\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to the Immer patches produced by each update.\r\n *\r\n * @returns An unsubscribe function.\r\n */\r\n listenToPatches(patchListener: PatchListener): () => void {\r\n this._patchListeners.push(patchListener);\r\n return () => {\r\n this._patchListeners = this._patchListeners.filter((f) => f !== patchListener);\r\n };\r\n }\r\n\r\n /**\r\n * Mutate the store via one or more Immer update functions.\r\n *\r\n * @param updater A single update function, or an array applied in order.\r\n * @param patchesCallback Optional callback receiving the patches for this update.\r\n */\r\n update(updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback) {\r\n update(this, updater, patchesCallback);\r\n }\r\n\r\n /**\r\n * Replace the store's state entirely with a new state value.\r\n */\r\n replace(newState: S) {\r\n if (newState !== this.currentState) {\r\n this._updateState(newState);\r\n }\r\n }\r\n\r\n /**\r\n * Replace the store's state by mapping from the current state.\r\n */\r\n replaceFromCurrent(replacer: (state: S) => S) {\r\n const nextState = replacer(this.currentState);\r\n if (nextState !== this.currentState) {\r\n this._updateState(nextState);\r\n }\r\n }\r\n\r\n /**\r\n * Apply a set of Immer patches to the store.\r\n */\r\n applyPatches(patches: Patch[]) {\r\n applyPatchesToStore(this, patches);\r\n }\r\n}\r\n\r\n/**\r\n * Apply Immer patches to a store, committing only if the root reference changes.\r\n */\r\nexport function applyPatchesToStore<S extends object = object>(store: Store<S>, patches: Patch[]) {\r\n const currentState = store.getRawState();\r\n const nextState = applyPatches(currentState, patches);\r\n if (nextState !== currentState) {\r\n store._updateState(nextState);\r\n }\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Runs an updater (or array of updaters) through Immer, collecting patches.\r\n */\r\nfunction applyUpdaterWithPatches<S extends object>(\r\n currentState: S,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n): [S, Patch[], Patch[]] {\r\n if (typeof updater === \"function\") {\r\n const [next, patches, inversePatches] = produceWithPatches(currentState, (draft: Draft<S>) => {\r\n updater(draft, currentState);\r\n });\r\n return [next, patches, inversePatches];\r\n }\r\n\r\n let state = currentState;\r\n const patches: Patch[] = [];\r\n const inversePatches: Patch[] = [];\r\n\r\n for (const single of updater) {\r\n const [next, p, ip] = produceWithPatches(state, (draft: Draft<S>) => {\r\n single(draft, state);\r\n });\r\n state = next;\r\n patches.push(...p);\r\n inversePatches.push(...ip);\r\n }\r\n\r\n return [state, patches, inversePatches];\r\n}\r\n\r\n/**\r\n * @internal\r\n *\r\n * Runs an updater (or array of updaters) through Immer without tracking patches.\r\n */\r\nfunction applyUpdater<S extends object>(\r\n currentState: S,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n): S {\r\n if (typeof updater === \"function\") {\r\n return produce(currentState, (draft: Draft<S>) => {\r\n updater(draft, currentState);\r\n });\r\n }\r\n\r\n return updater.reduce<S>(\r\n (previousState, single) =>\r\n produce(previousState, (draft: Draft<S>) => {\r\n single(draft, previousState);\r\n }),\r\n currentState,\r\n );\r\n}\r\n\r\n/**\r\n * Mutate a store via one or more Immer update functions.\r\n *\r\n * Patches are only computed when there's a consumer for them (a registered\r\n * patch listener or a `patchesCallback`), keeping the common path allocation-free.\r\n * Listeners are notified only when the root reference actually changes.\r\n *\r\n * @param store The store to update.\r\n * @param updater A single update function, or an array applied in order.\r\n * @param patchesCallback Optional callback receiving the patches for this update.\r\n */\r\nexport function update<S extends object = object>(\r\n store: Store<S>,\r\n updater: TUpdateFunction<S> | TUpdateFunction<S>[],\r\n patchesCallback?: TPatchesCallback,\r\n) {\r\n const currentState = store.getRawState();\r\n\r\n let nextState: S;\r\n\r\n if (store._hasPatchListeners() || patchesCallback != null) {\r\n const [next, patches, inversePatches] = applyUpdaterWithPatches(currentState, updater);\r\n\r\n if (patches.length > 0) {\r\n if (patchesCallback != null) {\r\n patchesCallback(patches, inversePatches);\r\n }\r\n store._emitPatches(patches, inversePatches);\r\n }\r\n\r\n nextState = next;\r\n } else {\r\n nextState = applyUpdater(currentState, updater);\r\n }\r\n\r\n // Reference guard: an updater that mutated nothing yields the same reference,\r\n // so we skip the dispatch entirely.\r\n if (nextState !== currentState) {\r\n store._updateState(nextState);\r\n }\r\n}\r\n"],"mappings":"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"}
|