@angular-architects/ngrx-toolkit 18.1.0 → 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +4 -12
  2. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +15 -15
  3. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +1 -1
  4. package/fesm2022/angular-architects-ngrx-toolkit.mjs +487 -78
  5. package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -1
  6. package/index.d.ts +9 -2
  7. package/lib/devtools/features/with-disabled-name-indicies.d.ts +27 -0
  8. package/lib/devtools/features/with-glitch-tracking.d.ts +30 -0
  9. package/lib/devtools/features/with-mapper.d.ts +28 -0
  10. package/lib/devtools/internal/current-action-names.d.ts +1 -0
  11. package/lib/devtools/internal/default-tracker.d.ts +13 -0
  12. package/lib/devtools/internal/devtools-feature.d.ts +24 -0
  13. package/lib/devtools/internal/devtools-syncer.service.d.ts +35 -0
  14. package/lib/devtools/internal/glitch-tracker.service.d.ts +18 -0
  15. package/lib/devtools/internal/models.d.ts +25 -0
  16. package/lib/devtools/rename-devtools-name.d.ts +7 -0
  17. package/lib/devtools/update-state.d.ts +17 -0
  18. package/lib/devtools/with-dev-tools-stub.d.ts +5 -0
  19. package/lib/devtools/with-devtools.d.ts +30 -0
  20. package/lib/shared/prettify.d.ts +1 -1
  21. package/lib/shared/throw-if-null.d.ts +1 -0
  22. package/lib/with-call-state.d.ts +2 -2
  23. package/lib/with-data-service.d.ts +3 -3
  24. package/lib/with-pagination.d.ts +4 -4
  25. package/lib/with-reset.d.ts +29 -0
  26. package/lib/with-storage-sync.d.ts +2 -2
  27. package/lib/with-undo-redo.d.ts +4 -3
  28. package/package.json +6 -7
  29. package/redux-connector/src/lib/create-redux.d.ts +4 -4
  30. package/redux-connector/src/lib/model.d.ts +5 -0
  31. package/redux-connector/src/lib/rxjs-interop/redux-method.d.ts +5 -2
  32. package/redux-connector/src/lib/signal-redux-store.d.ts +10 -2
  33. package/redux-connector/src/lib/util.d.ts +2 -2
  34. package/esm2022/angular-architects-ngrx-toolkit.mjs +0 -5
  35. package/esm2022/index.mjs +0 -8
  36. package/esm2022/lib/assertions/assertions.mjs +0 -6
  37. package/esm2022/lib/shared/prettify.mjs +0 -2
  38. package/esm2022/lib/shared/signal-store-models.mjs +0 -2
  39. package/esm2022/lib/with-call-state.mjs +0 -60
  40. package/esm2022/lib/with-data-service.mjs +0 -202
  41. package/esm2022/lib/with-devtools.mjs +0 -92
  42. package/esm2022/lib/with-pagination.mjs +0 -209
  43. package/esm2022/lib/with-redux.mjs +0 -100
  44. package/esm2022/lib/with-storage-sync.mjs +0 -56
  45. package/esm2022/lib/with-undo-redo.mjs +0 -113
  46. package/esm2022/redux-connector/angular-architects-ngrx-toolkit-redux-connector.mjs +0 -5
  47. package/esm2022/redux-connector/index.mjs +0 -3
  48. package/esm2022/redux-connector/src/lib/create-redux.mjs +0 -41
  49. package/esm2022/redux-connector/src/lib/model.mjs +0 -2
  50. package/esm2022/redux-connector/src/lib/rxjs-interop/redux-method.mjs +0 -22
  51. package/esm2022/redux-connector/src/lib/signal-redux-store.mjs +0 -43
  52. package/esm2022/redux-connector/src/lib/util.mjs +0 -13
  53. package/lib/with-devtools.d.ts +0 -38
