@ngxs/store 21.0.0 → 22.0.0-dev.master-8c6b0fc

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,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, DestroyRef, NgZone, Injector, runInInjectionContext, InjectionToken, ErrorHandler, ɵisPromise as _isPromise, computed, makeEnvironmentProviders, provideEnvironmentInitializer, NgModule, APP_BOOTSTRAP_LISTENER, PendingTasks, ApplicationRef, assertInInjectionContext, EnvironmentInjector, createEnvironmentInjector } from '@angular/core';
3
- import { config, Observable, Subject, of, forkJoin, map, shareReplay, filter, take, mergeMap, EMPTY, from, isObservable, defaultIfEmpty, takeUntil, finalize, catchError, distinctUntilChanged, startWith, skip, buffer, debounceTime } from 'rxjs';
4
- import { ɵwrapObserverCalls as _wrapObserverCalls, ɵOrderedSubject as _OrderedSubject, ɵStateStream as _StateStream, ɵhasOwnProperty as _hasOwnProperty, ɵmemoize as _memoize, ɵgetStoreMetadata as _getStoreMetadata, ɵgetSelectorMetadata as _getSelectorMetadata, ɵMETA_KEY as _META_KEY, ɵINITIAL_STATE_TOKEN as _INITIAL_STATE_TOKEN, ɵNgxsActionRegistry as _NgxsActionRegistry, ɵNgxsAppBootstrappedState as _NgxsAppBootstrappedState, ɵensureStoreMetadata as _ensureStoreMetadata, ɵMETA_OPTIONS_KEY as _META_OPTIONS_KEY, ɵensureSelectorMetadata as _ensureSelectorMetadata, ɵNGXS_STATE_CONTEXT_FACTORY as _NGXS_STATE_CONTEXT_FACTORY, ɵNGXS_STATE_FACTORY as _NGXS_STATE_FACTORY } from '@ngxs/store/internals';
2
+ import { inject, Injectable, DestroyRef, NgZone, Injector, runInInjectionContext, InjectionToken, ErrorHandler, EnvironmentInjector, ɵisPromise as _isPromise, computed, makeEnvironmentProviders, provideEnvironmentInitializer, assertInInjectionContext, createEnvironmentInjector, NgModule, APP_BOOTSTRAP_LISTENER, PendingTasks, ApplicationRef } from '@angular/core';
3
+ import { config, Observable, Subject, of, forkJoin, map, shareReplay, mergeMap, EMPTY, filter, from, isObservable, defaultIfEmpty, takeUntil, finalize, catchError, distinctUntilChanged, take, buffer, debounceTime } from 'rxjs';
4
+ import { ɵwrapObserverCalls as _wrapObserverCalls, ɵOrderedSubject as _OrderedSubject, ɵStateStream as _StateStream, ɵhasOwnProperty as _hasOwnProperty, ɵmemoize as _memoize, ɵgetStoreMetadata as _getStoreMetadata, ɵgetSelectorMetadata as _getSelectorMetadata, ɵMETA_KEY as _META_KEY, ɵNGXS_DEVELOPMENT_OPTIONS as _NGXS_DEVELOPMENT_OPTIONS, ɵINITIAL_STATE_TOKEN as _INITIAL_STATE_TOKEN, ɵNgxsActionRegistry as _NgxsActionRegistry, ɵNGXS_APP_BOOTSTRAP_STATE as _NGXS_APP_BOOTSTRAP_STATE, ɵensureStoreMetadata as _ensureStoreMetadata, ɵMETA_OPTIONS_KEY as _META_OPTIONS_KEY, ɵensureSelectorMetadata as _ensureSelectorMetadata, ɵNGXS_STATE_CONTEXT_FACTORY as _NGXS_STATE_CONTEXT_FACTORY, ɵNGXS_STATE_FACTORY as _NGXS_STATE_FACTORY } from '@ngxs/store/internals';
5
5
  export { StateToken } from '@ngxs/store/internals';
6
6
  import { NGXS_PLUGINS, getActionTypeFromInstance, InitState, UpdateState, setValue, getValue, ɵisPluginClass as _isPluginClass } from '@ngxs/store/plugins';
7
7
  export { InitState, NGXS_PLUGINS, UpdateState, actionMatcher, getActionTypeFromInstance, getValue, setValue } from '@ngxs/store/plugins';
8
8
  import { isStateOperator } from '@ngxs/store/operators';
9
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
+ import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
10
 
11
11
  class PluginManager {
12
12
  plugins = [];
@@ -31,10 +31,10 @@ class PluginManager {
31
31
  const handlers = this._pluginHandlers || [];
32
32
  return handlers.map((plugin) => (plugin.handle ? plugin.handle.bind(plugin) : plugin));
33
33
  }
34
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PluginManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
35
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PluginManager, providedIn: 'root' });
34
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PluginManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
35
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PluginManager, providedIn: 'root' });
36
36
  }
37
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PluginManager, decorators: [{
37
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PluginManager, decorators: [{
38
38
  type: Injectable,
39
39
  args: [{ providedIn: 'root' }]
40
40
  }], ctorParameters: () => [] });
@@ -131,12 +131,15 @@ class InternalDispatchedActionResults extends Subject {
131
131
  // Complete the subject once the root injector is destroyed to ensure
132
132
  // there are no active subscribers that would receive events or perform
133
133
  // any actions after the application is destroyed.
134
- inject(DestroyRef).onDestroy(() => this.complete());
134
+ inject(DestroyRef).onDestroy(() => {
135
+ this.complete();
136
+ this.unsubscribe();
137
+ });
135
138
  }
136
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatchedActionResults, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
137
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatchedActionResults, providedIn: 'root' });
139
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatchedActionResults, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
140
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatchedActionResults, providedIn: 'root' });
138
141
  }
139
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatchedActionResults, decorators: [{
142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatchedActionResults, decorators: [{
140
143
  type: Injectable,
141
144
  args: [{ providedIn: 'root' }]
142
145
  }], ctorParameters: () => [] });
@@ -164,10 +167,10 @@ class InternalNgxsExecutionStrategy {
164
167
  }
165
168
  return func();
166
169
  }
167
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalNgxsExecutionStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
168
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalNgxsExecutionStrategy, providedIn: 'root' });
170
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalNgxsExecutionStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
171
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalNgxsExecutionStrategy, providedIn: 'root' });
169
172
  }
170
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalNgxsExecutionStrategy, decorators: [{
173
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalNgxsExecutionStrategy, decorators: [{
171
174
  type: Injectable,
172
175
  args: [{ providedIn: 'root' }]
173
176
  }] });
@@ -202,13 +205,15 @@ class InternalActions extends _OrderedSubject {
202
205
  // there are no active subscribers that would receive events or perform
203
206
  // any actions after the application is destroyed.
204
207
  this.complete();
208
+ this.unsubscribe();
205
209
  this.dispatched$.complete();
210
+ this.dispatched$.unsubscribe();
206
211
  });
207
212
  }
208
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
209
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActions, providedIn: 'root' });
213
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
214
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActions, providedIn: 'root' });
210
215
  }
211
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActions, decorators: [{
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActions, decorators: [{
212
217
  type: Injectable,
213
218
  args: [{ providedIn: 'root' }]
214
219
  }], ctorParameters: () => [] });
