@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.
@@ -198,4 +198,4 @@ declare function applyPatchesToStore<S extends object = object>(store: Store<S>,
198
198
  declare function update<S extends object = object>(store: Store<S>, updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback): void;
199
199
  //#endregion
200
200
  export { TReactionFunction as a, TStoreSubscriptionListener as c, TUpdateListener as d, applyPatchesToStore as f, TPatchesCallback as i, TStoreWatch as l, IStoreInternalOptions as n, TStoreAction as o, update as p, Store as r, TStoreActionUpdate as s, ICreateReactionOptions as t, TUpdateFunction as u };
201
- //# sourceMappingURL=Store-B65MojT2.d.ts.map
201
+ //# sourceMappingURL=Store-B65MojT2.d.cts.map
@@ -0,0 +1,201 @@
1
+ import { Draft, Patch, PatchListener } from "immer";
2
+
3
+ //#region src/core/Store.d.ts
4
+ /**
5
+ * A plain pub/sub listener. Fired (in the order added) every time the store's
6
+ * root state reference changes. This is the vanilla integration point that any
7
+ * ecosystem — including the React adapter's `useSyncExternalStore` — builds on.
8
+ */
9
+ type TUpdateListener = () => void;
10
+ /**
11
+ * @typeParam S The store's state
12
+ * @param draft The mutable draft to change during this update (Immer proxy).
13
+ * @param original A readonly snapshot of the state as it was before this update.
14
+ */
15
+ type TUpdateFunction<S> = (draft: Draft<S>, original: S) => void;
16
+ /**
17
+ * A selector that derives a watched slice `T` from the full store state `S`.
18
+ */
19
+ type TStoreWatch<S extends object, T> = (state: S) => T;
20
+ /**
21
+ * Fired by {@link Store.watch} whenever the watched slice changes structurally.
22
+ */
23
+ type TStoreSubscriptionListener<S extends object, T> = (watched: T, allState: S, previousWatched: T) => void;
24
+ /**
25
+ * Runs inside an Immer `produce` whenever a watched slice changes, letting the
26
+ * store derive further state from its own mutations.
27
+ */
28
+ type TReactionFunction<S extends object, T> = (watched: T, draft: Draft<S>, original: S, previousWatched: T) => void;
29
+ type TStoreActionUpdate<S extends object> = (updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback) => void;
30
+ type TStoreAction<S extends object> = (update: TStoreActionUpdate<S>) => void;
31
+ type TPatchesCallback = (patches: Patch[], inversePatches: Patch[]) => void;
32
+ /**
33
+ * @internal
34
+ * Drives a registered reaction. `forceRun` bypasses the change-detection
35
+ * fast-path (used when a reaction is created with `runNow`).
36
+ */
37
+ type TRunReactionFunction = (forceRun?: boolean) => void;
38
+ /**
39
+ * @internal
40
+ * Binds a reaction definition to a concrete store instance.
41
+ */
42
+ type TReactionCreator<S extends object> = (store: Store<S>) => TRunReactionFunction;
43
+ interface IStoreInternalOptions<S extends object> {
44
+ ssr: boolean;
45
+ reactionCreators?: TReactionCreator<S>[];
46
+ }
47
+ interface ICreateReactionOptions {
48
+ runNow?: boolean;
49
+ runNowWithSideEffects?: boolean;
50
+ }
51
+ /**
52
+ * A framework-agnostic, Immer-backed state container.
53
+ *
54
+ * The store owns a single immutable state value and a `Set` of plain
55
+ * listeners. Every mutation runs through Immer's `produce`, and listeners are
56
+ * only notified when the resulting root reference actually changes — making
57
+ * "no-op" updates genuinely free for subscribers.
58
+ *
59
+ * @typeParam S Your store's state interface.
60
+ */
61
+ declare class Store<S extends object = object> {
62
+ private currentState;
63
+ private readonly createInitialState;
64
+ private ssr;
65
+ /** Plain pub/sub listeners — a Set both dedupes and dispatches fast. */
66
+ private readonly listeners;
67
+ private reactionCreators;
68
+ private reactions;
69
+ private clientSubscriptions;
70
+ /**
71
+ * @internal
72
+ */
73
+ _patchListeners: PatchListener[];
74
+ constructor(initialState: S | (() => S));
75
+ get state(): S;
76
+ /**
77
+ * @internal
78
+ */
79
+ _setInternalOptions({
80
+ ssr,
81
+ reactionCreators
82
+ }: IStoreInternalOptions<S>): void;
83
+ /**
84
+ * @internal
85
+ */
86
+ _getReactionCreators(): TReactionCreator<S>[];
87
+ /**
88
+ * @internal
89
+ */
90
+ _instantiateReactions(): void;
91
+ /**
92
+ * @internal
93
+ */
94
+ _getInitialState(): S;
95
+ /**
96
+ * @internal
97
+ */
98
+ _hasPatchListeners(): boolean;
99
+ /**
100
+ * @internal
101
+ */
102
+ _emitPatches(patches: Patch[], inversePatches: Patch[]): void;
103
+ /**
104
+ * @internal
105
+ *
106
+ * Writes a new state value without running reactions. Used by reactions
107
+ * themselves to avoid re-entrancy.
108
+ */
109
+ _updateStateWithoutReaction(nextState: S): void;
110
+ /**
111
+ * @internal
112
+ *
113
+ * Commits a new root state, runs reactions, then dispatches to all
114
+ * subscribers. Callers are responsible for the `nextState !== currentState`
115
+ * reference guard before invoking this.
116
+ */
117
+ _updateState(nextState: S): void;
118
+ /**
119
+ * Returns the raw state object contained within this store at this moment.
120
+ *
121
+ * ---
122
+ * ** WARNING **
123
+ *
124
+ * Most of the time, if you're using this in your app, there's probably a
125
+ * better way to do it (a selector subscription or the React adapter).
126
+ * ---
127
+ */
128
+ getRawState(): S;
129
+ /**
130
+ * Subscribe a plain listener to store mutations. The listener fires once per
131
+ * committed update (root reference change) and receives no arguments — read
132
+ * the latest value with {@link getRawState}.
133
+ *
134
+ * This is the low-level primitive that vanilla code and framework adapters
135
+ * (e.g. React's `useSyncExternalStore`) build upon.
136
+ *
137
+ * @returns An unsubscribe function.
138
+ */
139
+ subscribe(listener: TUpdateListener): () => void;
140
+ /**
141
+ * Subscribe to a derived slice of state. The `listener` only fires when the
142
+ * watched value changes structurally (per the Fast-Path rule).
143
+ *
144
+ * @returns An unsubscribe function.
145
+ */
146
+ watch<T>(watch: TStoreWatch<S, T>, listener: TStoreSubscriptionListener<S, T>): () => void;
147
+ /**
148
+ * Register a reaction: when the watched slice changes, the `reaction` recipe
149
+ * runs inside Immer to derive further state on the same store.
150
+ *
151
+ * @returns A function that removes the reaction.
152
+ */
153
+ createReaction<T>(watch: TStoreWatch<S, T>, reaction: TReactionFunction<S, T>, {
154
+ runNow,
155
+ runNowWithSideEffects
156
+ }?: ICreateReactionOptions): () => void;
157
+ /**
158
+ * Subscribe to the Immer patches produced by each update.
159
+ *
160
+ * @returns An unsubscribe function.
161
+ */
162
+ listenToPatches(patchListener: PatchListener): () => void;
163
+ /**
164
+ * Mutate the store via one or more Immer update functions.
165
+ *
166
+ * @param updater A single update function, or an array applied in order.
167
+ * @param patchesCallback Optional callback receiving the patches for this update.
168
+ */
169
+ update(updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback): void;
170
+ /**
171
+ * Replace the store's state entirely with a new state value.
172
+ */
173
+ replace(newState: S): void;
174
+ /**
175
+ * Replace the store's state by mapping from the current state.
176
+ */
177
+ replaceFromCurrent(replacer: (state: S) => S): void;
178
+ /**
179
+ * Apply a set of Immer patches to the store.
180
+ */
181
+ applyPatches(patches: Patch[]): void;
182
+ }
183
+ /**
184
+ * Apply Immer patches to a store, committing only if the root reference changes.
185
+ */
186
+ declare function applyPatchesToStore<S extends object = object>(store: Store<S>, patches: Patch[]): void;
187
+ /**
188
+ * Mutate a store via one or more Immer update functions.
189
+ *
190
+ * Patches are only computed when there's a consumer for them (a registered
191
+ * patch listener or a `patchesCallback`), keeping the common path allocation-free.
192
+ * Listeners are notified only when the root reference actually changes.
193
+ *
194
+ * @param store The store to update.
195
+ * @param updater A single update function, or an array applied in order.
196
+ * @param patchesCallback Optional callback receiving the patches for this update.
197
+ */
198
+ declare function update<S extends object = object>(store: Store<S>, updater: TUpdateFunction<S> | TUpdateFunction<S>[], patchesCallback?: TPatchesCallback): void;
199
+ //#endregion
200
+ export { TReactionFunction as a, TStoreSubscriptionListener as c, TUpdateListener as d, applyPatchesToStore as f, TPatchesCallback as i, TStoreWatch as l, IStoreInternalOptions as n, TStoreAction as o, update as p, Store as r, TStoreActionUpdate as s, ICreateReactionOptions as t, TUpdateFunction as u };
201
+ //# sourceMappingURL=Store-B65MojT2.d.mts.map
@@ -363,4 +363,4 @@ Object.defineProperty(exports, "update", {
363
363
  }
364
364
  });
365
365
 
366
- //# sourceMappingURL=Store-CI9N0P6I.js.map
366
+ //# sourceMappingURL=Store-CI9N0P6I.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store-CI9N0P6I.cjs","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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"}
@@ -346,4 +346,4 @@ function update(store, updater, patchesCallback) {
346
346
  //#endregion
347
347
  export { applyPatchesToStore as n, update as r, Store as t };
348
348
 
349
- //# sourceMappingURL=Store-PjfFkZ2I.js.map
349
+ //# sourceMappingURL=Store-PjfFkZ2I.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store-PjfFkZ2I.mjs","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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"}