@@ -1,80 +1,428 @@
1
- import { patchState as patchState$1, signalStoreFeature, withState, withComputed, withMethods, withHooks, getState } from '@ngrx/signals';
2
- import { signal, effect, inject, PLATFORM_ID, computed, isSignal, untracked } from '@angular/core';
3
- import { isPlatformServer } from '@angular/common';
1
+ import { getState, signalStoreFeature, withMethods, withHooks, watchState, patchState as patchState$1, withState, withComputed, withProps } from '@ngrx/signals';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, PLATFORM_ID, Injectable, signal, effect, computed, isSignal, untracked } from '@angular/core';
4
+ import { isPlatformBrowser, isPlatformServer } from '@angular/common';
4
5
  import { Subject } from 'rxjs';
5
6
  import { setAllEntities, addEntity, updateEntity, removeEntity } from '@ngrx/signals/entities';
6
7
 
7
- const storeRegistry = signal({});
8
- let currentActionNames = new Set();
9
- let synchronizationInitialized = false;
10
- function initSynchronization() {
11
- effect(() => {
12
- if (!connection) {
8
+ /**
9
+ * Stub for DevTools integration. Can be used to disable DevTools in production.
10
+ */
11
+ const withDevToolsStub = () => (store) => store;
12
+
13
+ const currentActionNames = new Set();
14
+
15
+ function throwIfNull(obj) {
16
+ if (obj === null || obj === undefined) {
17
+ throw new Error('');
18
+ }
19
+ return obj;
20
+ }
21
+
22
+ const dummyConnection = {
23
+ send: () => void true,
24
+ };
25
+ /**
26
+ * A service provided by the root injector is
27
+ * required because the synchronization runs
28
+ * globally.
29
+ *
30
+ * The SignalStore could be provided in a component.
31
+ * If the effect starts in the injection
32
+ * context of the SignalStore, the complete sync
33
+ * process would shut down once the component gets
34
+ * destroyed.
35
+ */
36
+ class DevtoolsSyncer {
37
+ /**
38
+ * Stores all SignalStores that are connected to the
39
+ * DevTools along their options, names and id.
40
+ */
41
+ #stores = {};
42
+ #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
43
+ #trackers = [];
44
+ /**
45
+ * Maintains the current states of all stores to avoid conflicts
46
+ * between glitch-free and glitched trackers when used simultaneously.
47
+ *
48
+ * The challenge lies in ensuring that glitched trackers do not
49
+ * interfere with the synchronization process of glitch-free trackers.
50
+ * Specifically, glitched trackers could cause the synchronization to
51
+ * read the current state of stores managed by glitch-free trackers.
52
+ *
53
+ * Therefore, the synchronization process doesn't read the state from
54
+ * each store, but relies on #currentState.
55
+ *
56
+ * Please note, that here the key is the name and not the id.
57
+ */
58
+ #currentState = {};
59
+ #currentId = 1;
60
+ #connection = this.#isBrowser
61
+ ? window.__REDUX_DEVTOOLS_EXTENSION__
62
+ ? window.__REDUX_DEVTOOLS_EXTENSION__.connect({
63
+ name: 'NgRx SignalStore',
64
+ })
65
+ : dummyConnection
66
+ : dummyConnection;
67
+ constructor() {
68
+ if (!this.#isBrowser) {
13
69
  return;
14
70
  }
15
- const stores = storeRegistry();
16
- const rootState = {};
17
- for (const name in stores) {
18
- const store = stores[name];
19
- rootState[name] = store();
71
+ const isToolkitAvailable = Boolean(window.__REDUX_DEVTOOLS_EXTENSION__);
72
+ if (!isToolkitAvailable) {
73
+ throw new Error('NgRx Toolkit/DevTools: Redux DevTools Extension is not available.');
20
74
  }
75
+ }
76
+ ngOnDestroy() {
77
+ currentActionNames.clear();
78
+ }
79
+ syncToDevTools(changedStatePerId) {
80
+ const mappedChangedStatePerName = Object.entries(changedStatePerId).reduce((acc, [id, store]) => {
81
+ const { options, name } = this.#stores[id];
82
+ acc[name] = options.map(store);
83
+ return acc;
84
+ }, {});
85
+ this.#currentState = {
86
+ ...this.#currentState,
87
+ ...mappedChangedStatePerName,
88
+ };
21
89
  const names = Array.from(currentActionNames);
22
90
  const type = names.length ? names.join(', ') : 'Store Update';
23
- currentActionNames = new Set();
24
- connection.send({ type }, rootState);
25
- });
91
+ currentActionNames.clear();
92
+ this.#connection.send({ type }, this.#currentState);
93
+ }
94
+ getNextId() {
95
+ return String(this.#currentId++);
96
+ }
97
+ /**
98
+ * Consumer provides the id. That is because we can only start
99
+ * tracking the store in the init hook.
100
+ * Unfortunately, methods for renaming having the final id
101
+ * need to be defined already before.
102
+ * That's why `withDevtools` requests first the id and
103
+ * then registers itself later.
104
+ */
105
+ addStore(id, name, store, options) {
106
+ let storeName = name;
107
+ const names = Object.values(this.#stores).map((store) => store.name);
108
+ if (names.includes(storeName)) {
109
+ const { options } = throwIfNull(Object.values(this.#stores).find((store) => store.name === storeName));
110
+ if (!options.indexNames) {
111
+ throw new Error(`An instance of the store ${storeName} already exists. \
112
+ Enable automatic indexing via withDevTools('${storeName}', { indexNames: true }), or rename it upon instantiation.`);
113
+ }
114
+ }
115
+ for (let i = 1; names.includes(storeName); i++) {
116
+ storeName = `${name}-${i}`;
117
+ }
118
+ this.#stores[id] = { name: storeName, options };
119
+ const tracker = options.tracker;
120
+ if (!this.#trackers.includes(tracker)) {
121
+ this.#trackers.push(tracker);
122
+ }
123
+ tracker.onChange((changedState) => this.syncToDevTools(changedState));
124
+ tracker.track(id, store);
125
+ }
126
+ removeStore(id) {
127
+ const name = this.#stores[id].name;
128
+ this.#stores = Object.entries(this.#stores).reduce((newStore, [storeId, value]) => {
129
+ if (storeId !== id) {
130
+ newStore[storeId] = value;
131
+ }
132
+ return newStore;
133
+ }, {});
134
+ this.#currentState = Object.entries(this.#currentState).reduce((newState, [storeName, state]) => {
135
+ if (storeName !== name) {
136
+ newState[name] = state;
137
+ }
138
+ return newState;
139
+ }, {});
140
+ for (const tracker of this.#trackers) {
141
+ tracker.removeStore(id);
142
+ }
143
+ }
144
+ renameStore(oldName, newName) {
145
+ const storeNames = Object.values(this.#stores).map((store) => store.name);
146
+ const id = throwIfNull(Object.keys(this.#stores).find((id) => this.#stores[id].name === oldName));
147
+ if (storeNames.includes(newName)) {
148
+ throw new Error(`NgRx Toolkit/DevTools: cannot rename from ${oldName} to ${newName}. ${newName} is already assigned to another SignalStore instance.`);
149
+ }
150
+ this.#stores = Object.entries(this.#stores).reduce((newStore, [id, value]) => {
151
+ if (value.name === oldName) {
152
+ newStore[id] = { ...value, name: newName };
153
+ }
154
+ else {
155
+ newStore[id] = value;
156
+ }
157
+ return newStore;
158
+ }, {});
159
+ // we don't rename in #currentState but wait for tracker to notify
160
+ // us with a changed state that contains that name.
161
+ this.#currentState = Object.entries(this.#currentState).reduce((newState, [storeName, state]) => {
162
+ if (storeName !== oldName) {
163
+ newState[storeName] = state;
164
+ }
165
+ return newState;
166
+ }, {});
167
+ this.#trackers.forEach((tracker) => tracker.notifyRenamedStore(id));
168
+ }
169
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevtoolsSyncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
170
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevtoolsSyncer, providedIn: 'root' }); }
26
171
  }
