@ngrx/store-devtools 14.0.2 → 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
|
}
|
|
@@ -267,6 +267,163 @@ function escapeRegExp(s) {
|
|
|
267
267
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
class DevtoolsDispatcher extends ActionsSubject {
|
|
271
|
+
}
|
|
272
|
+
/** @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 });
|
|
273
|
+
/** @nocollapse */ DevtoolsDispatcher.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher });
|
|
274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, decorators: [{
|
|
275
|
+
type: Injectable
|
|
276
|
+
}] });
|
|
277
|
+
|
|
278
|
+
const ExtensionActionTypes = {
|
|
279
|
+
START: 'START',
|
|
280
|
+
DISPATCH: 'DISPATCH',
|
|
281
|
+
STOP: 'STOP',
|
|
282
|
+
ACTION: 'ACTION',
|
|
283
|
+
};
|
|
284
|
+
const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
|
|
285
|
+
class DevtoolsExtension {
|
|
286
|
+
constructor(devtoolsExtension, config, dispatcher) {
|
|
287
|
+
this.config = config;
|
|
288
|
+
this.dispatcher = dispatcher;
|
|
289
|
+
this.devtoolsExtension = devtoolsExtension;
|
|
290
|
+
this.createActionStreams();
|
|
291
|
+
}
|
|
292
|
+
notify(action, state) {
|
|
293
|
+
if (!this.devtoolsExtension) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// Check to see if the action requires a full update of the liftedState.
|
|
297
|
+
// If it is a simple action generated by the user's app and the recording
|
|
298
|
+
// is not locked/paused, only send the action and the current state (fast).
|
|
299
|
+
//
|
|
300
|
+
// A full liftedState update (slow: serializes the entire liftedState) is
|
|
301
|
+
// only required when:
|
|
302
|
+
// a) redux-devtools-extension fires the @@Init action (ignored by
|
|
303
|
+
// @ngrx/store-devtools)
|
|
304
|
+
// b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
|
|
305
|
+
// or @ngrx/store/update-reducers)
|
|
306
|
+
// c) the state has been recomputed due to time-traveling
|
|
307
|
+
// d) any action that is not a PerformAction to err on the side of
|
|
308
|
+
// caution.
|
|
309
|
+
if (action.type === PERFORM_ACTION) {
|
|
310
|
+
if (state.isLocked || state.isPaused) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const currentState = unliftState(state);
|
|
314
|
+
if (shouldFilterActions(this.config) &&
|
|
315
|
+
isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const sanitizedState = this.config.stateSanitizer
|
|
319
|
+
? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
|
|
320
|
+
: currentState;
|
|
321
|
+
const sanitizedAction = this.config.actionSanitizer
|
|
322
|
+
? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
|
|
323
|
+
: action;
|
|
324
|
+
this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
// Requires full state update
|
|
328
|
+
const sanitizedLiftedState = Object.assign(Object.assign({}, state), { stagedActionIds: state.stagedActionIds, actionsById: this.config.actionSanitizer
|
|
329
|
+
? sanitizeActions(this.config.actionSanitizer, state.actionsById)
|
|
330
|
+
: state.actionsById, computedStates: this.config.stateSanitizer
|
|
331
|
+
? sanitizeStates(this.config.stateSanitizer, state.computedStates)
|
|
332
|
+
: state.computedStates });
|
|
333
|
+
this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
createChangesObservable() {
|
|
337
|
+
if (!this.devtoolsExtension) {
|
|
338
|
+
return EMPTY;
|
|
339
|
+
}
|
|
340
|
+
return new Observable((subscriber) => {
|
|
341
|
+
const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
|
|
342
|
+
this.extensionConnection = connection;
|
|
343
|
+
connection.init();
|
|
344
|
+
connection.subscribe((change) => subscriber.next(change));
|
|
345
|
+
return connection.unsubscribe;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
createActionStreams() {
|
|
349
|
+
// Listens to all changes
|
|
350
|
+
const changes$ = this.createChangesObservable().pipe(share());
|
|
351
|
+
// Listen for the start action
|
|
352
|
+
const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
|
|
353
|
+
// Listen for the stop action
|
|
354
|
+
const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
|
|
355
|
+
// Listen for lifted actions
|
|
356
|
+
const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
|
|
357
|
+
if (action.type === IMPORT_STATE) {
|
|
358
|
+
// State imports may happen in two situations:
|
|
359
|
+
// 1. Explicitly by user
|
|
360
|
+
// 2. User activated the "persist state accross reloads" option
|
|
361
|
+
// and now the state is imported during reload.
|
|
362
|
+
// Because of option 2, we need to give possible
|
|
363
|
+
// lazy loaded reducers time to instantiate.
|
|
364
|
+
// As soon as there is no UPDATE action within 1 second,
|
|
365
|
+
// it is assumed that all reducers are loaded.
|
|
366
|
+
return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
return of(action);
|
|
370
|
+
}
|
|
371
|
+
}));
|
|
372
|
+
// Listen for unlifted actions
|
|
373
|
+
const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
|
|
374
|
+
const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
|
|
375
|
+
const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
|
|
376
|
+
this.start$ = start$.pipe(takeUntil(stop$));
|
|
377
|
+
// Only take the action sources between the start/stop events
|
|
378
|
+
this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
|
|
379
|
+
this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
|
|
380
|
+
}
|
|
381
|
+
unwrapAction(action) {
|
|
382
|
+
return typeof action === 'string' ? eval(`(${action})`) : action;
|
|
383
|
+
}
|
|
384
|
+
getExtensionConfig(config) {
|
|
385
|
+
var _a;
|
|
386
|
+
const extensionOptions = {
|
|
387
|
+
name: config.name,
|
|
388
|
+
features: config.features,
|
|
389
|
+
serialize: config.serialize,
|
|
390
|
+
autoPause: (_a = config.autoPause) !== null && _a !== void 0 ? _a : false,
|
|
391
|
+
// The action/state sanitizers are not added to the config
|
|
392
|
+
// because sanitation is done in this class already.
|
|
393
|
+
// It is done before sending it to the devtools extension for consistency:
|
|
394
|
+
// - If we call extensionConnection.send(...),
|
|
395
|
+
// the extension would call the sanitizers.
|
|
396
|
+
// - If we call devtoolsExtension.send(...) (aka full state update),
|
|
397
|
+
// the extension would NOT call the sanitizers, so we have to do it ourselves.
|
|
398
|
+
};
|
|
399
|
+
if (config.maxAge !== false /* support === 0 */) {
|
|
400
|
+
extensionOptions.maxAge = config.maxAge;
|
|
401
|
+
}
|
|
402
|
+
return extensionOptions;
|
|
403
|
+
}
|
|
404
|
+
sendToReduxDevtools(send) {
|
|
405
|
+
try {
|
|
406
|
+
send();
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/** @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 });
|
|
414
|
+
/** @nocollapse */ DevtoolsExtension.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension });
|
|
415
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, decorators: [{
|
|
416
|
+
type: Injectable
|
|
417
|
+
}], ctorParameters: function () {
|
|
418
|
+
return [{ type: undefined, decorators: [{
|
|
419
|
+
type: Inject,
|
|
420
|
+
args: [REDUX_DEVTOOLS_EXTENSION]
|
|
421
|
+
}] }, { type: StoreDevtoolsConfig, decorators: [{
|
|
422
|
+
type: Inject,
|
|
423
|
+
args: [STORE_DEVTOOLS_CONFIG]
|
|
424
|
+
}] }, { type: DevtoolsDispatcher }];
|
|
425
|
+
} });
|
|
426
|
+
|
|
270
427
|
const INIT_ACTION = { type: INIT };
|
|
271
428
|
const RECOMPUTE = '@ngrx/store-devtools/recompute';
|
|
272
429
|
const RECOMPUTE_ACTION = { type: RECOMPUTE };
|
|
@@ -628,163 +785,6 @@ function liftReducerWith(initialCommittedState, initialLiftedState, errorHandler
|
|
|
628
785
|
};
|
|
629
786
|
}
|
|
630
787
|
|
|
631
|
-
class DevtoolsDispatcher extends ActionsSubject {
|
|
632
|
-
}
|
|
633
|
-
/** @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 });
|
|
634
|
-
/** @nocollapse */ DevtoolsDispatcher.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher });
|
|
635
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsDispatcher, decorators: [{
|
|
636
|
-
type: Injectable
|
|
637
|
-
}] });
|
|
638
|
-
|
|
639
|
-
const ExtensionActionTypes = {
|
|
640
|
-
START: 'START',
|
|
641
|
-
DISPATCH: 'DISPATCH',
|
|
642
|
-
STOP: 'STOP',
|
|
643
|
-
ACTION: 'ACTION',
|
|
644
|
-
};
|
|
645
|
-
const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
|
|
646
|
-
class DevtoolsExtension {
|
|
647
|
-
constructor(devtoolsExtension, config, dispatcher) {
|
|
648
|
-
this.config = config;
|
|
649
|
-
this.dispatcher = dispatcher;
|
|
650
|
-
this.devtoolsExtension = devtoolsExtension;
|
|
651
|
-
this.createActionStreams();
|
|
652
|
-
}
|
|
653
|
-
notify(action, state) {
|
|
654
|
-
if (!this.devtoolsExtension) {
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
// Check to see if the action requires a full update of the liftedState.
|
|
658
|
-
// If it is a simple action generated by the user's app and the recording
|
|
659
|
-
// is not locked/paused, only send the action and the current state (fast).
|
|
660
|
-
//
|
|
661
|
-
// A full liftedState update (slow: serializes the entire liftedState) is
|
|
662
|
-
// only required when:
|
|
663
|
-
// a) redux-devtools-extension fires the @@Init action (ignored by
|
|
664
|
-
// @ngrx/store-devtools)
|
|
665
|
-
// b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
|
|
666
|
-
// or @ngrx/store/update-reducers)
|
|
667
|
-
// c) the state has been recomputed due to time-traveling
|
|
668
|
-
// d) any action that is not a PerformAction to err on the side of
|
|
669
|
-
// caution.
|
|
670
|
-
if (action.type === PERFORM_ACTION) {
|
|
671
|
-
if (state.isLocked || state.isPaused) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
const currentState = unliftState(state);
|
|
675
|
-
if (shouldFilterActions(this.config) &&
|
|
676
|
-
isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
|
|
677
|
-
return;
|
|
678
|
-
}
|
|
679
|
-
const sanitizedState = this.config.stateSanitizer
|
|
680
|
-
? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
|
|
681
|
-
: currentState;
|
|
682
|
-
const sanitizedAction = this.config.actionSanitizer
|
|
683
|
-
? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
|
|
684
|
-
: action;
|
|
685
|
-
this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
|
|
686
|
-
}
|
|
687
|
-
else {
|
|
688
|
-
// Requires full state update
|
|
689
|
-
const sanitizedLiftedState = Object.assign(Object.assign({}, state), { stagedActionIds: state.stagedActionIds, actionsById: this.config.actionSanitizer
|
|
690
|
-
? sanitizeActions(this.config.actionSanitizer, state.actionsById)
|
|
691
|
-
: state.actionsById, computedStates: this.config.stateSanitizer
|
|
692
|
-
? sanitizeStates(this.config.stateSanitizer, state.computedStates)
|
|
693
|
-
: state.computedStates });
|
|
694
|
-
this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
createChangesObservable() {
|
|
698
|
-
if (!this.devtoolsExtension) {
|
|
699
|
-
return EMPTY;
|
|
700
|
-
}
|
|
701
|
-
return new Observable((subscriber) => {
|
|
702
|
-
const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
|
|
703
|
-
this.extensionConnection = connection;
|
|
704
|
-
connection.init();
|
|
705
|
-
connection.subscribe((change) => subscriber.next(change));
|
|
706
|
-
return connection.unsubscribe;
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
createActionStreams() {
|
|
710
|
-
// Listens to all changes
|
|
711
|
-
const changes$ = this.createChangesObservable().pipe(share());
|
|
712
|
-
// Listen for the start action
|
|
713
|
-
const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
|
|
714
|
-
// Listen for the stop action
|
|
715
|
-
const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
|
|
716
|
-
// Listen for lifted actions
|
|
717
|
-
const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
|
|
718
|
-
if (action.type === IMPORT_STATE) {
|
|
719
|
-
// State imports may happen in two situations:
|
|
720
|
-
// 1. Explicitly by user
|
|
721
|
-
// 2. User activated the "persist state accross reloads" option
|
|
722
|
-
// and now the state is imported during reload.
|
|
723
|
-
// Because of option 2, we need to give possible
|
|
724
|
-
// lazy loaded reducers time to instantiate.
|
|
725
|
-
// As soon as there is no UPDATE action within 1 second,
|
|
726
|
-
// it is assumed that all reducers are loaded.
|
|
727
|
-
return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
|
|
728
|
-
}
|
|
729
|
-
else {
|
|
730
|
-
return of(action);
|
|
731
|
-
}
|
|
732
|
-
}));
|
|
733
|
-
// Listen for unlifted actions
|
|
734
|
-
const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
|
|
735
|
-
const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
|
|
736
|
-
const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
|
|
737
|
-
this.start$ = start$.pipe(takeUntil(stop$));
|
|
738
|
-
// Only take the action sources between the start/stop events
|
|
739
|
-
this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
|
|
740
|
-
this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
|
|
741
|
-
}
|
|
742
|
-
unwrapAction(action) {
|
|
743
|
-
return typeof action === 'string' ? eval(`(${action})`) : action;
|
|
744
|
-
}
|
|
745
|
-
getExtensionConfig(config) {
|
|
746
|
-
var _a;
|
|
747
|
-
const extensionOptions = {
|
|
748
|
-
name: config.name,
|
|
749
|
-
features: config.features,
|
|
750
|
-
serialize: config.serialize,
|
|
751
|
-
autoPause: (_a = config.autoPause) !== null && _a !== void 0 ? _a : false,
|
|
752
|
-
// The action/state sanitizers are not added to the config
|
|
753
|
-
// because sanitation is done in this class already.
|
|
754
|
-
// It is done before sending it to the devtools extension for consistency:
|
|
755
|
-
// - If we call extensionConnection.send(...),
|
|
756
|
-
// the extension would call the sanitizers.
|
|
757
|
-
// - If we call devtoolsExtension.send(...) (aka full state update),
|
|
758
|
-
// the extension would NOT call the sanitizers, so we have to do it ourselves.
|
|
759
|
-
};
|
|
760
|
-
if (config.maxAge !== false /* support === 0 */) {
|
|
761
|
-
extensionOptions.maxAge = config.maxAge;
|
|
762
|
-
}
|
|
763
|
-
return extensionOptions;
|
|
764
|
-
}
|
|
765
|
-
sendToReduxDevtools(send) {
|
|
766
|
-
try {
|
|
767
|
-
send();
|
|
768
|
-
}
|
|
769
|
-
catch (err) {
|
|
770
|
-
console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
/** @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 });
|
|
775
|
-
/** @nocollapse */ DevtoolsExtension.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension });
|
|
776
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ngImport: i0, type: DevtoolsExtension, decorators: [{
|
|
777
|
-
type: Injectable
|
|
778
|
-
}], ctorParameters: function () {
|
|
779
|
-
return [{ type: undefined, decorators: [{
|
|
780
|
-
type: Inject,
|
|
781
|
-
args: [REDUX_DEVTOOLS_EXTENSION]
|
|
782
|
-
}] }, { type: StoreDevtoolsConfig, decorators: [{
|
|
783
|
-
type: Inject,
|
|
784
|
-
args: [STORE_DEVTOOLS_CONFIG]
|
|
785
|
-
}] }, { type: DevtoolsDispatcher }];
|
|
786
|
-
} });
|
|
787
|
-
|
|
788
788
|
class StoreDevtools {
|
|
789
789
|
constructor(dispatcher, actions$, reducers$, extension, scannedActions, errorHandler, initialState, config) {
|
|
790
790
|
const liftedInitialState = liftInitialState(initialState, config.monitor);
|
|
@@ -895,6 +895,43 @@ function createReduxDevtoolsExtension() {
|
|
|
895
895
|
return null;
|
|
896
896
|
}
|
|
897
897
|
}
|
|
898
|
+
function provideStoreDevtools(options = {}) {
|
|
899
|
+
return {
|
|
900
|
+
ɵproviders: [
|
|
901
|
+
DevtoolsExtension,
|
|
902
|
+
DevtoolsDispatcher,
|
|
903
|
+
StoreDevtools,
|
|
904
|
+
{
|
|
905
|
+
provide: INITIAL_OPTIONS,
|
|
906
|
+
useValue: options,
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
provide: IS_EXTENSION_OR_MONITOR_PRESENT,
|
|
910
|
+
deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
|
|
911
|
+
useFactory: createIsExtensionOrMonitorPresent,
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
provide: REDUX_DEVTOOLS_EXTENSION,
|
|
915
|
+
useFactory: createReduxDevtoolsExtension,
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
provide: STORE_DEVTOOLS_CONFIG,
|
|
919
|
+
deps: [INITIAL_OPTIONS],
|
|
920
|
+
useFactory: createConfig,
|
|
921
|
+
},
|
|
922
|
+
{
|
|
923
|
+
provide: StateObservable,
|
|
924
|
+
deps: [StoreDevtools],
|
|
925
|
+
useFactory: createStateObservable,
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
provide: ReducerManagerDispatcher,
|
|
929
|
+
useExisting: DevtoolsDispatcher,
|
|
930
|
+
},
|
|
931
|
+
],
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
|
|
898
935
|
function createStateObservable(devtools) {
|
|
899
936
|
return devtools.state;
|
|
900
937
|
}
|
|
@@ -902,38 +939,7 @@ class StoreDevtoolsModule {
|
|
|
902
939
|
static instrument(options = {}) {
|
|
903
940
|
return {
|
|
904
941
|
ngModule: StoreDevtoolsModule,
|
|
905
|
-
providers: [
|
|
906
|
-
DevtoolsExtension,
|
|
907
|
-
DevtoolsDispatcher,
|
|
908
|
-
StoreDevtools,
|
|
909
|
-
{
|
|
910
|
-
provide: INITIAL_OPTIONS,
|
|
911
|
-
useValue: options,
|
|
912
|
-
},
|
|
913
|
-
{
|
|
914
|
-
provide: IS_EXTENSION_OR_MONITOR_PRESENT,
|
|
915
|
-
deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
|
|
916
|
-
useFactory: createIsExtensionOrMonitorPresent,
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
provide: REDUX_DEVTOOLS_EXTENSION,
|
|
920
|
-
useFactory: createReduxDevtoolsExtension,
|
|
921
|
-
},
|
|
922
|
-
{
|
|
923
|
-
provide: STORE_DEVTOOLS_CONFIG,
|
|
924
|
-
deps: [INITIAL_OPTIONS],
|
|
925
|
-
useFactory: createConfig,
|
|
926
|
-
},
|
|
927
|
-
{
|
|
928
|
-
provide: StateObservable,
|
|
929
|
-
deps: [StoreDevtools],
|
|
930
|
-
useFactory: createStateObservable,
|
|
931
|
-
},
|
|
932
|
-
{
|
|
933
|
-
provide: ReducerManagerDispatcher,
|
|
934
|
-
useExisting: DevtoolsDispatcher,
|
|
935
|
-
},
|
|
936
|
-
],
|
|
942
|
+
providers: [...provideStoreDevtools(options).ɵproviders],
|
|
937
943
|
};
|
|
938
944
|
}
|
|
939
945
|
}
|
|
@@ -955,5 +961,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ng
|
|
|
955
961
|
* Generated bundle index. Do not edit.
|
|
956
962
|
*/
|
|
957
963
|
|
|
958
|
-
export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule };
|
|
964
|
+
export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule, provideStoreDevtools };
|
|
959
965
|
//# sourceMappingURL=ngrx-store-devtools.mjs.map
|