@@ -238,10 +243,10 @@ class Actions extends Observable {
238
243
  observer.add(childSubscription);
239
244
  });
240
245
  }
241
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Actions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
242
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Actions, providedIn: 'root' });
246
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Actions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
247
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Actions, providedIn: 'root' });
243
248
  }
244
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Actions, decorators: [{
249
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Actions, decorators: [{
245
250
  type: Injectable,
246
251
  args: [{ providedIn: 'root' }]
247
252
  }], ctorParameters: () => [] });
@@ -296,7 +301,23 @@ class InternalDispatcher {
296
301
  ])(prevState, action).pipe(shareReplay());
297
302
  }
298
303
  getActionResultStream(action) {
299
- return this._actionResults.pipe(filter((ctx) => ctx.action === action && ctx.status !== ActionStatus.Dispatched), take(1), shareReplay());
304
+ // Hot path: avoid allocating `filter` + `take(1)` operator subscriber wrappers on every
305
+ // dispatch. Instead, subscribe directly and complete inline — functionally identical but
306
+ // without the intermediate operator chain objects.
307
+ // `subscriber.complete()` triggers the outer subscription's teardown synchronously, which
308
+ // calls `.unsubscribe()` on the inner `_actionResults` subscription (the returned
309
+ // TeardownLogic), so there is no leak even though unsubscription fires mid-callback.
310
+ return new Observable(subscriber => {
311
+ return this._actionResults.subscribe({
312
+ next: ctx => {
313
+ if (ctx.action === action && ctx.status !== ActionStatus.Dispatched) {
314
+ subscriber.next(ctx);
315
+ subscriber.complete();
316
+ }
317
+ },
318
+ complete: () => !subscriber.closed && subscriber.complete()
319
+ });
320
+ }).pipe(shareReplay());
300
321
  }
301
322
  createDispatchObservable(actionResult$) {
302
323
  return actionResult$.pipe(mergeMap((ctx) => {
@@ -314,10 +335,10 @@ class InternalDispatcher {
314
335
  }
315
336
  }), shareReplay());
316
337
  }
317
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
318
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatcher, providedIn: 'root' });
338
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
339
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatcher, providedIn: 'root' });
319
340
  }
320
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalDispatcher, decorators: [{
341
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalDispatcher, decorators: [{
321
342
  type: Injectable,
322
343
  args: [{ providedIn: 'root' }]
323
344
  }] });
@@ -384,8 +405,8 @@ class NgxsConfig {
384
405
  injectContainerState: false,
385
406
  suppressErrors: false
386
407
  };
387
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
388
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsConfig, providedIn: 'root', useFactory: () => {
408
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
409
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsConfig, providedIn: 'root', useFactory: () => {
389
410
  const defaultConfig = new NgxsConfig();
390
411
  const config = inject(NGXS_OPTIONS);
391
412
  return {
@@ -398,7 +419,7 @@ class NgxsConfig {
398
419
  };
399
420
  } });
400
421
  }
401
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsConfig, decorators: [{
422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsConfig, decorators: [{
402
423
  type: Injectable,
403
424
  args: [{
404
425
  providedIn: 'root',
@@ -482,10 +503,10 @@ class InternalStateOperations {
482
503
  // Set the state to the current + new
483
504
  stateOperations.setState({ ...currentState, ...results.defaults });
484
505
  }
485
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalStateOperations, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
486
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalStateOperations, providedIn: 'root' });
506
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalStateOperations, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
507
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalStateOperations, providedIn: 'root' });
487
508
  }
488
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalStateOperations, decorators: [{
509
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalStateOperations, decorators: [{
489
510
  type: Injectable,
490
511
  args: [{ providedIn: 'root' }]
491
512
  }] });
@@ -547,7 +568,7 @@ function createMemoizedSelectorFn(originalFn, creationMetadata) {
547
568
  }
548
569
  return returnValue;
549
570
  };
550
- const memoizedFn = _memoize(wrappedFn);
571
+ const memoizedFn = _memoize(wrappedFn, originalFn);
551
572
  Object.setPrototypeOf(memoizedFn, originalFn);
552
573
  return memoizedFn;
553
574
  }
@@ -673,7 +694,7 @@ function buildGraph(stateClasses) {
673
694
  const meta = stateClass[_META_KEY];
674
695
  graph[meta.name] = (meta.children || []).map(findName);
675
696
  return graph;
676
- }, {});
697
+ }, Object.create(null));
677
698
  }
678
699
  /**
679
700
  * Given a states array, returns object graph
@@ -690,7 +711,7 @@ function nameToState(states) {
690
711
  const meta = stateClass[_META_KEY];
691
712
  result[meta.name] = stateClass;
692
713
  return result;
693
- }, {});
714
+ }, Object.create(null));
694
715
  }
695
716
  /**
696
717
  * Given a object relationship graph will return the full path
@@ -712,7 +733,7 @@ function nameToState(states) {
712
733
  *
713
734
  * @ignore
714
735
  */
715
- function findFullParentPath(obj, out = {}) {
736
+ function findFullParentPath(obj, out = Object.create(null)) {
716
737
  // Recursively find the full dotted parent path for a given key.
717
738
  const find = (graph, target) => {
718
739
  for (const key in graph) {
@@ -751,7 +772,7 @@ function findFullParentPath(obj, out = {}) {
751
772
  */
752
773
  function topologicalSort(graph) {
753
774
  const sorted = [];
754
- const visited = {};
775
+ const visited = Object.create(null);
755
776
  // DFS (Depth-First Search) to visit each node and its dependencies.
756
777
  const visit = (name, ancestors = []) => {
757
778
  visited[name] = true;
@@ -860,12 +881,6 @@ function jit_hasInjectableAnnotation(stateClass) {
860
881
  return annotations.some((annotation) => annotation?.ngMetadataName === 'Injectable');
861
882
  }
862
883
 
863
- const NGXS_DEVELOPMENT_OPTIONS =
864
- /* @__PURE__ */ new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_DEVELOPMENT_OPTIONS' : '', {
865
- providedIn: 'root',
866
- factory: () => ({ warnOnUnhandledActions: true })
867
- });
868
-
869
884
  class NgxsUnhandledActionsLogger {
870
885
  /**
871
886
  * These actions should be ignored by default; the user can increase this
@@ -873,7 +888,7 @@ class NgxsUnhandledActionsLogger {
873
888
  */
874
889
  _ignoredActions = new Set([InitState.type, UpdateState.type]);
875
890
  constructor() {
876
- const options = inject(NGXS_DEVELOPMENT_OPTIONS);
891
+ const options = inject(_NGXS_DEVELOPMENT_OPTIONS);
877
892
  if (typeof options.warnOnUnhandledActions === 'object') {
878
893
  this.ignoreActions(...options.warnOnUnhandledActions.ignore);
879
894
  }
@@ -898,10 +913,10 @@ class NgxsUnhandledActionsLogger {
898
913
  : action.type;
899
914
  console.warn(`The ${action} action has been dispatched but hasn't been handled. This may happen if the state with an action handler for this action is not registered.`);
900
915
  }
901
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledActionsLogger, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
902
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledActionsLogger });
916
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledActionsLogger, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
917
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledActionsLogger });
903
918
  }
904
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledActionsLogger, decorators: [{
919
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledActionsLogger, decorators: [{
905
920
  type: Injectable
906
921
  }], ctorParameters: () => [] });
907
922
 
@@ -922,10 +937,10 @@ class NgxsUnhandledErrorHandler {
922
937
  // `handleError` (see `_callAndReportToErrorHandler`).
923
938
  this._ngZone.runOutsideAngular(() => this._errorHandler.handleError(error));
924
939
  }
925
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
926
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledErrorHandler, providedIn: 'root' });
940
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
941
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledErrorHandler, providedIn: 'root' });
927
942
  }