27
- function getValueFromSymbol(obj, symbol) {
28
- if (typeof obj === 'object' && obj && symbol in obj) {
29
- return obj[symbol];
172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevtoolsSyncer, decorators: [{
173
+ type: Injectable,
174
+ args: [{ providedIn: 'root' }]
175
+ }], ctorParameters: () => [] });
176
+
177
+ class DefaultTracker {
178
+ #stores = signal({});
179
+ get stores() {
180
+ return this.#stores();
30
181
  }
182
+ #trackCallback;
183
+ #trackingEffect = effect(() => {
184
+ if (this.#trackCallback === undefined) {
185
+ throw new Error('no callback function defined');
186
+ }
187
+ const stores = this.#stores();
188
+ const fullState = Object.entries(stores).reduce((acc, [id, store]) => {
189
+ return { ...acc, [id]: getState(store) };
190
+ }, {});
191
+ this.#trackCallback(fullState);
192
+ });
193
+ track(id, store) {
194
+ this.#stores.update((value) => ({
195
+ ...value,
196
+ [id]: store,
197
+ }));
198
+ }
199
+ onChange(callback) {
200
+ this.#trackCallback = callback;
201
+ }
202
+ removeStore(id) {
203
+ this.#stores.update((stores) => Object.entries(stores).reduce((newStore, [storeId, state]) => {
204
+ if (storeId !== id) {
205
+ newStore[storeId] = state;
206
+ }
207
+ return newStore;
208
+ }, {}));
209
+ }
210
+ notifyRenamedStore(id) {
211
+ if (this.#stores()[id]) {
212
+ this.#stores.update((stores) => {
213
+ return { ...stores };
214
+ });
215
+ }
216
+ }
217
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DefaultTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
218
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DefaultTracker, providedIn: 'root' }); }
31
219
  }
