@ngrx/effects
Version:
Side effect model for @ngrx/store
667 lines (645 loc) • 27.5 kB
JavaScript
import * as i1 from 'rxjs';
import { merge, Observable, Subject, defer } from 'rxjs';
import { ignoreElements, materialize, map, catchError, filter, groupBy, mergeMap, exhaustMap, dematerialize, take, concatMap, finalize } from 'rxjs/operators';
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Inject, NgModule, Optional, inject, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER } from '@angular/core';
import * as i3 from '@ngrx/store';
import { ScannedActionsSubject, createAction, ROOT_STORE_PROVIDER, FEATURE_STATE_PROVIDER, Store } from '@ngrx/store';
const DEFAULT_EFFECT_CONFIG = {
dispatch: true,
functional: false,
useEffectsErrorHandler: true,
};
const CREATE_EFFECT_METADATA_KEY = '__@ngrx/effects_create__';
/**
* @description
*
* Creates an effect from a source and an `EffectConfig`.
*
* @param source A function which returns an observable or observable factory.
* @param config A `EffectConfig` to configure the effect. By default,
* `dispatch` is true, `functional` is false, and `useEffectsErrorHandler` is
* true.
* @returns If `EffectConfig`#`functional` is true, returns the source function.
* Else, returns the source function result. When `EffectConfig`#`dispatch` is
* true, the source function result needs to be `Observable<Action>`.
*
* @usageNotes
*
* ### Class Effects
*
* ```ts
* @Injectable()
* export class FeatureEffects {
* // mapping to a different action
* readonly effect1$ = createEffect(
* () => this.actions$.pipe(
* ofType(FeatureActions.actionOne),
* map(() => FeatureActions.actionTwo())
* )
* );
*
* // non-dispatching effect
* readonly effect2$ = createEffect(
* () => this.actions$.pipe(
* ofType(FeatureActions.actionTwo),
* tap(() => console.log('Action Two Dispatched'))
* ),
* { dispatch: false } // FeatureActions.actionTwo is not dispatched
* );
*
* constructor(private readonly actions$: Actions) {}
* }
* ```
*
* ### Functional Effects
*
* ```ts
* // mapping to a different action
* export const loadUsers = createEffect(
* (actions$ = inject(Actions), usersService = inject(UsersService)) => {
* return actions$.pipe(
* ofType(UsersPageActions.opened),
* exhaustMap(() => {
* return usersService.getAll().pipe(
* map((users) => UsersApiActions.usersLoadedSuccess({ users })),
* catchError((error) =>
* of(UsersApiActions.usersLoadedFailure({ error }))
* )
* );
* })
* );
* },
* { functional: true }
* );
*
* // non-dispatching functional effect
* export const logDispatchedActions = createEffect(
* () => inject(Actions).pipe(tap(console.log)),
* { functional: true, dispatch: false }
* );
* ```
*/
function createEffect(source, config = {}) {
const effect = config.functional ? source : source();
const value = {
...DEFAULT_EFFECT_CONFIG,
...config, // Overrides any defaults if values are provided
};
Object.defineProperty(effect, CREATE_EFFECT_METADATA_KEY, {
value,
});
return effect;
}
function getCreateEffectMetadata(instance) {
const propertyNames = Object.getOwnPropertyNames(instance);
const metadata = propertyNames
.filter((propertyName) => {
if (instance[propertyName] &&
instance[propertyName].hasOwnProperty(CREATE_EFFECT_METADATA_KEY)) {
// If the property type has overridden `hasOwnProperty` we need to ensure
// that the metadata is valid (containing a `dispatch` property)
// https://github.com/ngrx/platform/issues/2975
const property = instance[propertyName];
return property[CREATE_EFFECT_METADATA_KEY].hasOwnProperty('dispatch');
}
return false;
})
.map((propertyName) => {
const metaData = instance[propertyName][CREATE_EFFECT_METADATA_KEY];
return {
propertyName,
...metaData,
};
});
return metadata;
}
function getEffectsMetadata(instance) {
return getSourceMetadata(instance).reduce((acc, { propertyName, dispatch, useEffectsErrorHandler }) => {
acc[propertyName] = { dispatch, useEffectsErrorHandler };
return acc;
}, {});
}
function getSourceMetadata(instance) {
return getCreateEffectMetadata(instance);
}
function getSourceForInstance(instance) {
return Object.getPrototypeOf(instance);
}
function isClassInstance(obj) {
return (!!obj.constructor &&
obj.constructor.name !== 'Object' &&
obj.constructor.name !== 'Function');
}
function isClass(classOrRecord) {
return typeof classOrRecord === 'function';
}
function getClasses(classesAndRecords) {
return classesAndRecords.filter(isClass);
}
function isToken(tokenOrRecord) {
return tokenOrRecord instanceof InjectionToken || isClass(tokenOrRecord);
}
function mergeEffects(sourceInstance, globalErrorHandler, effectsErrorHandler) {
const source = getSourceForInstance(sourceInstance);
const isClassBasedEffect = !!source && source.constructor.name !== 'Object';
const sourceName = isClassBasedEffect ? source.constructor.name : null;
const observables$ = getSourceMetadata(sourceInstance).map(({ propertyName, dispatch, useEffectsErrorHandler, }) => {
const observable$ = typeof sourceInstance[propertyName] === 'function'
? sourceInstance[propertyName]()
: sourceInstance[propertyName];
const effectAction$ = useEffectsErrorHandler
? effectsErrorHandler(observable$, globalErrorHandler)
: observable$;
if (dispatch === false) {
return effectAction$.pipe(ignoreElements());
}
const materialized$ = effectAction$.pipe(materialize());
return materialized$.pipe(map((notification) => ({
effect: sourceInstance[propertyName],
notification,
propertyName,
sourceName,
sourceInstance,
})));
});
return merge(...observables$);
}
const MAX_NUMBER_OF_RETRY_ATTEMPTS = 10;
function defaultEffectsErrorHandler(observable$, errorHandler, retryAttemptLeft = MAX_NUMBER_OF_RETRY_ATTEMPTS) {
return observable$.pipe(catchError((error) => {
if (errorHandler)
errorHandler.handleError(error);
if (retryAttemptLeft <= 1) {
return observable$; // last attempt
}
// Return observable that produces this particular effect
return defaultEffectsErrorHandler(observable$, errorHandler, retryAttemptLeft - 1);
}));
}
class Actions extends Observable {
constructor(source) {
super();
if (source) {
this.source = source;
}
}
lift(operator) {
const observable = new Actions();
observable.source = this;
observable.operator = operator;
return observable;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: Actions, deps: [{ token: ScannedActionsSubject }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: Actions, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: Actions, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1.Observable, decorators: [{
type: Inject,
args: [ScannedActionsSubject]
}] }] });
/**
* `ofType` filters an Observable of `Actions` into an Observable of the actions
* whose type strings are passed to it.
*
* For example, if `actions` has type `Actions<AdditionAction|SubstractionAction>`, and
* the type of the `Addition` action is `add`, then
* `actions.pipe(ofType('add'))` returns an `Observable<AdditionAction>`.
*
* Properly typing this function is hard and requires some advanced TS tricks
* below.
*
* Type narrowing automatically works, as long as your `actions` object
* starts with a `Actions<SomeUnionOfActions>` instead of generic `Actions`.
*
* For backwards compatibility, when one passes a single type argument
* `ofType<T>('something')` the result is an `Observable<T>`. Note, that `T`
* completely overrides any possible inference from 'something'.
*
* Unfortunately, for unknown 'actions: Actions' these types will produce
* 'Observable<never>'. In such cases one has to manually set the generic type
* like `actions.ofType<AdditionAction>('add')`.
*
* @usageNotes
*
* Filter the Actions stream on the "customers page loaded" action
*
* ```ts
* import { ofType } from '@ngrx/effects';
* import * fromCustomers from '../customers';
*
* this.actions$.pipe(
* ofType(fromCustomers.pageLoaded)
* )
* ```
*/
function ofType(...allowedTypes) {
return filter((action) => allowedTypes.some((typeOrActionCreator) => {
if (typeof typeOrActionCreator === 'string') {
// Comparing the string to type
return typeOrActionCreator === action.type;
}
// We are filtering by ActionCreator
return typeOrActionCreator.type === action.type;
}));
}
const _ROOT_EFFECTS_GUARD = new InjectionToken('@ngrx/effects Internal Root Guard');
const USER_PROVIDED_EFFECTS = new InjectionToken('@ngrx/effects User Provided Effects');
const _ROOT_EFFECTS = new InjectionToken('@ngrx/effects Internal Root Effects');
const _ROOT_EFFECTS_INSTANCES = new InjectionToken('@ngrx/effects Internal Root Effects Instances');
const _FEATURE_EFFECTS = new InjectionToken('@ngrx/effects Internal Feature Effects');
const _FEATURE_EFFECTS_INSTANCE_GROUPS = new InjectionToken('@ngrx/effects Internal Feature Effects Instance Groups');
const EFFECTS_ERROR_HANDLER = new InjectionToken('@ngrx/effects Effects Error Handler', { providedIn: 'root', factory: () => defaultEffectsErrorHandler });
const ROOT_EFFECTS_INIT = '@ngrx/effects/init';
const rootEffectsInit = createAction(ROOT_EFFECTS_INIT);
function reportInvalidActions(output, reporter) {
if (output.notification.kind === 'N') {
const action = output.notification.value;
const isInvalidAction = !isAction(action);
if (isInvalidAction) {
reporter.handleError(new Error(`Effect ${getEffectName(output)} dispatched an invalid action: ${stringify(action)}`));
}
}
}
function isAction(action) {
return (typeof action !== 'function' &&
action &&
action.type &&
typeof action.type === 'string');
}
function getEffectName({ propertyName, sourceInstance, sourceName, }) {
const isMethod = typeof sourceInstance[propertyName] === 'function';
const isClassBasedEffect = !!sourceName;
return isClassBasedEffect
? `"${sourceName}.${String(propertyName)}${isMethod ? '()' : ''}"`
: `"${String(propertyName)}()"`;
}
function stringify(action) {
try {
return JSON.stringify(action);
}
catch {
return action;
}
}
const onIdentifyEffectsKey = 'ngrxOnIdentifyEffects';
function isOnIdentifyEffects(instance) {
return isFunction(instance, onIdentifyEffectsKey);
}
const onRunEffectsKey = 'ngrxOnRunEffects';
function isOnRunEffects(instance) {
return isFunction(instance, onRunEffectsKey);
}
const onInitEffects = 'ngrxOnInitEffects';
function isOnInitEffects(instance) {
return isFunction(instance, onInitEffects);
}
function isFunction(instance, functionName) {
return (instance &&
functionName in instance &&
typeof instance[functionName] === 'function');
}
class EffectSources extends Subject {
constructor(errorHandler, effectsErrorHandler) {
super();
this.errorHandler = errorHandler;
this.effectsErrorHandler = effectsErrorHandler;
}
addEffects(effectSourceInstance) {
this.next(effectSourceInstance);
}
/**
* @internal
*/
toActions() {
return this.pipe(groupBy((effectsInstance) => isClassInstance(effectsInstance)
? getSourceForInstance(effectsInstance)
: effectsInstance), mergeMap((source$) => {
return source$.pipe(groupBy(effectsInstance));
}), mergeMap((source$) => {
const effect$ = source$.pipe(exhaustMap((sourceInstance) => {
return resolveEffectSource(this.errorHandler, this.effectsErrorHandler)(sourceInstance);
}), map((output) => {
reportInvalidActions(output, this.errorHandler);
return output.notification;
}), filter((notification) => notification.kind === 'N' && notification.value != null), dematerialize());
// start the stream with an INIT action
// do this only for the first Effect instance
const init$ = source$.pipe(take(1), filter(isOnInitEffects), map((instance) => instance.ngrxOnInitEffects()));
return merge(effect$, init$);
}));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectSources, deps: [{ token: i0.ErrorHandler }, { token: EFFECTS_ERROR_HANDLER }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectSources, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectSources, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i0.ErrorHandler }, { type: undefined, decorators: [{
type: Inject,
args: [EFFECTS_ERROR_HANDLER]
}] }] });
function effectsInstance(sourceInstance) {
if (isOnIdentifyEffects(sourceInstance)) {
return sourceInstance.ngrxOnIdentifyEffects();
}
return '';
}
function resolveEffectSource(errorHandler, effectsErrorHandler) {
return (sourceInstance) => {
const mergedEffects$ = mergeEffects(sourceInstance, errorHandler, effectsErrorHandler);
if (isOnRunEffects(sourceInstance)) {
return sourceInstance.ngrxOnRunEffects(mergedEffects$);
}
return mergedEffects$;
};
}
class EffectsRunner {
get isStarted() {
return !!this.effectsSubscription;
}
constructor(effectSources, store) {
this.effectSources = effectSources;
this.store = store;
this.effectsSubscription = null;
}
start() {
if (!this.effectsSubscription) {
this.effectsSubscription = this.effectSources
.toActions()
.subscribe(this.store);
}
}
ngOnDestroy() {
if (this.effectsSubscription) {
this.effectsSubscription.unsubscribe();
this.effectsSubscription = null;
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRunner, deps: [{ token: EffectSources }, { token: i3.Store }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRunner, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRunner, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: EffectSources }, { type: i3.Store }] });
class EffectsRootModule {
constructor(sources, runner, store, rootEffectsInstances, storeRootModule, storeFeatureModule, guard) {
this.sources = sources;
runner.start();
for (const effectsInstance of rootEffectsInstances) {
sources.addEffects(effectsInstance);
}
store.dispatch({ type: ROOT_EFFECTS_INIT });
}
addEffects(effectsInstance) {
this.sources.addEffects(effectsInstance);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRootModule, deps: [{ token: EffectSources }, { token: EffectsRunner }, { token: i3.Store }, { token: _ROOT_EFFECTS_INSTANCES }, { token: i3.StoreRootModule, optional: true }, { token: i3.StoreFeatureModule, optional: true }, { token: _ROOT_EFFECTS_GUARD, optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: EffectsRootModule }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRootModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsRootModule, decorators: [{
type: NgModule,
args: [{}]
}], ctorParameters: () => [{ type: EffectSources }, { type: EffectsRunner }, { type: i3.Store }, { type: undefined, decorators: [{
type: Inject,
args: [_ROOT_EFFECTS_INSTANCES]
}] }, { type: i3.StoreRootModule, decorators: [{
type: Optional
}] }, { type: i3.StoreFeatureModule, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [_ROOT_EFFECTS_GUARD]
}] }] });
class EffectsFeatureModule {
constructor(effectsRootModule, effectsInstanceGroups, storeRootModule, storeFeatureModule) {
const effectsInstances = effectsInstanceGroups.flat();
for (const effectsInstance of effectsInstances) {
effectsRootModule.addEffects(effectsInstance);
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsFeatureModule, deps: [{ token: EffectsRootModule }, { token: _FEATURE_EFFECTS_INSTANCE_GROUPS }, { token: i3.StoreRootModule, optional: true }, { token: i3.StoreFeatureModule, optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: EffectsFeatureModule }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsFeatureModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsFeatureModule, decorators: [{
type: NgModule,
args: [{}]
}], ctorParameters: () => [{ type: EffectsRootModule }, { type: undefined, decorators: [{
type: Inject,
args: [_FEATURE_EFFECTS_INSTANCE_GROUPS]
}] }, { type: i3.StoreRootModule, decorators: [{
type: Optional
}] }, { type: i3.StoreFeatureModule, decorators: [{
type: Optional
}] }] });
class EffectsModule {
static forFeature(...featureEffects) {
const effects = featureEffects.flat();
const effectsClasses = getClasses(effects);
return {
ngModule: EffectsFeatureModule,
providers: [
effectsClasses,
{
provide: _FEATURE_EFFECTS,
multi: true,
useValue: effects,
},
{
provide: USER_PROVIDED_EFFECTS,
multi: true,
useValue: [],
},
{
provide: _FEATURE_EFFECTS_INSTANCE_GROUPS,
multi: true,
useFactory: createEffectsInstances,
deps: [_FEATURE_EFFECTS, USER_PROVIDED_EFFECTS],
},
],
};
}
static forRoot(...rootEffects) {
const effects = rootEffects.flat();
const effectsClasses = getClasses(effects);
return {
ngModule: EffectsRootModule,
providers: [
effectsClasses,
{
provide: _ROOT_EFFECTS,
useValue: [effects],
},
{
provide: _ROOT_EFFECTS_GUARD,
useFactory: _provideForRootGuard,
},
{
provide: USER_PROVIDED_EFFECTS,
multi: true,
useValue: [],
},
{
provide: _ROOT_EFFECTS_INSTANCES,
useFactory: createEffectsInstances,
deps: [_ROOT_EFFECTS, USER_PROVIDED_EFFECTS],
},
],
};
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: EffectsModule }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: EffectsModule, decorators: [{
type: NgModule,
args: [{}]
}] });
function createEffectsInstances(effectsGroups, userProvidedEffectsGroups) {
const effects = [];
for (const effectsGroup of effectsGroups) {
effects.push(...effectsGroup);
}
for (const userProvidedEffectsGroup of userProvidedEffectsGroups) {
effects.push(...userProvidedEffectsGroup);
}
return effects.map((effectsTokenOrRecord) => isToken(effectsTokenOrRecord)
? inject(effectsTokenOrRecord)
: effectsTokenOrRecord);
}
function _provideForRootGuard() {
const runner = inject(EffectsRunner, { optional: true, skipSelf: true });
const rootEffects = inject(_ROOT_EFFECTS, { self: true });
// check whether any effects are actually passed
const hasEffects = !(rootEffects.length === 1 && rootEffects[0].length === 0);
if (hasEffects && runner) {
throw new TypeError(`EffectsModule.forRoot() called twice. Feature modules should use EffectsModule.forFeature() instead.`);
}
return 'guarded';
}
/**
* Wraps project fn with error handling making it safe to use in Effects.
* Takes either a config with named properties that represent different possible
* callbacks or project/error callbacks that are required.
*/
function act(
/** Allow to take either config object or project/error functions */
configOrProject, errorFn) {
const { project, error, complete, operator, unsubscribe } = typeof configOrProject === 'function'
? {
project: configOrProject,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
error: errorFn,
operator: concatMap,
complete: undefined,
unsubscribe: undefined,
}
: { ...configOrProject, operator: configOrProject.operator || concatMap };
return (source) => defer(() => {
const subject = new Subject();
return merge(source.pipe(operator((input, index) => defer(() => {
let completed = false;
let errored = false;
let projectedCount = 0;
return project(input, index).pipe(materialize(), map((notification) => {
switch (notification.kind) {
case 'E':
errored = true;
return {
kind: 'N',
value: error(notification.error, input),
};
case 'C':
completed = true;
return complete
? {
kind: 'N',
value: complete(projectedCount, input),
}
: undefined;
default:
++projectedCount;
return notification;
}
}), filter((n) => n != null), dematerialize(), finalize(() => {
if (!completed && !errored && unsubscribe) {
subject.next(unsubscribe(projectedCount, input));
}
}));
}))), subject);
});
}
/**
* @usageNotes
*
* ### Providing effects at the root level
*
* ```ts
* bootstrapApplication(AppComponent, {
* providers: [provideEffects(RouterEffects)],
* });
* ```
*
* ### Providing effects at the feature level
*
* ```ts
* const booksRoutes: Route[] = [
* {
* path: '',
* providers: [provideEffects(BooksApiEffects)],
* children: [
* { path: '', component: BookListComponent },
* { path: ':id', component: BookDetailsComponent },
* ],
* },
* ];
* ```
*/
function provideEffects(...effects) {
const effectsClassesAndRecords = effects.flat();
const effectsClasses = getClasses(effectsClassesAndRecords);
return makeEnvironmentProviders([
effectsClasses,
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useValue: () => {
inject(ROOT_STORE_PROVIDER);
inject(FEATURE_STATE_PROVIDER, { optional: true });
const effectsRunner = inject(EffectsRunner);
const effectSources = inject(EffectSources);
const shouldInitEffects = !effectsRunner.isStarted;
if (shouldInitEffects) {
effectsRunner.start();
}
for (const effectsClassOrRecord of effectsClassesAndRecords) {
const effectsInstance = isClass(effectsClassOrRecord)
? inject(effectsClassOrRecord)
: effectsClassOrRecord;
effectSources.addEffects(effectsInstance);
}
if (shouldInitEffects) {
const store = inject(Store);
store.dispatch(rootEffectsInit());
}
},
},
]);
}
/**
* DO NOT EDIT
*
* This file is automatically generated at build
*/
/**
* Generated bundle index. Do not edit.
*/
export { Actions, EFFECTS_ERROR_HANDLER, EffectSources, EffectsFeatureModule, EffectsModule, EffectsRootModule, EffectsRunner, ROOT_EFFECTS_INIT, USER_PROVIDED_EFFECTS, act, createEffect, defaultEffectsErrorHandler, getEffectsMetadata, mergeEffects, ofType, provideEffects, rootEffectsInit };
//# sourceMappingURL=ngrx-effects.mjs.map