928
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsUnhandledErrorHandler, decorators: [{
943
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsUnhandledErrorHandler, decorators: [{
929
944
  type: Injectable,
930
945
  args: [{ providedIn: 'root' }]
931
946
  }] });
@@ -1023,13 +1038,13 @@ function createAllowedActionTypesMap(types) {
1023
1038
  return types.reduce((filterMap, klass) => {
1024
1039
  filterMap[getActionTypeFromInstance(klass)] = true;
1025
1040
  return filterMap;
1026
- }, {});
1041
+ }, Object.create(null));
1027
1042
  }
1028
1043
  function createAllowedStatusesMap(statuses) {
1029
1044
  return statuses.reduce((filterMap, status) => {
1030
1045
  filterMap[status] = true;
1031
1046
  return filterMap;
1032
- }, {});
1047
+ }, Object.create(null));
1033
1048
  }
1034
1049
 
1035
1050
  function simplePatch(value) {
@@ -1051,35 +1066,74 @@ function simplePatch(value) {
1051
1066
  };
1052
1067
  }
1053
1068
 
1069
+ class StateContextDestroyedError extends Error {
1070
+ path;
1071
+ name = 'StateContextDestroyedError';
1072
+ constructor(path) {
1073
+ super(typeof ngDevMode !== 'undefined' && ngDevMode
1074
+ ? `Attempted to interact with state after the injector has been destroyed. State path: "${path}". ` +
1075
+ `This can happen in server-side rendering when the app is destroyed before all async operations complete, ` +
1076
+ `e.g. inside a finalize() operator that runs after the injector has been destroyed.`
1077
+ : path);
1078
+ this.path = path;
1079
+ Object.setPrototypeOf(this, StateContextDestroyedError.prototype);
1080
+ }
1081
+ }
1054
1082
  /**
1055
- * State Context factory class
1083
+ * Creates `StateContext` instances scoped to a specific state path.
1084
+ * Each action handler receives one of these contexts so it can read and
1085
+ * write only its own slice of the global state tree.
1056
1086
  * @ignore
1057
1087
  */
1058
1088
  class StateContextFactory {
1089
+ _injector = inject(EnvironmentInjector);
1059
1090
  _internalStateOperations = inject(InternalStateOperations);
1091
+ // Resolved lazily via `setErrorHandler` to avoid a cyclic dependency when
1092
+ // the ErrorHandler itself injects the Store.
1093
+ _errorHandler = null;
1060
1094
  /**
1061
1095
  * Create the state context
1062
1096
  */
1063
1097
  createStateContext(path, abortSignal) {
1098
+ const injector = this._injector;
1099
+ const errorHandler = this._errorHandler;
1064
1100
  const root = this._internalStateOperations.getRootStateOperations();
1065
1101
  return {
1066
1102
  abortSignal,
1067
1103
  getState() {
1104
+ if (injector.destroyed) {
1105
+ // Only report — do not return early. Returning `undefined as T` would
1106
+ // be a breaking change for callers that assume getState() always
1107
+ // returns a value. handleError is just for observability (e.g. Rollbar);
1108
+ // the state data is still readable even after the injector is gone.
1109
+ errorHandler?.handleError(new StateContextDestroyedError(path));
1110
+ }
1068
1111
  const currentAppState = root.getState();
1069
1112
  return getState(currentAppState, path);
1070
1113
  },
1071
- patchState(val) {
1114
+ patchState(value) {
1115
+ // If the injector has been destroyed (e.g. app destroyed mid-action),
1116
+ // skip the state update to avoid writing to completed subjects.
1117
+ if (injector.destroyed) {
1118
+ errorHandler?.handleError(new StateContextDestroyedError(path));
1119
+ return;
1120
+ }
1072
1121
  const currentAppState = root.getState();
1073
- const patchOperator = simplePatch(val);
1074
- setStateFromOperator(root, currentAppState, patchOperator, path);
1122
+ const patchOperator = simplePatch(value);
1123
+ setStateFromOperator(root, currentAppState, patchOperator, path, injector);
1075
1124
  },
1076
- setState(val) {
1125
+ setState(value) {
1126
+ // Same guard as patchState — no-op if the injector is already destroyed.
1127
+ if (injector.destroyed) {
1128
+ errorHandler?.handleError(new StateContextDestroyedError(path));
1129
+ return;
1130
+ }
1077
1131
  const currentAppState = root.getState();
1078
- if (isStateOperator(val)) {
1079
- setStateFromOperator(root, currentAppState, val, path);
1132
+ if (isStateOperator(value)) {
1133
+ setStateFromOperator(root, currentAppState, value, path, injector);
1080
1134
  }
1081
1135
  else {
1082
- setStateValue(root, currentAppState, val, path);
1136
+ setStateValue(root, currentAppState, value, path, injector);
1083
1137
  }
1084
1138
  },
1085
1139
  dispatch(actions) {
@@ -1087,32 +1141,58 @@ class StateContextFactory {
1087
1141
  }
1088
1142
  };
1089
1143
  }
1090
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateContextFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1091
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateContextFactory, providedIn: 'root' });
1144
+ /** @internal */
1145
+ setErrorHandler() {
1146
+ // Called from `LifecycleStateManager.ngxsBootstrap` rather than at
1147
+ // construction time. If we injected ErrorHandler in the constructor,
1148
+ // an ErrorHandler that itself injects Store would create a circular
1149
+ // dependency — deferring the lookup breaks the cycle.
1150
+ this._errorHandler ??= this._injector.get(ErrorHandler);
1151
+ }
1152
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateContextFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1153
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateContextFactory, providedIn: 'root' });
1092
1154
  }
1093
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateContextFactory, decorators: [{
1155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateContextFactory, decorators: [{
1094
1156
  type: Injectable,
1095
1157
  args: [{ providedIn: 'root' }]
1096
1158
  }] });
1097
- function setStateValue(root, currentAppState, newValue, path) {
1159
+ function setStateValue(root, currentAppState, newValue, path, injector) {
1160
+ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
1161
+ warnIfNewReferenceHasIdenticalValue(injector, getState(currentAppState, path), newValue, path);
1162
+ }
1098
1163
  const newAppState = setValue(currentAppState, path, newValue);
1099
1164
  root.setState(newAppState);
1165
+ // Note: this returns the full app state rather than just the patched slice.
1166
+ // That's a long-standing quirk (present since the original state-factory.ts)
1167
+ // and fixing it would be a breaking change — tracked for a future release.
1100
1168
  return newAppState;
1101
- // In doing this refactoring I noticed that there is a 'bug' where the
1102
- // application state is returned instead of this state slice.
1103
- // This has worked this way since the beginning see:
1104
- // https://github.com/ngxs/store/blame/324c667b4b7debd8eb979006c67ca0ae347d88cd/src/state-factory.ts
1105
- // This needs to be fixed, but is a 'breaking' change.
1106
- // I will do this fix in a subsequent PR and we can decide how to handle it.
1107
- }
1108
- function setStateFromOperator(root, currentAppState, stateOperator, path) {
1169
+ }
1170
+ function setStateFromOperator(root, currentAppState, stateOperator, path, injector) {
1109
1171
  const local = getState(currentAppState, path);
1110
1172
  const newValue = stateOperator(local);
1111
- return setStateValue(root, currentAppState, newValue, path);
1173
+ return setStateValue(root, currentAppState, newValue, path, injector);
1112
1174
  }