32
- function getStoreSignal(store) {
33
- const [signalStateKey] = Object.getOwnPropertySymbols(store);
34
- if (!signalStateKey) {
35
- throw new Error('Cannot find State Signal');
220
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DefaultTracker, decorators: [{
221
+ type: Injectable,
222
+ args: [{ providedIn: 'root' }]
223
+ }] });
224
+
225
+ const existingNames = new Map();
226
+ const renameDevtoolsMethodName = '___renameDevtoolsName';
227
+ const uniqueDevtoolsId = '___uniqueDevtoolsId';
228
+ /**
229
+ * Adds this store as a feature state to the Redux DevTools.
230
+ *
231
+ * By default, the action name is 'Store Update'. You can
232
+ * change that via the {@link updateState} method, which has as second
233
+ * parameter the action name.
234
+ *
235
+ * The standalone function {@link renameDevtoolsName} can rename
236
+ * the store name.
237
+ *
238
+ * @param name name of the store as it should appear in the DevTools
239
+ * @param features features to extend or modify the behavior of the Devtools
240
+ */
241
+ function withDevtools(name, ...features) {
242
+ if (existingNames.has(name)) {
243
+ throw new Error(`The store "${name}" has already been registered in the DevTools. Duplicate registration is not allowed.`);
36
244
  }
37
- return getValueFromSymbol(store, signalStateKey);
245
+ existingNames.set(name, true);
246
+ return signalStoreFeature(withMethods(() => {
247
+ const syncer = inject(DevtoolsSyncer);
248
+ const id = syncer.getNextId();
249
+ // TODO: use withProps and symbols
250
+ return {
251
+ [renameDevtoolsMethodName]: (newName) => {
252
+ syncer.renameStore(name, newName);
253
+ },
254
+ [uniqueDevtoolsId]: () => id,
255
+ };
256
+ }), withHooks((store) => {
257
+ const syncer = inject(DevtoolsSyncer);
258
+ const id = String(store[uniqueDevtoolsId]());
259
+ return {
260
+ onInit() {
261
+ const id = String(store[uniqueDevtoolsId]());
262
+ const finalOptions = {
263
+ indexNames: !features.some((f) => f.indexNames === false),
264
+ map: features.find((f) => f.map)?.map ?? ((state) => state),
265
+ tracker: inject(features.find((f) => f.tracker)?.tracker || DefaultTracker),
266
+ };
267
+ syncer.addStore(id, name, store, finalOptions);
268
+ },
269
+ onDestroy() {
270
+ syncer.removeStore(id);
271
+ },
272
+ };
273
+ }));
274
+ }
275
+
276
+ const DEVTOOLS_FEATURE = Symbol('DEVTOOLS_FEATURE');
277
+ function createDevtoolsFeature(options) {
278
+ return {
279
+ [DEVTOOLS_FEATURE]: true,
280
+ ...options,
281
+ };
282
+ }
283
+
284
+ /**
285
+ * If multiple instances of the same SignalStore class
286
+ * exist, their devtool names are indexed.
287
+ *
288
+ * For example:
289
+ *
290
+ * ```typescript
291
+ * const Store = signalStore(
292
+ * withDevtools('flights')
293
+ * )
294
+ *
295
+ * const store1 = new Store(); // will show up as 'flights'
296
+ * const store2 = new Store(); // will show up as 'flights-1'
297
+ * ```
298
+ *
299
+ * With adding `withDisabledNameIndices` to the store:
300
+ * ```typescript
301
+ * const Store = signalStore(
302
+ * withDevtools('flights', withDisabledNameIndices())
303
+ * )
304
+ *
305
+ * const store1 = new Store(); // will show up as 'flights'
306
+ * const store2 = new Store(); //💥 throws an error
307
+ * ```
308
+ *
309
+ */
310
+ function withDisabledNameIndices() {
311
+ return createDevtoolsFeature({ indexNames: false });
38
312
  }
