@ngrx/store-devtools 14.2.0 → 14.3.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/esm2020/src/index.mjs +2 -1
- package/esm2020/src/instrument.mjs +4 -53
- package/esm2020/src/provide-store-devtools.mjs +58 -0
- package/fesm2015/ngrx-store-devtools.mjs +257 -251
- package/fesm2015/ngrx-store-devtools.mjs.map +1 -1
- package/fesm2020/ngrx-store-devtools.mjs +259 -253
- package/fesm2020/ngrx-store-devtools.mjs.map +1 -1
- package/package.json +2 -2
- package/schematics-core/utility/libs-version.js +1 -1
- package/schematics-core/utility/libs-version.js.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/instrument.d.ts +2 -6
- package/src/provide-store-devtools.d.ts +8 -0
|
@@ -1,70 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, Injectable, Inject, NgModule } from '@angular/core';
|
|
3
3
|
import * as i2 from '@ngrx/store';
|
|
4
|
-
import {
|
|
4
|
+
import { ActionsSubject, UPDATE, INIT, INITIAL_STATE, StateObservable, ReducerManagerDispatcher } from '@ngrx/store';
|
|
5
5
|
import { EMPTY, Observable, of, merge, queueScheduler, ReplaySubject } from 'rxjs';
|
|
6
6
|
import { share, filter, map, concatMap, timeout, debounceTime, catchError, take, takeUntil, switchMap, skip, observeOn, withLatestFrom, scan } from 'rxjs/operators';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Chrome extension documentation
|
|
10
|
-
* @see https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md
|
|
11
|
-
* Firefox extension documentation
|
|
12
|
-
* @see https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md
|
|
13
|
-
*/
|
|
14
|
-
class StoreDevtoolsConfig {
|
|
15
|
-
constructor() {
|
|
16
|
-
/**
|
|
17
|
-
* Maximum allowed actions to be stored in the history tree (default: `false`)
|
|
18
|
-
*/
|
|
19
|
-
this.maxAge = false;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const STORE_DEVTOOLS_CONFIG = new InjectionToken('@ngrx/store-devtools Options');
|
|
23
|
-
/**
|
|
24
|
-
* Used to provide a `StoreDevtoolsConfig` for the store-devtools.
|
|
25
|
-
*/
|
|
26
|
-
const INITIAL_OPTIONS = new InjectionToken('@ngrx/store-devtools Initial Config');
|
|
27
|
-
function noMonitor() {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
const DEFAULT_NAME = 'NgRx Store DevTools';
|
|
31
|
-
function createConfig(optionsInput) {
|
|
32
|
-
const DEFAULT_OPTIONS = {
|
|
33
|
-
maxAge: false,
|
|
34
|
-
monitor: noMonitor,
|
|
35
|
-
actionSanitizer: undefined,
|
|
36
|
-
stateSanitizer: undefined,
|
|
37
|
-
name: DEFAULT_NAME,
|
|
38
|
-
serialize: false,
|
|
39
|
-
logOnly: false,
|
|
40
|
-
autoPause: false,
|
|
41
|
-
// Add all features explicitly. This prevent buggy behavior for
|
|
42
|
-
// options like "lock" which might otherwise not show up.
|
|
43
|
-
features: {
|
|
44
|
-
pause: true,
|
|
45
|
-
lock: true,
|
|
46
|
-
persist: true,
|
|
47
|
-
export: true,
|
|
48
|
-
import: 'custom',
|
|
49
|
-
jump: true,
|
|
50
|
-
skip: true,
|
|
51
|
-
reorder: true,
|
|
52
|
-
dispatch: true,
|
|
53
|
-
test: true, // Generate tests for the selected actions
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
const options = typeof optionsInput === 'function' ? optionsInput() : optionsInput;
|
|
57
|
-
const logOnly = options.logOnly
|
|
58
|
-
? { pause: true, export: true, test: true }
|
|
59
|
-
: false;
|
|
60
|
-
const features = options.features || logOnly || DEFAULT_OPTIONS.features;
|
|
61
|
-
const config = Object.assign({}, DEFAULT_OPTIONS, { features }, options);
|
|
62
|
-
if (config.maxAge && config.maxAge < 2) {
|
|
63
|
-
throw new Error(`Devtools 'maxAge' cannot be less than 2, got ${config.maxAge}`);
|
|
64
|
-
}
|
|
65
|
-
return config;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
8
|
const PERFORM_ACTION = 'PERFORM_ACTION';
|
|
69
9
|
const REFRESH = 'REFRESH';
|
|
70
10
|
const RESET = 'RESET';
|
|
@@ -162,6 +102,66 @@ class PauseRecording {
|
|
|
162
102
|
}
|
|
163
103
|
}
|
|
164
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Chrome extension documentation
|
|
107
|
+
* @see https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md
|
|
108
|
+
* Firefox extension documentation
|
|
109
|
+
* @see https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md
|
|
110
|
+
*/
|
|
111
|
+
class StoreDevtoolsConfig {
|
|
112
|
+
constructor() {
|
|
113
|
+
/**
|
|
114
|
+
* Maximum allowed actions to be stored in the history tree (default: `false`)
|
|
115
|
+
*/
|
|
116
|
+
this.maxAge = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const STORE_DEVTOOLS_CONFIG = new InjectionToken('@ngrx/store-devtools Options');
|
|
120
|
+
/**
|
|
121
|
+
* Used to provide a `StoreDevtoolsConfig` for the store-devtools.
|
|
122
|
+
*/
|
|
123
|
+
const INITIAL_OPTIONS = new InjectionToken('@ngrx/store-devtools Initial Config');
|
|
124
|
+
function noMonitor() {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const DEFAULT_NAME = 'NgRx Store DevTools';
|
|
128
|
+
function createConfig(optionsInput) {
|
|
129
|
+
const DEFAULT_OPTIONS = {
|
|
130
|
+
maxAge: false,
|
|
131
|
+
monitor: noMonitor,
|
|
132
|
+
actionSanitizer: undefined,
|
|
133
|
+
stateSanitizer: undefined,
|
|
134
|
+
name: DEFAULT_NAME,
|
|
135
|
+
serialize: false,
|
|
136
|
+
logOnly: false,
|
|
137
|
+
autoPause: false,
|
|
138
|
+
// Add all features explicitly. This prevent buggy behavior for
|
|
139
|
+
// options like "lock" which might otherwise not show up.
|
|
140
|
+
features: {
|
|
141
|
+
pause: true,
|
|
142
|
+
lock: true,
|
|
143
|
+
persist: true,
|
|
144
|
+
export: true,
|
|
145
|
+
import: 'custom',
|
|
146
|
+
jump: true,
|
|
147
|
+
skip: true,
|
|
148
|
+
reorder: true,
|
|
149
|
+
dispatch: true,
|
|
150
|
+
test: true, // Generate tests for the selected actions
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
const options = typeof optionsInput === 'function' ? optionsInput() : optionsInput;
|
|
154
|
+
const logOnly = options.logOnly
|
|
155
|
+
? { pause: true, export: true, test: true }
|
|
156
|
+
: false;
|
|
157
|
+
const features = options.features || logOnly || DEFAULT_OPTIONS.features;
|
|
158
|
+
const config = Object.assign({}, DEFAULT_OPTIONS, { features }, options);
|
|
159
|
+
if (config.maxAge && config.maxAge < 2) {
|
|
160
|
+
throw new Error(`Devtools 'maxAge' cannot be less than 2, got ${config.maxAge}`);
|
|
161
|
+
}
|
|
162
|
+
return config;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
165
|
function difference(first, second) {
|
|
166
166
|
return first.filter((item) => second.indexOf(item) < 0);
|
|
167
167
|
}
|
|
@@ -275,6 +275,165 @@ function escapeRegExp(s) {
|
|
|
275
275
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
class DevtoolsDispatcher extends ActionsSubject {
|
|
279
|
+
}
|
|
280
|
+
/** @nocollapse */ DevtoolsDispatcher.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
281
|
+
/** @nocollapse */ DevtoolsDispatcher.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher });
|
|
282
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, decorators: [{
|
|
283
|
+
type: Injectable
|
|
284
|
+
}] });
|
|
285
|
+
|
|
286
|
+
const ExtensionActionTypes = {
|
|
287
|
+
START: 'START',
|
|
288
|
+
DISPATCH: 'DISPATCH',
|
|
289
|
+
STOP: 'STOP',
|
|
290
|
+
ACTION: 'ACTION',
|
|
291
|
+
};
|
|
292
|
+
const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
|
|
293
|
+
class DevtoolsExtension {
|
|
294
|
+
constructor(devtoolsExtension, config, dispatcher) {
|
|
295
|
+
this.config = config;
|
|
296
|
+
this.dispatcher = dispatcher;
|
|
297
|
+
this.devtoolsExtension = devtoolsExtension;
|
|
298
|
+
this.createActionStreams();
|
|
299
|
+
}
|
|
300
|
+
notify(action, state) {
|
|
301
|
+
if (!this.devtoolsExtension) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
// Check to see if the action requires a full update of the liftedState.
|
|
305
|
+
// If it is a simple action generated by the user's app and the recording
|
|
306
|
+
// is not locked/paused, only send the action and the current state (fast).
|
|
307
|
+
//
|
|
308
|
+
// A full liftedState update (slow: serializes the entire liftedState) is
|
|
309
|
+
// only required when:
|
|
310
|
+
// a) redux-devtools-extension fires the @@Init action (ignored by
|
|
311
|
+
// @ngrx/store-devtools)
|
|
312
|
+
// b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
|
|
313
|
+
// or @ngrx/store/update-reducers)
|
|
314
|
+
// c) the state has been recomputed due to time-traveling
|
|
315
|
+
// d) any action that is not a PerformAction to err on the side of
|
|
316
|
+
// caution.
|
|
317
|
+
if (action.type === PERFORM_ACTION) {
|
|
318
|
+
if (state.isLocked || state.isPaused) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const currentState = unliftState(state);
|
|
322
|
+
if (shouldFilterActions(this.config) &&
|
|
323
|
+
isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const sanitizedState = this.config.stateSanitizer
|
|
327
|
+
? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
|
|
328
|
+
: currentState;
|
|
329
|
+
const sanitizedAction = this.config.actionSanitizer
|
|
330
|
+
? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
|
|
331
|
+
: action;
|
|
332
|
+
this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// Requires full state update
|
|
336
|
+
const sanitizedLiftedState = {
|
|
337
|
+
...state,
|
|
338
|
+
stagedActionIds: state.stagedActionIds,
|
|
339
|
+
actionsById: this.config.actionSanitizer
|
|
340
|
+
? sanitizeActions(this.config.actionSanitizer, state.actionsById)
|
|
341
|
+
: state.actionsById,
|
|
342
|
+
computedStates: this.config.stateSanitizer
|
|
343
|
+
? sanitizeStates(this.config.stateSanitizer, state.computedStates)
|
|
344
|
+
: state.computedStates,
|
|
345
|
+
};
|
|
346
|
+
this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
createChangesObservable() {
|
|
350
|
+
if (!this.devtoolsExtension) {
|
|
351
|
+
return EMPTY;
|
|
352
|
+
}
|
|
353
|
+
return new Observable((subscriber) => {
|
|
354
|
+
const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
|
|
355
|
+
this.extensionConnection = connection;
|
|
356
|
+
connection.init();
|
|
357
|
+
connection.subscribe((change) => subscriber.next(change));
|
|
358
|
+
return connection.unsubscribe;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
createActionStreams() {
|
|
362
|
+
// Listens to all changes
|
|
363
|
+
const changes$ = this.createChangesObservable().pipe(share());
|
|
364
|
+
// Listen for the start action
|
|
365
|
+
const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
|
|
366
|
+
// Listen for the stop action
|
|
367
|
+
const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
|
|
368
|
+
// Listen for lifted actions
|
|
369
|
+
const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
|
|
370
|
+
if (action.type === IMPORT_STATE) {
|
|
371
|
+
// State imports may happen in two situations:
|
|
372
|
+
// 1. Explicitly by user
|
|
373
|
+
// 2. User activated the "persist state accross reloads" option
|
|
374
|
+
// and now the state is imported during reload.
|
|
375
|
+
// Because of option 2, we need to give possible
|
|
376
|
+
// lazy loaded reducers time to instantiate.
|
|
377
|
+
// As soon as there is no UPDATE action within 1 second,
|
|
378
|
+
// it is assumed that all reducers are loaded.
|
|
379
|
+
return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
return of(action);
|
|
383
|
+
}
|
|
384
|
+
}));
|
|
385
|
+
// Listen for unlifted actions
|
|
386
|
+
const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
|
|
387
|
+
const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
|
|
388
|
+
const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
|
|
389
|
+
this.start$ = start$.pipe(takeUntil(stop$));
|
|
390
|
+
// Only take the action sources between the start/stop events
|
|
391
|
+
this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
|
|
392
|
+
this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
|
|
393
|
+
}
|
|
394
|
+
unwrapAction(action) {
|
|
395
|
+
return typeof action === 'string' ? eval(`(${action})`) : action;
|
|
396
|
+
}
|
|
397
|
+
getExtensionConfig(config) {
|
|
398
|
+
const extensionOptions = {
|
|
399
|
+
name: config.name,
|
|
400
|
+
features: config.features,
|
|
401
|
+
serialize: config.serialize,
|
|
402
|
+
autoPause: config.autoPause ?? false,
|
|
403
|
+
// The action/state sanitizers are not added to the config
|
|
404
|
+
// because sanitation is done in this class already.
|
|
405
|
+
// It is done before sending it to the devtools extension for consistency:
|
|
406
|
+
// - If we call extensionConnection.send(...),
|
|
407
|
+
// the extension would call the sanitizers.
|
|
408
|
+
// - If we call devtoolsExtension.send(...) (aka full state update),
|
|
409
|
+
// the extension would NOT call the sanitizers, so we have to do it ourselves.
|
|
410
|
+
};
|
|
411
|
+
if (config.maxAge !== false /* support === 0 */) {
|
|
412
|
+
extensionOptions.maxAge = config.maxAge;
|
|
413
|
+
}
|
|
414
|
+
return extensionOptions;
|
|
415
|
+
}
|
|
416
|
+
sendToReduxDevtools(send) {
|
|
417
|
+
try {
|
|
418
|
+
send();
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/** @nocollapse */ DevtoolsExtension.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, deps: [{ token: REDUX_DEVTOOLS_EXTENSION }, { token: STORE_DEVTOOLS_CONFIG }, { token: DevtoolsDispatcher }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
426
|
+
/** @nocollapse */ DevtoolsExtension.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension });
|
|
427
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, decorators: [{
|
|
428
|
+
type: Injectable
|
|
429
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
430
|
+
type: Inject,
|
|
431
|
+
args: [REDUX_DEVTOOLS_EXTENSION]
|
|
432
|
+
}] }, { type: StoreDevtoolsConfig, decorators: [{
|
|
433
|
+
type: Inject,
|
|
434
|
+
args: [STORE_DEVTOOLS_CONFIG]
|
|
435
|
+
}] }, { type: DevtoolsDispatcher }]; } });
|
|
436
|
+
|
|
278
437
|
const INIT_ACTION = { type: INIT };
|
|
279
438
|
const RECOMPUTE = '@ngrx/store-devtools/recompute';
|
|
280
439
|
const RECOMPUTE_ACTION = { type: RECOMPUTE };
|
|
@@ -639,165 +798,6 @@ function liftReducerWith(initialCommittedState, initialLiftedState, errorHandler
|
|
|
639
798
|
};
|
|
640
799
|
}
|
|
641
800
|
|
|
642
|
-
class DevtoolsDispatcher extends ActionsSubject {
|
|
643
|
-
}
|
|
644
|
-
/** @nocollapse */ DevtoolsDispatcher.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
645
|
-
/** @nocollapse */ DevtoolsDispatcher.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher });
|
|
646
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, decorators: [{
|
|
647
|
-
type: Injectable
|
|
648
|
-
}] });
|
|
649
|
-
|
|
650
|
-
const ExtensionActionTypes = {
|
|
651
|
-
START: 'START',
|
|
652
|
-
DISPATCH: 'DISPATCH',
|
|
653
|
-
STOP: 'STOP',
|
|
654
|
-
ACTION: 'ACTION',
|
|
655
|
-
};
|
|
656
|
-
const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
|
|
657
|
-
class DevtoolsExtension {
|
|
658
|
-
constructor(devtoolsExtension, config, dispatcher) {
|
|
659
|
-
this.config = config;
|
|
660
|
-
this.dispatcher = dispatcher;
|
|
661
|
-
this.devtoolsExtension = devtoolsExtension;
|
|
662
|
-
this.createActionStreams();
|
|
663
|
-
}
|
|
664
|
-
notify(action, state) {
|
|
665
|
-
if (!this.devtoolsExtension) {
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
// Check to see if the action requires a full update of the liftedState.
|
|
669
|
-
// If it is a simple action generated by the user's app and the recording
|
|
670
|
-
// is not locked/paused, only send the action and the current state (fast).
|
|
671
|
-
//
|
|
672
|
-
// A full liftedState update (slow: serializes the entire liftedState) is
|
|
673
|
-
// only required when:
|
|
674
|
-
// a) redux-devtools-extension fires the @@Init action (ignored by
|
|
675
|
-
// @ngrx/store-devtools)
|
|
676
|
-
// b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
|
|
677
|
-
// or @ngrx/store/update-reducers)
|
|
678
|
-
// c) the state has been recomputed due to time-traveling
|
|
679
|
-
// d) any action that is not a PerformAction to err on the side of
|
|
680
|
-
// caution.
|
|
681
|
-
if (action.type === PERFORM_ACTION) {
|
|
682
|
-
if (state.isLocked || state.isPaused) {
|
|
683
|
-
return;
|
|
684
|
-
}
|
|
685
|
-
const currentState = unliftState(state);
|
|
686
|
-
if (shouldFilterActions(this.config) &&
|
|
687
|
-
isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
const sanitizedState = this.config.stateSanitizer
|
|
691
|
-
? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
|
|
692
|
-
: currentState;
|
|
693
|
-
const sanitizedAction = this.config.actionSanitizer
|
|
694
|
-
? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
|
|
695
|
-
: action;
|
|
696
|
-
this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
|
|
697
|
-
}
|
|
698
|
-
else {
|
|
699
|
-
// Requires full state update
|
|
700
|
-
const sanitizedLiftedState = {
|
|
701
|
-
...state,
|
|
702
|
-
stagedActionIds: state.stagedActionIds,
|
|
703
|
-
actionsById: this.config.actionSanitizer
|
|
704
|
-
? sanitizeActions(this.config.actionSanitizer, state.actionsById)
|
|
705
|
-
: state.actionsById,
|
|
706
|
-
computedStates: this.config.stateSanitizer
|
|
707
|
-
? sanitizeStates(this.config.stateSanitizer, state.computedStates)
|
|
708
|
-
: state.computedStates,
|
|
709
|
-
};
|
|
710
|
-
this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
createChangesObservable() {
|
|
714
|
-
if (!this.devtoolsExtension) {
|
|
715
|
-
return EMPTY;
|
|
716
|
-
}
|
|
717
|
-
return new Observable((subscriber) => {
|
|
718
|
-
const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
|
|
719
|
-
this.extensionConnection = connection;
|
|
720
|
-
connection.init();
|
|
721
|
-
connection.subscribe((change) => subscriber.next(change));
|
|
722
|
-
return connection.unsubscribe;
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
createActionStreams() {
|
|
726
|
-
// Listens to all changes
|
|
727
|
-
const changes$ = this.createChangesObservable().pipe(share());
|
|
728
|
-
// Listen for the start action
|
|
729
|
-
const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
|
|
730
|
-
// Listen for the stop action
|
|
731
|
-
const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
|
|
732
|
-
// Listen for lifted actions
|
|
733
|
-
const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
|
|
734
|
-
if (action.type === IMPORT_STATE) {
|
|
735
|
-
// State imports may happen in two situations:
|
|
736
|
-
// 1. Explicitly by user
|
|
737
|
-
// 2. User activated the "persist state accross reloads" option
|
|
738
|
-
// and now the state is imported during reload.
|
|
739
|
-
// Because of option 2, we need to give possible
|
|
740
|
-
// lazy loaded reducers time to instantiate.
|
|
741
|
-
// As soon as there is no UPDATE action within 1 second,
|
|
742
|
-
// it is assumed that all reducers are loaded.
|
|
743
|
-
return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
return of(action);
|
|
747
|
-
}
|
|
748
|
-
}));
|
|
749
|
-
// Listen for unlifted actions
|
|
750
|
-
const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
|
|
751
|
-
const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
|
|
752
|
-
const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
|
|
753
|
-
this.start$ = start$.pipe(takeUntil(stop$));
|
|
754
|
-
// Only take the action sources between the start/stop events
|
|
755
|
-
this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
|
|
756
|
-
this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
|
|
757
|
-
}
|
|
758
|
-
unwrapAction(action) {
|
|
759
|
-
return typeof action === 'string' ? eval(`(${action})`) : action;
|
|
760
|
-
}
|
|
761
|
-
getExtensionConfig(config) {
|
|
762
|
-
const extensionOptions = {
|
|
763
|
-
name: config.name,
|
|
764
|
-
features: config.features,
|
|
765
|
-
serialize: config.serialize,
|
|
766
|
-
autoPause: config.autoPause ?? false,
|
|
767
|
-
// The action/state sanitizers are not added to the config
|
|
768
|
-
// because sanitation is done in this class already.
|
|
769
|
-
// It is done before sending it to the devtools extension for consistency:
|
|
770
|
-
// - If we call extensionConnection.send(...),
|
|
771
|
-
// the extension would call the sanitizers.
|
|
772
|
-
// - If we call devtoolsExtension.send(...) (aka full state update),
|
|
773
|
-
// the extension would NOT call the sanitizers, so we have to do it ourselves.
|
|
774
|
-
};
|
|
775
|
-
if (config.maxAge !== false /* support === 0 */) {
|
|
776
|
-
extensionOptions.maxAge = config.maxAge;
|
|
777
|
-
}
|
|
778
|
-
return extensionOptions;
|
|
779
|
-
}
|
|
780
|
-
sendToReduxDevtools(send) {
|
|
781
|
-
try {
|
|
782
|
-
send();
|
|
783
|
-
}
|
|
784
|
-
catch (err) {
|
|
785
|
-
console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
/** @nocollapse */ DevtoolsExtension.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, deps: [{ token: REDUX_DEVTOOLS_EXTENSION }, { token: STORE_DEVTOOLS_CONFIG }, { token: DevtoolsDispatcher }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
790
|
-
/** @nocollapse */ DevtoolsExtension.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension });
|
|
791
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, decorators: [{
|
|
792
|
-
type: Injectable
|
|
793
|
-
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
794
|
-
type: Inject,
|
|
795
|
-
args: [REDUX_DEVTOOLS_EXTENSION]
|
|
796
|
-
}] }, { type: StoreDevtoolsConfig, decorators: [{
|
|
797
|
-
type: Inject,
|
|
798
|
-
args: [STORE_DEVTOOLS_CONFIG]
|
|
799
|
-
}] }, { type: DevtoolsDispatcher }]; } });
|
|
800
|
-
|
|
801
801
|
class StoreDevtools {
|
|
802
802
|
constructor(dispatcher, actions$, reducers$, extension, scannedActions, errorHandler, initialState, config) {
|
|
803
803
|
const liftedInitialState = liftInitialState(initialState, config.monitor);
|
|
@@ -906,6 +906,43 @@ function createReduxDevtoolsExtension() {
|
|
|
906
906
|
return null;
|
|
907
907
|
}
|
|
908
908
|
}
|
|
909
|
+
function provideStoreDevtools(options = {}) {
|
|
910
|
+
return {
|
|
911
|
+
ɵproviders: [
|
|
912
|
+
DevtoolsExtension,
|
|
913
|
+
DevtoolsDispatcher,
|
|
914
|
+
StoreDevtools,
|
|
915
|
+
{
|
|
916
|
+
provide: INITIAL_OPTIONS,
|
|
917
|
+
useValue: options,
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
provide: IS_EXTENSION_OR_MONITOR_PRESENT,
|
|
921
|
+
deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
|
|
922
|
+
useFactory: createIsExtensionOrMonitorPresent,
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
provide: REDUX_DEVTOOLS_EXTENSION,
|
|
926
|
+
useFactory: createReduxDevtoolsExtension,
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
provide: STORE_DEVTOOLS_CONFIG,
|
|
930
|
+
deps: [INITIAL_OPTIONS],
|
|
931
|
+
useFactory: createConfig,
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
provide: StateObservable,
|
|
935
|
+
deps: [StoreDevtools],
|
|
936
|
+
useFactory: createStateObservable,
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
provide: ReducerManagerDispatcher,
|
|
940
|
+
useExisting: DevtoolsDispatcher,
|
|
941
|
+
},
|
|
942
|
+
],
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
909
946
|
function createStateObservable(devtools) {
|
|
910
947
|
return devtools.state;
|
|
911
948
|
}
|
|
@@ -913,38 +950,7 @@ class StoreDevtoolsModule {
|
|
|
913
950
|
static instrument(options = {}) {
|
|
914
951
|
return {
|
|
915
952
|
ngModule: StoreDevtoolsModule,
|
|
916
|
-
providers: [
|
|
917
|
-
DevtoolsExtension,
|
|
918
|
-
DevtoolsDispatcher,
|
|
919
|
-
StoreDevtools,
|
|
920
|
-
{
|
|
921
|
-
provide: INITIAL_OPTIONS,
|
|
922
|
-
useValue: options,
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
provide: IS_EXTENSION_OR_MONITOR_PRESENT,
|
|
926
|
-
deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
|
|
927
|
-
useFactory: createIsExtensionOrMonitorPresent,
|
|
928
|
-
},
|
|
929
|
-
{
|
|
930
|
-
provide: REDUX_DEVTOOLS_EXTENSION,
|
|
931
|
-
useFactory: createReduxDevtoolsExtension,
|
|
932
|
-
},
|
|
933
|
-
{
|
|
934
|
-
provide: STORE_DEVTOOLS_CONFIG,
|
|
935
|
-
deps: [INITIAL_OPTIONS],
|
|
936
|
-
useFactory: createConfig,
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
provide: StateObservable,
|
|
940
|
-
deps: [StoreDevtools],
|
|
941
|
-
useFactory: createStateObservable,
|
|
942
|
-
},
|
|
943
|
-
{
|
|
944
|
-
provide: ReducerManagerDispatcher,
|
|
945
|
-
useExisting: DevtoolsDispatcher,
|
|
946
|
-
},
|
|
947
|
-
],
|
|
953
|
+
providers: [...provideStoreDevtools(options).ɵproviders],
|
|
948
954
|
};
|
|
949
955
|
}
|
|
950
956
|
}
|
|
@@ -966,5 +972,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ng
|
|
|
966
972
|
* Generated bundle index. Do not edit.
|
|
967
973
|
*/
|
|
968
974
|
|
|
969
|
-
export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule };
|
|
975
|
+
export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule, provideStoreDevtools };
|
|
970
976
|
//# sourceMappingURL=ngrx-store-devtools.mjs.map
|