1113
1175
  function getState(currentAppState, path) {
1114
1176
  return getValue(currentAppState, path);
1115
1177
  }
1178
+ // Mirrors `warnOnNewReferenceWithIdenticalValue` in `Store#selectSignal`, but catches the
1179
+ // producer side: an action handler that sets a new reference with an identical value causes
1180
+ // unnecessary re-emissions for every `select()`/`selectSignal()` subscriber on this slice.
1181
+ function warnIfNewReferenceHasIdenticalValue(injector, oldValue, newValue, path) {
1182
+ if (Object.is(oldValue, newValue) || injector.destroyed)
1183
+ return;
1184
+ const warnOption = injector.get(_NGXS_DEVELOPMENT_OPTIONS, null)?.warnOnNewReferenceWithIdenticalValue;
1185
+ if (!warnOption)
1186
+ return;
1187
+ try {
1188
+ if (warnOption.isEqual(oldValue, newValue)) {
1189
+ console.error(`A new reference with an identical value was set on the "${path}" state slice. This will cause unnecessary re-emissions for subscribers relying on reference-based equality.`);
1190
+ }
1191
+ }
1192
+ catch {
1193
+ // Swallow silently.
1194
+ }
1195
+ }
1116
1196
 
1117
1197
  class InternalActionHandlerFactory {
1118
1198
  _actions = inject(InternalActions);
@@ -1182,10 +1262,10 @@ class InternalActionHandlerFactory {
1182
1262
  return result;
1183
1263
  };
1184
1264
  }
1185
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActionHandlerFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1186
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActionHandlerFactory, providedIn: 'root' });
1265
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActionHandlerFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1266
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActionHandlerFactory, providedIn: 'root' });
1187
1267
  }
1188
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: InternalActionHandlerFactory, decorators: [{
1268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: InternalActionHandlerFactory, decorators: [{
1189
1269
  type: Injectable,
1190
1270
  args: [{ providedIn: 'root' }]
1191
1271
  }] });