39
- let connection;
313
+
40
314
  /**
41
- * required for testing. is not exported during build
315
+ * Allows you to define a function to map the state.
316
+ *
317
+ * It is needed for huge states, that slows down the Devtools and where
318
+ * you don't need to see the whole state or other reasons.
319
+ *
320
+ * Example:
321
+ *
322
+ * ```typescript
323
+ * const initialState = {
324
+ * id: 1,
325
+ * email: 'john.list@host.com',
326
+ * name: 'John List',
327
+ * enteredPassword: ''
328
+ * }
329
+ *
330
+ * const Store = signalStore(
331
+ * withState(initialState),
332
+ * withDevtools(
333
+ * 'user',
334
+ * withMapper(state => ({...state, enteredPassword: '***' }))
335
+ * )
336
+ * )
337
+ * ```
338
+ *
339
+ * @param map function which maps the state
42
340
  */
43
- function reset() {
44
- connection = undefined;
45
- synchronizationInitialized = false;
46
- storeRegistry.set({});
341
+ function withMapper(map) {
342
+ return createDevtoolsFeature({ map: map });
47
343
  }
344
+
48
345
  /**
49
- * @param name store's name as it should appear in the DevTools
346
+ * Internal Service used by {@link withGlitchTracking}. It does not rely
347
+ * on `effect` as {@link DefaultTracker} does but uses the NgRx function
348
+ * `watchState` to track all state changes.
50
349
  */
51
- function withDevtools(name) {
52
- return (store) => {
53
- const isServer = isPlatformServer(inject(PLATFORM_ID));
54
- if (isServer) {
55
- return store;
56
- }
57
- const extensions = window.__REDUX_DEVTOOLS_EXTENSION__;
58
- if (!extensions) {
59
- return store;
60
- }
61
- if (!connection) {
62
- connection = extensions.connect({
63
- name: 'NgRx Signal Store',
64
- });
65
- }
66
- const storeSignal = getStoreSignal(store);
67
- storeRegistry.update((value) => ({
68
- ...value,
69
- [name]: storeSignal,
70
- }));
71
- if (!synchronizationInitialized) {
72
- initSynchronization();
73
- synchronizationInitialized = true;
350
+ class GlitchTrackerService {
351
+ #stores = {};
352
+ #callback;
353
+ get stores() {
354
+ return Object.entries(this.#stores).reduce((acc, [id, { store }]) => {
355
+ acc[id] = store;
356
+ return acc;
357
+ }, {});
358
+ }
359
+ onChange(callback) {
360
+ this.#callback = callback;
361
+ }
362
+ removeStore(id) {
363
+ this.#stores = Object.entries(this.#stores).reduce((newStore, [storeId, value]) => {
364
+ if (storeId !== id) {
365
+ newStore[storeId] = value;
366
+ }
367
+ else {
368
+ value.destroyWatcher();
369
+ }
370
+ return newStore;
371
+ }, {});
372
+ throwIfNull(this.#callback)({});
373
+ }
374
+ track(id, store) {
375
+ const watcher = watchState(store, (state) => {
376
+ throwIfNull(this.#callback)({ [id]: state });
377
+ });
378
+ this.#stores[id] = { destroyWatcher: watcher.destroy, store };
379
+ }
380
+ notifyRenamedStore(id) {
381
+ if (Object.keys(this.#stores).includes(id) && this.#callback) {
382
+ this.#callback({ [id]: getState(this.#stores[id].store) });
74
383
  }
75
- return store;
76
- };
384
+ }
385
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GlitchTrackerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
386
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GlitchTrackerService, providedIn: 'root' }); }
77
387
  }
