@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.
- package/README.md +4 -12
- package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +15 -15
- package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +1 -1
- package/fesm2022/angular-architects-ngrx-toolkit.mjs +487 -78
- package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -1
- package/index.d.ts +9 -2
- package/lib/devtools/features/with-disabled-name-indicies.d.ts +27 -0
- package/lib/devtools/features/with-glitch-tracking.d.ts +30 -0
- package/lib/devtools/features/with-mapper.d.ts +28 -0
- package/lib/devtools/internal/current-action-names.d.ts +1 -0
- package/lib/devtools/internal/default-tracker.d.ts +13 -0
- package/lib/devtools/internal/devtools-feature.d.ts +24 -0
- package/lib/devtools/internal/devtools-syncer.service.d.ts +35 -0
- package/lib/devtools/internal/glitch-tracker.service.d.ts +18 -0
- package/lib/devtools/internal/models.d.ts +25 -0
- package/lib/devtools/rename-devtools-name.d.ts +7 -0
- package/lib/devtools/update-state.d.ts +17 -0
- package/lib/devtools/with-dev-tools-stub.d.ts +5 -0
- package/lib/devtools/with-devtools.d.ts +30 -0
- package/lib/shared/prettify.d.ts +1 -1
- package/lib/shared/throw-if-null.d.ts +1 -0
- package/lib/with-call-state.d.ts +2 -2
- package/lib/with-data-service.d.ts +3 -3
- package/lib/with-pagination.d.ts +4 -4
- package/lib/with-reset.d.ts +29 -0
- package/lib/with-storage-sync.d.ts +2 -2
- package/lib/with-undo-redo.d.ts +4 -3
- package/package.json +6 -7
- package/redux-connector/src/lib/create-redux.d.ts +4 -4
- package/redux-connector/src/lib/model.d.ts +5 -0
- package/redux-connector/src/lib/rxjs-interop/redux-method.d.ts +5 -2
- package/redux-connector/src/lib/signal-redux-store.d.ts +10 -2
- package/redux-connector/src/lib/util.d.ts +2 -2
- package/esm2022/angular-architects-ngrx-toolkit.mjs +0 -5
- package/esm2022/index.mjs +0 -8
- package/esm2022/lib/assertions/assertions.mjs +0 -6
- package/esm2022/lib/shared/prettify.mjs +0 -2
- package/esm2022/lib/shared/signal-store-models.mjs +0 -2
- package/esm2022/lib/with-call-state.mjs +0 -60
- package/esm2022/lib/with-data-service.mjs +0 -202
- package/esm2022/lib/with-devtools.mjs +0 -92
- package/esm2022/lib/with-pagination.mjs +0 -209
- package/esm2022/lib/with-redux.mjs +0 -100
- package/esm2022/lib/with-storage-sync.mjs +0 -56
- package/esm2022/lib/with-undo-redo.mjs +0 -113
- package/esm2022/redux-connector/angular-architects-ngrx-toolkit-redux-connector.mjs +0 -5
- package/esm2022/redux-connector/index.mjs +0 -3
- package/esm2022/redux-connector/src/lib/create-redux.mjs +0 -41
- package/esm2022/redux-connector/src/lib/model.mjs +0 -2
- package/esm2022/redux-connector/src/lib/rxjs-interop/redux-method.mjs +0 -22
- package/esm2022/redux-connector/src/lib/signal-redux-store.mjs +0 -43
- package/esm2022/redux-connector/src/lib/util.mjs +0 -13
- package/lib/with-devtools.d.ts +0 -38
|
@@ -1,80 +1,428 @@
|
|
|
1
|
-
import { patchState as patchState$1,
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
24
|
-
connection.send({ type },
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
313
|
+
|
|
40
314
|
/**
|
|
41
|
-
*
|
|
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
|
|
44
|
-
|
|
45
|
-
synchronizationInitialized = false;
|
|
46
|
-
storeRegistry.set({});
|
|
341
|
+
function withMapper(map) {
|
|
342
|
+
return createDevtoolsFeature({ map: map });
|
|
47
343
|
}
|
|
344
|
+
|
|
48
345
|
/**
|
|
49
|
-
*
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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] &&
|
|
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] &&
|
|
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] &&
|
|
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] &&
|
|
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] &&
|
|
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] &&
|
|
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
|