@@ -1229,8 +1309,8 @@ class StateFactory {
1229
1309
  _actionsSubscription = null;
1230
1310
  _ngxsUnhandledErrorHandler = null;
1231
1311
  _states = [];
1232
- _statesByName = {};
1233
- _statePaths = {};
1312
+ _statesByName = Object.create(null);
1313
+ _statePaths = Object.create(null);
1234
1314
  getRuntimeSelectorContext = _memoize(() => {
1235
1315
  // eslint-disable-next-line @typescript-eslint/no-this-alias
1236
1316
  const stateFactory = this;
@@ -1326,20 +1406,51 @@ class StateFactory {
1326
1406
  }
1327
1407
  connectActionHandlers() {
1328
1408
  this._actionsSubscription = this._actions
1329
- .pipe(filter((ctx) => ctx.status === ActionStatus.Dispatched), mergeMap(ctx => {
1409
+ .pipe(mergeMap(ctx => {
1410
+ if (ctx.status !== ActionStatus.Dispatched) {
1411
+ return EMPTY;
1412
+ }
1330
1413
  const action = ctx.action;
1331
- return this.invokeActions(action).pipe(map(() => ({ action, status: ActionStatus.Successful })), defaultIfEmpty({ action, status: ActionStatus.Canceled }), catchError(error => {
1332
- const ngxsUnhandledErrorHandler = (this._ngxsUnhandledErrorHandler ||=
1333
- this._injector.get(NgxsUnhandledErrorHandler));
1334
- const handleableError = assignUnhandledCallback(error, () => ngxsUnhandledErrorHandler.handleError(error, { action }));
1335
- return of({
1336
- action,
1337
- status: ActionStatus.Errored,
1338
- error: handleableError
1339
- });
1414
+ return new Observable(subscriber => this.invokeActions(action).subscribe({
1415
+ next: () => {
1416
+ subscriber.next({ action, status: ActionStatus.Successful });
1417
+ subscriber.complete();
1418
+ },
1419
+ error: error => {
1420
+ const ngxsUnhandledErrorHandler = (this._ngxsUnhandledErrorHandler ||=
1421
+ this._injector.get(NgxsUnhandledErrorHandler));
1422
+ function callback() {
1423
+ ngxsUnhandledErrorHandler.handleError(error, { action });
1424
+ }
1425
+ // An arrow function here would share the `[[Context]]` of the enclosing `error =>`
1426
+ // arrow function, which captures `this` (StateFactory), causing the error object to
1427
+ // retain the entire instance. A named function declaration creates its own context and
1428
+ // V8 only captures variables it actually references — `ngxsUnhandledErrorHandler`,
1429
+ // `error`, `action` — so `this` is never captured. `.bind(null)` goes one step further:
1430
+ // a JSBoundFunction has no `[[Context]]` slot at all, fully severing the retention chain.
1431
+ // This matters because the callback is stored as a value in the
1432
+ // `ɵɵunhandledRxjsErrorCallbacks` WeakMap, keyed by the error object. The error may be
1433
+ // held by third-party code (e.g. error trackers, logging) for an indeterminate duration,
1434
+ // and we have no control over when that key is released.
1435
+ const handleableError = assignUnhandledCallback(error, callback.bind(null));
1436
+ subscriber.next({
1437
+ action,
1438
+ status: ActionStatus.Errored,
1439
+ error: handleableError
1440
+ });
1441
+ subscriber.complete();
1442
+ },
1443
+ complete: () => {
1444
+ if (subscriber.closed)
1445
+ return;
1446
+ subscriber.next({ action, status: ActionStatus.Canceled });
1447
+ subscriber.complete();
1448
+ }
1340
1449
  }));
1341
1450
  }))
1342
- .subscribe(ctx => this._actionResults.next(ctx));
1451
+ .subscribe(ctx => {
1452
+ this._actionResults.next(ctx);
1453
+ });
1343
1454
  }
1344
1455
  /**
1345
1456
  * Invoke actions on the states.
@@ -1373,10 +1484,7 @@ class StateFactory {
1373
1484
  // didn't return `null` so we may ensure the module has been imported.
1374
1485
  unhandledActionsLogger?.warn(action);
1375
1486
  }
1376
- if (!results.length) {
1377
- results.push(of(undefined));
1378
- }
1379
- return forkJoin(results);
1487
+ return results.length > 0 ? forkJoin(results) : of(undefined);
1380
1488
  }
1381
1489
  addToStatesMap(stateClasses) {
1382
1490
  const newStates = [];
@@ -1409,24 +1517,23 @@ class StateFactory {
1409
1517
  }
1410
1518
  hydrateActionMetasMap({ path, actions, instance }) {
1411
1519
  for (const actionType of Object.keys(actions)) {
1412
- const actionHandlers = actions[actionType].map(actionMeta => {
1520
+ for (const actionMeta of actions[actionType]) {
1413
1521
  const handlerFn = (ctx, action) => instance[actionMeta.fn](ctx, action);
1414
- return this._actionHandlerFactory.createActionHandler(path, handlerFn, actionMeta.options);
1415
- });
1416
- for (const actionHandler of actionHandlers) {
1417
- this._actionRegistry.register(actionType, actionHandler);
1522
+ const actionHandler = this._actionHandlerFactory.createActionHandler(path, handlerFn, actionMeta.options);
1523
+ this._actionRegistry.register(actionType, actionHandler, actionMeta.actionClass);
1418
1524
  }
1419
1525
  }
1420
1526
  }
1421
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1422
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateFactory, providedIn: 'root' });
1527
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1528
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateFactory, providedIn: 'root' });
1423
1529
  }
1424
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: StateFactory, decorators: [{
1530
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateFactory, decorators: [{
1425
1531
  type: Injectable,
1426
1532
  args: [{ providedIn: 'root' }]
1427
1533
  }], ctorParameters: () => [] });
1428
1534
 
1429
1535
  class Store {
1536
+ _injector;
1430
1537
  _stateStream = inject(_StateStream);
1431
1538
  _internalStateOperations = inject(InternalStateOperations);
1432
1539
  _config = inject(NgxsConfig);
@@ -1440,6 +1547,9 @@ class Store {
1440
1547
  _selectableStateStream = this._stateStream.pipe(leaveNgxs(this._internalExecutionStrategy), shareReplay({ bufferSize: 1, refCount: true }));
1441
1548
  constructor() {
1442
1549
  this.initStateStream();
1550
+ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
1551
+ this._injector = inject(Injector);
1552
+ }
1443
1553
  }
1444
1554
  /**
1445
1555
  * Dispatches action(s).
@@ -1491,6 +1601,21 @@ class Store {
1491
1601
  const selectorFn = this.getStoreBoundSelectorFn(selector);
1492
1602
  if (typeof ngDevMode !== 'undefined' && ngDevMode) {
1493
1603
  return computed(() => selectorFn(this._stateStream.state()), {
1604
+ equal: (a, b) => {
1605
+ const warnOption = this._injector?.get(_NGXS_DEVELOPMENT_OPTIONS, null)?.warnOnNewReferenceWithIdenticalValue;
1606
+ if (warnOption && !Object.is(a, b)) {
1607
+ try {
1608
+ const originalFn = selector.originalFn;
1609
+ if (warnOption.isEqual(a, b) && originalFn) {
1610
+ console.error('The selector returned the same value shape as it was before triggering signal recomputation. Selector function: ', originalFn);
1611
+ }
1612
+ }
1613
+ catch {
1614
+ // Swallow silently.
1615
+ }
1616
+ }
1617
+ return a === b;
1618
+ },
1494
1619
  debugName: 'NGXS selectSignal'
1495
1620
  });
1496
1621
  }
@@ -1532,10 +1657,10 @@ class Store {
1532
1657
  this._stateStream.next(initialStateValue);
1533
1658
  }
1534
1659
  }
1535
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Store, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1536
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Store, providedIn: 'root' });
1660
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Store, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1661
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Store, providedIn: 'root' });
1537
1662
  }
1538
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Store, decorators: [{
1663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: Store, decorators: [{
1539
1664
  type: Injectable,
1540
1665
  args: [{ providedIn: 'root' }]
1541
1666
  }], ctorParameters: () => [] });
@@ -1570,6 +1695,125 @@ function withNgxsPreboot(prebootFn) {
1570
1695
  ]);
1571
1696
  }
1572
1697
 
1698
+ /**
1699
+ * This function registers a custom global plugin for the state.
1700
+ *
1701
+ * ```ts
1702
+ * bootstrapApplication(AppComponent, {
1703
+ * providers: [
1704
+ * provideStore(
1705
+ * [CountriesState],
1706
+ * withNgxsPlugin(LogoutPlugin)
1707
+ * )
1708
+ * ]
1709
+ * });
1710
+ * ```
1711
+ */
1712
+ function withNgxsPlugin(plugin) {
1713
+ return makeEnvironmentProviders([
1714
+ _isPluginClass(plugin)
1715
+ ? { provide: NGXS_PLUGINS, useClass: plugin, multi: true }
1716
+ : { provide: NGXS_PLUGINS, useValue: plugin, multi: true },
1717
+ // We should inject the `PluginManager` to retrieve `NGXS_PLUGINS` and
1718
+ // register those plugins. The plugin can be added from inside the child
1719
+ // route, so the plugin manager should be re-injected.
1720
+ provideEnvironmentInitializer(() => inject(PluginManager))
1721
+ ]);
1722
+ }
1723
+
1724
+ const REGISTERED_PLUGINS = /* @__PURE__ */ new InjectionToken('', {
1725
+ factory: () => {
1726
+ const plugins = new Set();
1727
+ inject(DestroyRef).onDestroy(() => plugins.clear());
1728
+ return plugins;
1729
+ }
1730
+ });
1731
+ /**
1732
+ * Dynamically registers an NGXS plugin in the current injection context.
1733
+ *
1734
+ * This function allows you to register NGXS plugins at runtime, creating an isolated
1735
+ * environment injector for the plugin. The plugin is automatically cleaned up when
1736
+ * the injection context is destroyed. In development mode, the function validates
1737
+ * that the same plugin is not registered multiple times.
1738
+ *
1739
+ * @param plugin - The NGXS plugin to register. Can be either a class type implementing
1740
+ * `NgxsPlugin` or a plugin function (`NgxsPluginFn`).
1741
+ *
1742
+ * @throws {Error} Throws an error if called outside of an injection context.
1743
+ * @throws {Error} In development mode, throws an error if the plugin has already been registered.
1744
+ *
1745
+ * @remarks
1746
+ * - Must be called within an injection context (e.g., constructor, field initializer, or `runInInjectionContext`).
1747
+ * - The created environment injector is automatically destroyed when the parent context is destroyed.
1748
+ * - Duplicate plugin registration is only checked in development mode for performance reasons.
1749
+ *
1750
+ * @example
1751
+ * ```ts
1752
+ * // Register a plugin class
1753
+ * import { MyThirdPartyIntegrationPlugin } from './plugins/third-party.plugin';
1754
+ *
1755
+ * @Component({
1756
+ * selector: 'app-root',
1757
+ * template: '...'
1758
+ * })
1759
+ * export class AppComponent {
1760
+ * constructor() {
1761
+ * registerNgxsPlugin(MyThirdPartyIntegrationPlugin);
1762
+ * }
1763
+ * }
1764
+ * ```
1765
+ *
1766
+ * @example
1767
+ * ```ts
1768
+ * // Register a plugin function
1769
+ * import { myThirdPartyIntegrationPluginFn } from './plugins/third-party.plugin';
1770
+ *
1771
+ * @Component({
1772
+ * selector: 'app-feature',
1773
+ * template: '...'
1774
+ * })
1775
+ * export class FeatureComponent {
1776
+ * constructor() {
1777
+ * registerNgxsPlugin(myThirdPartyIntegrationPluginFn);
1778
+ * }
1779
+ * }
1780
+ * ```
1781
+ *
1782
+ * @example
1783
+ * ```ts
1784
+ * // Register conditionally based on environment
1785
+ * import { MyDevtoolsPlugin } from './plugins/devtools.plugin';
1786
+ *
1787
+ * @Component({
1788
+ * selector: 'app-root',
1789
+ * template: '...'
1790
+ * })
1791
+ * export class AppComponent {
1792
+ * constructor() {
1793
+ * if (ngDevMode) {
1794
+ * registerNgxsPlugin(MyDevtoolsPlugin);
1795
+ * }
1796
+ * }
1797
+ * }
1798
+ * ```
1799
+ */
1800
+ function registerNgxsPlugin(plugin) {
1801
+ ngDevMode && assertInInjectionContext(registerNgxsPlugin);
1802
+ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
1803
+ const registeredPlugins = inject(REGISTERED_PLUGINS);
1804
+ if (registeredPlugins.has(plugin)) {
1805
+ throw new Error('Plugin has already been registered. Each plugin should only be registered once to avoid unexpected behavior.');
1806
+ }
1807
+ registeredPlugins.add(plugin);
1808
+ }
1809
+ // Create a new environment injector with the plugin configuration.
1810
+ // This isolates the plugin's dependencies and providers.
1811
+ const injector = createEnvironmentInjector([PluginManager, withNgxsPlugin(plugin)], inject(EnvironmentInjector));
1812
+ // Ensure the created injector is destroyed when the injection context is destroyed.
1813
+ // This prevents memory leaks and ensures proper cleanup.
1814
+ inject(DestroyRef).onDestroy(() => injector.destroy());
1815
+ }
1816
+
1573
1817
  const ROOT_STORE_GUARD = /* @__PURE__ */ new InjectionToken('ROOT_STORE_GUARD', {
1574
1818
  providedIn: 'root',
1575
1819
  factory: () => ({ initialized: false })
@@ -1597,25 +1841,28 @@ class SelectFactory {
1597
1841
  SelectFactory.config = null;
1598
1842
  });
1599
1843
  }
1600
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SelectFactory, deps: [{ token: Store }, { token: NgxsConfig }], target: i0.ɵɵFactoryTarget.Injectable });
1601
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SelectFactory, providedIn: 'root' });
1844
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SelectFactory, deps: [{ token: Store }, { token: NgxsConfig }], target: i0.ɵɵFactoryTarget.Injectable });
1845
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SelectFactory, providedIn: 'root' });
1602
1846
  }