388
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GlitchTrackerService, decorators: [{
389
+ type: Injectable,
390
+ args: [{ providedIn: 'root' }]
391
+ }] });
392
+
393
+ /**
394
+ * It tracks all state changes of the State, including intermediary updates
395
+ * that are typically suppressed by Angular's glitch-free mechanism.
396
+ *
397
+ * This feature is especially useful for debugging.
398
+ *
399
+ * Example:
400
+ *
401
+ * ```typescript
402
+ * const Store = signalStore(
403
+ * { providedIn: 'root' },
404
+ * withState({ count: 0 }),
405
+ * withDevtools('counter', withGlitchTracking()),
406
+ * withMethods((store) => ({
407
+ * increase: () =>
408
+ * patchState(store, (value) => ({ count: value.count + 1 })),
409
+ * }))
410
+ * );
411
+ *
412
+ * // would show up in the DevTools with value 0
413
+ * const store = inject(Store);
414
+ *
415
+ * store.increase(); // would show up in the DevTools with value 1
416
+ * store.increase(); // would show up in the DevTools with value 2
417
+ * store.increase(); // would show up in the DevTools with value 3
418
+ * ```
419
+ *
420
+ * Without `withGlitchTracking`, the DevTools would only show the final value of 3.
421
+ */
422
+ function withGlitchTracking() {
423
+ return createDevtoolsFeature({ tracker: GlitchTrackerService });
424
+ }
425
+
78
426
  /**
79
427
  * @deprecated Has been renamed to `updateState`
80
428
  */
@@ -93,6 +441,19 @@ function updateState(stateSource, action, ...updaters) {
93
441
  return patchState$1(stateSource, ...updaters);
94
442
  }
95
443
 
