@ngrx/store-devtools 14.1.0 → 14.3.1

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.
@@ -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 { INIT, UPDATE, ActionsSubject, INITIAL_STATE, StateObservable, ReducerManagerDispatcher } from '@ngrx/store';
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,59 @@ function createReduxDevtoolsExtension() {
895
895
  return null;
896
896
  }
897
897
  }
898
+ /**
899
+ * Provides developer tools and instrumentation for `Store`.
900
+ *
901
+ * @usageNotes
902
+ *
903
+ * ```ts
904
+ * bootstrapApplication(AppComponent, {
905
+ * providers: [
906
+ * provideStoreDevtools({
907
+ * maxAge: 25,
908
+ * logOnly: environment.production,
909
+ * }),
910
+ * ],
911
+ * });
912
+ * ```
913
+ */
914
+ function provideStoreDevtools(options = {}) {
915
+ return {
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
+ ],
948
+ };
949
+ }
950
+
898
951
  function createStateObservable(devtools) {
899
952
  return devtools.state;
900
953
  }
@@ -902,38 +955,7 @@ class StoreDevtoolsModule {
902
955
  static instrument(options = {}) {
903
956
  return {
904
957
  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
- ],
958
+ providers: [...provideStoreDevtools(options).ɵproviders],
937
959
  };
938
960
  }
939
961
  }
@@ -955,5 +977,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.1", ng
955
977
  * Generated bundle index. Do not edit.
956
978
  */
957
979
 
958
- export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule };
980
+ export { INITIAL_OPTIONS, RECOMPUTE, REDUX_DEVTOOLS_EXTENSION, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule, provideStoreDevtools };
959
981
  //# sourceMappingURL=ngrx-store-devtools.mjs.map