1603
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SelectFactory, decorators: [{
1847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SelectFactory, decorators: [{
1604
1848
  type: Injectable,
1605
1849
  args: [{ providedIn: 'root' }]
1606
1850
  }], ctorParameters: () => [{ type: Store }, { type: NgxsConfig }] });
1607
1851
 
1608
1852
  class LifecycleStateManager {
1853
+ _destroyRef = inject(DestroyRef);
1854
+ _injector = inject(Injector);
1609
1855
  _store = inject(Store);
1610
1856
  _internalStateOperations = inject(InternalStateOperations);
1611
1857
  _stateContextFactory = inject(StateContextFactory);
1612
- _appBootstrappedState = inject(_NgxsAppBootstrappedState);
1858
+ _appBootstrapState = inject(_NGXS_APP_BOOTSTRAP_STATE);
1613
1859
  _abortController = new AbortController();
1614
1860
  _initStateHasBeenDispatched;
1615
1861
  constructor() {
1616
1862
  inject(DestroyRef).onDestroy(() => this._abortController.abort());
1617
1863
  }
1618
1864
  ngxsBootstrap(action, results) {
1865
+ this._stateContextFactory.setErrorHandler();
1619
1866
  if (typeof ngDevMode !== 'undefined' && ngDevMode) {
1620
1867
  if (action instanceof InitState) {
1621
1868
  this._initStateHasBeenDispatched = true;
@@ -1633,22 +1880,22 @@ class LifecycleStateManager {
1633
1880
  }
1634
1881
  // It does not need to unsubscribe because it is completed when the
1635
1882
  // root injector is destroyed.
1636
- this._internalStateOperations
1637
- .getRootStateOperations()
1638
- .dispatch(action)
1639
- .pipe(mergeMap(() => {
1883
+ const rootStateOperations = this._internalStateOperations.getRootStateOperations();
1884
+ rootStateOperations.dispatch(action).subscribe(() => {
1640
1885
  // If no states are provided, we safely complete the stream
1641
1886
  // and do not proceed further.
1642
1887
  if (!results) {
1643
- return EMPTY;
1888
+ return;
1644
1889
  }
1645
1890
  this._invokeInitOnStates(results.states);
1646
- return this._appBootstrappedState;
1647
- }))
1648
- .subscribe(appBootstrapped => {
1649
- if (appBootstrapped) {
1891
+ const options = { injector: this._injector };
1892
+ toObservable(this._appBootstrapState, options)
1893
+ .pipe(takeUntilDestroyed(this._destroyRef))
1894
+ .subscribe(appBootstrapped => {
1895
+ if (!appBootstrapped)
1896
+ return;
1650
1897
  this._invokeBootstrapOnStates(results.states);
1651
- }
1898
+ });
1652
1899
  });
1653
1900
  }
1654
1901
  _invokeInitOnStates(mappedStores) {
@@ -1662,11 +1909,6 @@ class LifecycleStateManager {
1662
1909
  // root injector is destroyed.
1663
1910
  this._store
1664
1911
  .select(state => getValue(state, mappedStore.path))
1665
- .pipe(
1666
- // Ensure initial state is captured
1667
- startWith(undefined),
1668
- // `skip` is using `filter` internally.
1669
- skip(1))
1670
1912
  .subscribe(currentValue => {
1671
1913
  const change = new NgxsSimpleChange(previousValue, currentValue, !mappedStore.isInitialised);
1672
1914
  previousValue = currentValue;
@@ -1686,10 +1928,10 @@ class LifecycleStateManager {
1686
1928
  _getStateContext(mappedStore) {
1687
1929
  return this._stateContextFactory.createStateContext(mappedStore.path, this._abortController.signal);
1688
1930
  }
1689
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LifecycleStateManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1690
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LifecycleStateManager, providedIn: 'root' });
1931
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LifecycleStateManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1932
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LifecycleStateManager, providedIn: 'root' });
1691
1933
  }
1692
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LifecycleStateManager, decorators: [{
1934
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LifecycleStateManager, decorators: [{
1693
1935
  type: Injectable,
1694
1936
  args: [{ providedIn: 'root' }]
1695
1937
  }], ctorParameters: () => [] });
@@ -1776,11 +2018,11 @@ class NgxsRootModule {
1776
2018
  constructor() {
1777
2019
  rootStoreInitializer();
1778
2020
  }
1779
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsRootModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1780
- /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: NgxsRootModule });
1781
- /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsRootModule });
2021
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsRootModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2022
+ /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: NgxsRootModule });
2023
+ /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsRootModule });
1782
2024
  }
1783
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsRootModule, decorators: [{
2025
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsRootModule, decorators: [{
1784
2026
  type: NgModule
1785
2027
  }], ctorParameters: () => [] });
1786
2028
 
@@ -1791,11 +2033,11 @@ class NgxsFeatureModule {
1791
2033
  constructor() {
1792
2034
  featureStatesInitializer();
1793
2035
  }
1794
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsFeatureModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1795
- /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: NgxsFeatureModule });
1796
- /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsFeatureModule });
2036
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsFeatureModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2037
+ /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: NgxsFeatureModule });
2038
+ /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsFeatureModule });
1797
2039
  }