444
+ /**
445
+ * Renames the name of a store how it appears in the Devtools.
446
+ * @param store instance of the SignalStore
447
+ * @param newName new name for the Devtools
448
+ */
449
+ function renameDevtoolsName(store, newName) {
450
+ const renameMethod = store[renameDevtoolsMethodName];
451
+ if (!renameMethod) {
452
+ throw new Error("Devtools extensions haven't been added to this store.");
453
+ }
454
+ renameMethod(newName);
455
+ }
456
+
96
457
  function assertActionFnSpecs(obj) {
97
458
  if (!obj || typeof obj !== 'object') {
98
459
  throw new Error('%o is not an Action Specification');
@@ -325,7 +686,6 @@ function getDataServiceKeys(options) {
325
686
  deleteKey,
326
687
  };
327
688
  }
328
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
689
  function withDataService(options) {
330
690
  const { dataServiceType, filter, collection: prefix } = options;
331
691
  const { entitiesKey, filterKey, loadKey, selectedEntitiesKey, selectedIdsKey, updateFilterKey, updateSelectedKey, currentKey, createKey, updateKey, updateAllKey, deleteKey, loadByIdKey, setCurrentKey, } = getDataServiceKeys(options);
@@ -356,28 +716,30 @@ function withDataService(options) {
356
716
  },
357
717
  [loadKey]: async () => {
358
718
  const filter = store[filterKey];
359
- store[callStateKey] && patchState$1(store, setLoading(prefix));
719
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
360
720
  try {
361
721
  const result = await dataService.load(filter());
362
722
  patchState$1(store, prefix
363
723
  ? setAllEntities(result, { collection: prefix })
364
724
  : setAllEntities(result));
365
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
725
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
366
726
  }
367
727
  catch (e) {
368
- store[callStateKey] && patchState$1(store, setError(e, prefix));
728
+ (() => store[callStateKey] &&
729
+ patchState$1(store, setError(e, prefix)))();
369
730
  throw e;
370
731
  }
371
732
  },
372
733
  [loadByIdKey]: async (id) => {
373
- store[callStateKey] && patchState$1(store, setLoading(prefix));
734
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
374
735
  try {
375
736
  const current = await dataService.loadById(id);
376
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
737
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
377
738
  patchState$1(store, { [currentKey]: current });
378
739
  }
379
740
  catch (e) {
380
- store[callStateKey] && patchState$1(store, setError(e, prefix));
741
+ (() => store[callStateKey] &&
742
+ patchState$1(store, setError(e, prefix)))();
381
743
  throw e;
382
744
  }
383
745
  },
@@ -386,23 +748,24 @@ function withDataService(options) {
386
748
  },
387
749
  [createKey]: async (entity) => {
388
750
  patchState$1(store, { [currentKey]: entity });
389
- store[callStateKey] && patchState$1(store, setLoading(prefix));
751
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
390
752
  try {
391
753
  const created = await dataService.create(entity);
392
754
  patchState$1(store, { [currentKey]: created });
393
755
  patchState$1(store, prefix
394
756
  ? addEntity(created, { collection: prefix })
395
757
  : addEntity(created));
396
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
758
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
397
759
  }
398
760
  catch (e) {
399
- store[callStateKey] && patchState$1(store, setError(e, prefix));
761
+ (() => store[callStateKey] &&
762
+ patchState$1(store, setError(e, prefix)))();
400
763
  throw e;
401
764
  }
402
765
  },
403
766
  [updateKey]: async (entity) => {
404
767
  patchState$1(store, { [currentKey]: entity });
405
- store[callStateKey] && patchState$1(store, setLoading(prefix));
768
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
406
769
  try {
407
770
  const updated = await dataService.update(entity);
408
771
  patchState$1(store, { [currentKey]: updated });
@@ -412,40 +775,43 @@ function withDataService(options) {
412
775
  };
413
776
  const updater = (collection) => updateEntity(updateArg, { collection });
414
777
  patchState$1(store, prefix ? updater(prefix) : updateEntity(updateArg));
415
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
778
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
416
779
  }
417
780
  catch (e) {
418
- store[callStateKey] && patchState$1(store, setError(e, prefix));
781
+ (() => store[callStateKey] &&
782
+ patchState$1(store, setError(e, prefix)))();
419
783
  throw e;
420
784
  }
421
785
  },
422
786
  [updateAllKey]: async (entities) => {
423
- store[callStateKey] && patchState$1(store, setLoading(prefix));
787
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
424
788
  try {
425
789
  const result = await dataService.updateAll(entities);
426
790
  patchState$1(store, prefix
427
791
  ? setAllEntities(result, { collection: prefix })
428
792
  : setAllEntities(result));
429
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
793
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
430
794
  }
431
795
  catch (e) {
432
- store[callStateKey] && patchState$1(store, setError(e, prefix));
796
+ (() => store[callStateKey] &&
797
+ patchState$1(store, setError(e, prefix)))();
433
798
  throw e;
434
799
  }
435
800
  },
436
801
  [deleteKey]: async (entity) => {
437
802
  patchState$1(store, { [currentKey]: entity });
438
- store[callStateKey] && patchState$1(store, setLoading(prefix));
803
+ (() => store[callStateKey] && patchState$1(store, setLoading(prefix)))();
439
804
  try {
440
805
  await dataService.delete(entity);
441
806
  patchState$1(store, { [currentKey]: undefined });
442
807
  patchState$1(store, prefix
443
808
  ? removeEntity(entity.id, { collection: prefix })
444
809
  : removeEntity(entity.id));
445
- store[callStateKey] && patchState$1(store, setLoaded(prefix));
810
+ (() => store[callStateKey] && patchState$1(store, setLoaded(prefix)))();
446
811
  }
447
812
  catch (e) {
448
- store[callStateKey] && patchState$1(store, setError(e, prefix));
813
+ (() => store[callStateKey] &&
814
+ patchState$1(store, setError(e, prefix)))();
449
815
  throw e;
450
816
  }
451
817
  },
@@ -517,6 +883,11 @@ function withUndoRedo(options) {
517
883
  }
518
884
  updateInternal();
519
885
  },
886
+ clearStack() {
887
+ undoStack.splice(0);
888
+ redoStack.splice(0);
889
+ updateInternal();
890
+ },
520
891
  })), withHooks({
521
892
  onInit(store) {
522
893
  effect(() => {
@@ -563,7 +934,7 @@ function withUndoRedo(options) {
563
934
  }));
564
935
  }
565
936
 
566
- const NOOP = () => { };
937
+ const NOOP = () => void true;
567
938
  const StorageSyncStub = {
568
939
  clearStorage: NOOP,
569
940
  readFromStorage: NOOP,
@@ -822,9 +1193,47 @@ function createPageArray(currentPage, itemsPerPage, totalItems, paginationRange)
822
1193
  return pages;
823
1194
  }
824
1195
 
1196
+ /**
1197
+ * Adds a `resetState` method to the store, which resets the state
1198
+ * to the initial state.
1199
+ *
1200
+ * If you want to set a custom initial state, you can use {@link setResetState}.
1201
+ */
1202
+ function withReset() {
1203
+ return signalStoreFeature(withProps(() => ({ _resetState: { value: {} } })), withMethods((store) => {
1204
+ // workaround to TS excessive property check
1205
+ const methods = {
1206
+ resetState() {
1207
+ patchState$1(store, store._resetState.value);
1208
+ },
1209
+ __setResetState__(state) {
1210
+ store._resetState.value = state;
1211
+ },
1212
+ };
1213
+ return methods;
1214
+ }), withHooks((store) => ({
1215
+ onInit() {
1216
+ store._resetState.value = getState(store);
1217
+ },
1218
+ })));
1219
+ }
1220
+ /**
1221
+ * Sets the reset state of the store to the given state.
1222
+ *
1223
+ * Throws an error if the store is not configured with {@link withReset}.
1224
+ * @param store the instance of a SignalStore
1225
+ * @param state the state to set as the reset state
1226
+ */
1227
+ function setResetState(store, state) {
1228
+ if (!('__setResetState__' in store)) {
1229
+ throw new Error('Cannot set reset state, since store is not configured with withReset()');
1230
+ }
1231
+ store.__setResetState__(state);
1232
+ }
1233
+
825
1234
  /**
826
1235
  * Generated bundle index. Do not edit.
827
1236
  */
828
1237
 
829
- export { capitalize, createPageArray, firstPage, getCallStateKeys, getDataServiceKeys, getUndoRedoKeys, gotoPage, nextPage, noPayload, patchState, payload, previousPage, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, updateState, withCallState, withDataService, withDevtools, withPagination, withRedux, withStorageSync, withUndoRedo };
1238
+ export { capitalize, createPageArray, firstPage, getCallStateKeys, getDataServiceKeys, getUndoRedoKeys, gotoPage, nextPage, noPayload, patchState, payload, previousPage, renameDevtoolsName, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, updateState, withCallState, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withGlitchTracking, withMapper, withPagination, withRedux, withReset, withStorageSync, withUndoRedo };
830
1239
  //# sourceMappingURL=angular-architects-ngrx-toolkit.mjs.map