1798
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsFeatureModule, decorators: [{
2040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsFeatureModule, decorators: [{
1799
2041
  type: NgModule
1800
2042
  }], ctorParameters: () => [] });
1801
2043
 
@@ -1813,8 +2055,8 @@ function getRootProviders(states, options) {
1813
2055
  {
1814
2056
  provide: APP_BOOTSTRAP_LISTENER,
1815
2057
  useFactory: () => {
1816
- const appBootstrappedState = inject(_NgxsAppBootstrappedState);
1817
- return () => appBootstrappedState.bootstrap();
2058
+ const bootstrapState = inject(_NGXS_APP_BOOTSTRAP_STATE);
2059
+ return () => bootstrapState.set(true);
1818
2060
  },
1819
2061
  multi: true
1820
2062
  },
@@ -1841,24 +2083,33 @@ function getFeatureProviders(states) {
1841
2083
  ];
1842
2084
  }
1843
2085
 
2086
+ /**
2087
+ * @deprecated Use `provideStore()` and `provideStates()` instead.
2088
+ */
1844
2089
  class NgxsModule {
2090
+ /**
2091
+ * @deprecated Use `provideStore()` instead.
2092
+ */
1845
2093
  static forRoot(states = [], options = {}) {
1846
2094
  return {
1847
2095
  ngModule: NgxsRootModule,
1848
2096
  providers: getRootProviders(states, options)
1849
2097
  };
1850
2098
  }
2099
+ /**
2100
+ * @deprecated Use `provideStates()` instead.
2101
+ */
1851
2102
  static forFeature(states = []) {
1852
2103
  return {
1853
2104
  ngModule: NgxsFeatureModule,
1854
2105
  providers: getFeatureProviders(states)
1855
2106
  };
1856
2107
  }
1857
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1858
- /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: NgxsModule });
1859
- /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsModule });
2108
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2109
+ /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: NgxsModule });
2110
+ /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsModule });
1860
2111
  }
1861
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsModule, decorators: [{
2112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsModule, decorators: [{
1862
2113
  type: NgModule
1863
2114
  }] });
1864
2115
 
@@ -1885,7 +2136,8 @@ function Action(actions, options) {
1885
2136
  meta.actions[type].push({
1886
2137
  fn: name,
1887
2138
  options: options || {},
1888
- type
2139
+ type,
2140
+ actionClass: action
1889
2141
  });
1890
2142
  }
1891
2143
  };
@@ -2049,6 +2301,12 @@ function SelectorOptions(options) {
2049
2301
  });
2050
2302
  }
2051
2303
 
2304
+ /**
2305
+ * Function for creating a selector
2306
+ * @param selectors The selectors to use to create the arguments of this function
2307
+ * @param originalFn The original function being made into a selector
2308
+ * @param creationMetadata
2309
+ */
2052
2310
  function createSelector(selectors, projector, creationMetadata) {
2053
2311
  const memoizedFn = createMemoizedSelectorFn(projector, creationMetadata);
2054
2312
  const selectorMetaData = setupSelectorMetadata(projector, creationMetadata);
@@ -2065,7 +2323,7 @@ function Selector(selectors) {
2065
2323
  throwSelectorDecoratorError();
2066
2324
  }
2067
2325
  }
2068
- const memoizedFn = createSelector(selectors, originalFn, {
2326
+ const memoizedFn = createSelector(selectors || [], originalFn, {
2069
2327
  containerClass: target,
2070
2328
  selectorName: key.toString(),
2071
2329
  getSelectorOptions() {
@@ -2088,38 +2346,44 @@ class ActionDirector {
2088
2346
  _actionHandlerFactory = inject(InternalActionHandlerFactory);
2089
2347
  attachAction(stateToken, Action, handlerFn, options = {}) {
2090
2348
  const actionHandler = this._actionHandlerFactory.createActionHandler(stateToken.getName(), handlerFn, options);
2091
- const detach = this._registry.register(Action.type, actionHandler);
2349
+ const detach = this._registry.register(Action.type, actionHandler, Action);
2092
2350
  return { detach };
2093
2351
  }
2094
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ActionDirector, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2095
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ActionDirector, providedIn: 'root' });
2352
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ActionDirector, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2353
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ActionDirector, providedIn: 'root' });
2096
2354
  }
2097
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ActionDirector, decorators: [{
2355
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ActionDirector, decorators: [{
2098
2356
  type: Injectable,
2099
2357
  args: [{ providedIn: 'root' }]
2100
2358
  }] });
2101
2359
 
2360
+ /**
2361
+ * @deprecated Use `withNgxsDevelopmentOptions()` instead.
2362
+ */
2102
2363
  class NgxsDevelopmentModule {
2364
+ /**
2365
+ * @deprecated Use `withNgxsDevelopmentOptions()` instead.
2366
+ */
2103
2367
  static forRoot(options) {
2104
2368
  return {
2105
2369
  ngModule: NgxsDevelopmentModule,
2106
2370
  providers: [
2107
2371
  NgxsUnhandledActionsLogger,
2108
- { provide: NGXS_DEVELOPMENT_OPTIONS, useValue: options }
2372
+ { provide: _NGXS_DEVELOPMENT_OPTIONS, useValue: options }
2109
2373
  ]
2110
2374
  };
2111
2375
  }
2112
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsDevelopmentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2113
- /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: NgxsDevelopmentModule });
2114
- /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsDevelopmentModule });
2376
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsDevelopmentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2377
+ /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: NgxsDevelopmentModule });
2378
+ /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsDevelopmentModule });
2115
2379
  }
2116
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsDevelopmentModule, decorators: [{
2380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NgxsDevelopmentModule, decorators: [{
2117
2381
  type: NgModule
2118
2382
  }] });
2119
2383
  function withNgxsDevelopmentOptions(options) {
2120
2384
  return makeEnvironmentProviders([
2121
2385
  NgxsUnhandledActionsLogger,
2122
- { provide: NGXS_DEVELOPMENT_OPTIONS, useValue: options }
2386
+ { provide: _NGXS_DEVELOPMENT_OPTIONS, useValue: options }
2123
2387
  ]);
2124
2388
  }
2125
2389
 
@@ -2130,10 +2394,10 @@ class NoopNgxsExecutionStrategy {
2130
2394
  leave(func) {
2131
2395
  return func();
2132
2396
  }
2133
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NoopNgxsExecutionStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2134
- /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NoopNgxsExecutionStrategy, providedIn: 'root' });
2397
+ /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NoopNgxsExecutionStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2398
+ /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NoopNgxsExecutionStrategy, providedIn: 'root' });
2135
2399
  }
2136
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NoopNgxsExecutionStrategy, decorators: [{
2400
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: NoopNgxsExecutionStrategy, decorators: [{
2137
2401
  type: Injectable,
2138
2402
  args: [{ providedIn: 'root' }]
2139
2403
  }] });
@@ -2273,9 +2537,13 @@ function createPropertySelectors(parentSelector) {
2273
2537
  */
2274
2538
  function withNgxsPendingTasks() {
2275
2539
  return withNgxsPreboot(() => {
2540
+ // We silently return instead of logging a warning when not in server mode,
2541
+ // as `withNgxsPendingTasks` may legitimately be included in a shared
2542
+ // `provideStore` configuration used by both browser and server apps.
2543
+ // In the browser, data hydrated from the transfer state is consumed
2544
+ // synchronously, so there is no need to contribute to app stability.
2276
2545
  if (typeof ngServerMode === 'undefined' || !ngServerMode) {
2277
- console.warn('[withNgxsPendingTasks] This setup is recommended for server-side rendering only. ' +
2278
- 'Using it in the browser may lead to redundant change detection cycles and degraded performance.');
2546
+ return;
2279
2547
  }
2280
2548
  const actions$ = inject(Actions);
2281
2549
  const pendingTasks = inject(PendingTasks);
@@ -2376,32 +2644,6 @@ function provideStates(states, ...features) {
2376
2644
  ]);
2377
2645
  }
2378
2646
 
2379
- /**
2380
- * This function registers a custom global plugin for the state.
2381
- *
2382
- * ```ts
2383
- * bootstrapApplication(AppComponent, {
2384
- * providers: [
2385
- * provideStore(
2386
- * [CountriesState],
2387
- * withNgxsPlugin(LogoutPlugin)
2388
- * )
2389
- * ]
2390
- * });
2391
- * ```
2392
- */
2393
- function withNgxsPlugin(plugin) {
2394
- return makeEnvironmentProviders([
2395
- _isPluginClass(plugin)
2396
- ? { provide: NGXS_PLUGINS, useClass: plugin, multi: true }
2397
- : { provide: NGXS_PLUGINS, useValue: plugin, multi: true },
2398
- // We should inject the `PluginManager` to retrieve `NGXS_PLUGINS` and
2399
- // register those plugins. The plugin can be added from inside the child
2400
- // route, so the plugin manager should be re-injected.
2401
- provideEnvironmentInitializer(() => inject(PluginManager))
2402
- ]);
2403
- }
2404
-
2405
2647
  /**
2406
2648
  * This function serves as a utility and has multiple purposes.
2407
2649
  * Firstly, it allows you to select properties from the state class
@@ -2419,9 +2661,39 @@ function select(selector) {
2419
2661
  return inject(Store).selectSignal(selector);
2420
2662
  }
2421
2663
 
2664
+ // Extends Observable so callers can subscribe to emission updates (e.g. progress, intermediate states),
2665
+ // while implementing PromiseLike so the JS engine treats it as a thenable when `await` is used —
2666
+ // without this dual nature, callers would have to choose upfront between async/await and reactive patterns.
2667
+ class AsyncReturnType extends Observable {
2668
+ dispatchResult$;
2669
+ constructor(dispatchResult$) {
2670
+ super(subscriber => dispatchResult$.subscribe(subscriber));
2671
+ this.dispatchResult$ = dispatchResult$;
2672
+ }
2673
+ // Called automatically by the JS engine when `await dispatch(...)` is used.
2674
+ // The PromiseLike contract requires full generics on TResult1/TResult2 to support
2675
+ // promise chaining (e.g. `await dispatch(...).then(x => transform(x))`).
2676
+ then(onfulfilled, onrejected) {
2677
+ return new Promise((resolve, reject) => {
2678
+ this.dispatchResult$.subscribe({
2679
+ // Propagate observable errors into the promise rejection path so
2680
+ // `try/catch` around `await dispatch(...)` works as expected.
2681
+ error: reject,
2682
+ // Resolve on complete rather than on next emission — dispatch returns void,
2683
+ // so the caller cares about the action finishing, not any intermediate values.
2684
+ complete: resolve
2685
+ });
2686
+ }).then(
2687
+ // Bridge void → undefined because PromiseLike<void> resolves with no value,
2688
+ // but `onfulfilled` still needs to be invoked to continue the chain correctly.
2689
+ onfulfilled ? () => onfulfilled(undefined) : undefined,
2690
+ // Normalize null to undefined since Promise.then doesn't accept null for rejection handler.
2691
+ onrejected ?? undefined);
2692
+ }
2693
+ }
2422
2694
  function dispatch(ActionType) {
2423
2695
  const store = inject(Store);
2424
- return (...args) => store.dispatch(new ActionType(...args));
2696
+ return (...args) => new AsyncReturnType(store.dispatch(new ActionType(...args)));
2425
2697
  }
2426
2698
 
2427
2699
  function createSelectMap(selectorMap) {
@@ -2515,6 +2787,19 @@ function ɵprovideNgxsInternalStateTokens() {
2515
2787
  }
2516
2788
  ]);
2517
2789
  }
2790
+ // For internal third-party usage only.
2791
+ // Provides a type-safe accessor for `StateFactory`'s private fields so that
2792
+ // third-party consumers do not have to cast or use bracket notation themselves.
2793
+ function ɵgetTypedNgxsStateFactory(stateFactory) {
2794
+ return {
2795
+ // The flat list of all registered mapped stores.
2796
+ states: stateFactory['_states'],
2797
+ // A name-keyed map of all registered states.
2798
+ statesByName: stateFactory['_statesByName'],
2799
+ // A map of dot-separated state paths (e.g. "parent.child") to each state's name.
2800
+ statePaths: stateFactory['_statePaths']
2801
+ };
2802
+ }
2518
2803
 
2519
2804
  /**
2520
2805
  * The public api for consumers of @ngxs/store
@@ -2524,5 +2809,5 @@ function ɵprovideNgxsInternalStateTokens() {
2524
2809
  * Generated bundle index. Do not edit.
2525
2810
  */
2526
2811
 
2527
- export { Action, ActionDirector, ActionStatus, Actions, NgxsConfig, NgxsDevelopmentModule, NgxsModule, NgxsSimpleChange, NgxsUnhandledActionsLogger, NgxsUnhandledErrorHandler, Select, Selector, SelectorOptions, State, Store, createDispatchMap, createModelSelector, createPickSelector, createPropertySelectors, createSelectMap, createSelector, dispatch, lazyProvider, ofAction, ofActionCanceled, ofActionCompleted, ofActionDispatched, ofActionErrored, ofActionSuccessful, provideStates, provideStore, select, withNgxsDevelopmentOptions, withNgxsNoopExecutionStrategy, withNgxsPendingTasks, withNgxsPlugin, withNgxsPreboot, NgxsFeatureModule as ɵNgxsFeatureModule, NgxsRootModule as ɵNgxsRootModule, ɵprovideNgxsInternalStateTokens };
2812
+ export { Action, ActionDirector, ActionStatus, Actions, AsyncReturnType, NgxsConfig, NgxsDevelopmentModule, NgxsModule, NgxsSimpleChange, NgxsUnhandledActionsLogger, NgxsUnhandledErrorHandler, Select, Selector, SelectorOptions, State, StateContextDestroyedError, Store, createDispatchMap, createModelSelector, createPickSelector, createPropertySelectors, createSelectMap, createSelector, dispatch, lazyProvider, ofAction, ofActionCanceled, ofActionCompleted, ofActionDispatched, ofActionErrored, ofActionSuccessful, provideStates, provideStore, registerNgxsPlugin, select, withNgxsDevelopmentOptions, withNgxsNoopExecutionStrategy, withNgxsPendingTasks, withNgxsPlugin, withNgxsPreboot, NgxsFeatureModule as ɵNgxsFeatureModule, NgxsRootModule as ɵNgxsRootModule, ɵgetTypedNgxsStateFactory, ɵprovideNgxsInternalStateTokens };
2528
2813
  //# sourceMappingURL=ngxs-store.mjs.map