UNPKG

26.1 kBJavaScriptView Raw
1import * as i3 from '@ngrx/store';
2import { compose, ScannedActionsSubject, createAction } from '@ngrx/store';
3import * as i1 from 'rxjs';
4import { merge, Observable, Subject, defer, Notification, pipe, of } from 'rxjs';
5import { ignoreElements, materialize, map, catchError, filter, groupBy, mergeMap, exhaustMap, dematerialize, take, concatMap, finalize, withLatestFrom } from 'rxjs/operators';
6import * as i0 from '@angular/core';
7import { Injectable, Inject, InjectionToken, NgModule, Optional, Injector, SkipSelf, Self } from '@angular/core';
8
9const DEFAULT_EFFECT_CONFIG = {
10 dispatch: true,
11 useEffectsErrorHandler: true,
12};
13const CREATE_EFFECT_METADATA_KEY = '__@ngrx/effects_create__';
14
15/**
16 * @description
17 * Creates an effect from an `Observable` and an `EffectConfig`.
18 *
19 * @param source A function which returns an `Observable`.
20 * @param config A `Partial<EffectConfig>` to configure the effect. By default, `dispatch` is true and `useEffectsErrorHandler` is true.
21 * @returns If `EffectConfig`#`dispatch` is true, returns `Observable<Action>`. Else, returns `Observable<unknown>`.
22 *
23 * @usageNotes
24 *
25 * ** Mapping to a different action **
26 * ```ts
27 * effectName$ = createEffect(
28 * () => this.actions$.pipe(
29 * ofType(FeatureActions.actionOne),
30 * map(() => FeatureActions.actionTwo())
31 * )
32 * );
33 * ```
34 *
35 * ** Non-dispatching effects **
36 * ```ts
37 * effectName$ = createEffect(
38 * () => this.actions$.pipe(
39 * ofType(FeatureActions.actionOne),
40 * tap(() => console.log('Action One Dispatched'))
41 * ),
42 * { dispatch: false }
43 * // FeatureActions.actionOne is not dispatched
44 * );
45 * ```
46 */
47function createEffect(source, config) {
48 const effect = source();
49 const value = Object.assign(Object.assign({}, DEFAULT_EFFECT_CONFIG), config);
50 Object.defineProperty(effect, CREATE_EFFECT_METADATA_KEY, {
51 value,
52 });
53 return effect;
54}
55function getCreateEffectMetadata(instance) {
56 const propertyNames = Object.getOwnPropertyNames(instance);
57 const metadata = propertyNames
58 .filter((propertyName) => {
59 if (instance[propertyName] &&
60 instance[propertyName].hasOwnProperty(CREATE_EFFECT_METADATA_KEY)) {
61 // If the property type has overridden `hasOwnProperty` we need to ensure
62 // that the metadata is valid (containing a `dispatch`property)
63 // https://github.com/ngrx/platform/issues/2975
64 const property = instance[propertyName];
65 return property[CREATE_EFFECT_METADATA_KEY].hasOwnProperty('dispatch');
66 }
67 return false;
68 })
69 .map((propertyName) => {
70 const metaData = instance[propertyName][CREATE_EFFECT_METADATA_KEY];
71 return Object.assign({ propertyName }, metaData);
72 });
73 return metadata;
74}
75
76function getSourceForInstance(instance) {
77 return Object.getPrototypeOf(instance);
78}
79
80const METADATA_KEY = '__@ngrx/effects__';
81/**
82 * @deprecated The Effect decorator (`@Effect`) is deprecated in favor for the `createEffect` method.
83 * See the docs for more info {@link https://ngrx.io/guide/migration/v11#the-effect-decorator}
84 */
85function Effect(config = {}) {
86 return function (target, propertyName) {
87 const metadata = Object.assign(Object.assign(Object.assign({}, DEFAULT_EFFECT_CONFIG), config), { propertyName });
88 addEffectMetadataEntry(target, metadata);
89 };
90}
91function getEffectDecoratorMetadata(instance) {
92 const effectsDecorators = compose(getEffectMetadataEntries, getSourceForInstance)(instance);
93 return effectsDecorators;
94}
95/**
96 * Type guard to detemine whether METADATA_KEY is already present on the Class
97 * constructor
98 */
99function hasMetadataEntries(sourceProto) {
100 return sourceProto.constructor.hasOwnProperty(METADATA_KEY);
101}
102/** Add Effect Metadata to the Effect Class constructor under specific key */
103function addEffectMetadataEntry(sourceProto, metadata) {
104 if (hasMetadataEntries(sourceProto)) {
105 sourceProto.constructor[METADATA_KEY].push(metadata);
106 }
107 else {
108 Object.defineProperty(sourceProto.constructor, METADATA_KEY, {
109 value: [metadata],
110 });
111 }
112}
113function getEffectMetadataEntries(sourceProto) {
114 return hasMetadataEntries(sourceProto)
115 ? sourceProto.constructor[METADATA_KEY]
116 : [];
117}
118
119function getEffectsMetadata(instance) {
120 return getSourceMetadata(instance).reduce((acc, { propertyName, dispatch, useEffectsErrorHandler }) => {
121 acc[propertyName] = { dispatch, useEffectsErrorHandler };
122 return acc;
123 }, {});
124}
125function getSourceMetadata(instance) {
126 const effects = [
127 getEffectDecoratorMetadata,
128 getCreateEffectMetadata,
129 ];
130 return effects.reduce((sources, source) => sources.concat(source(instance)), []);
131}
132
133function mergeEffects(sourceInstance, globalErrorHandler, effectsErrorHandler) {
134 const sourceName = getSourceForInstance(sourceInstance).constructor.name;
135 const observables$ = getSourceMetadata(sourceInstance).map(({ propertyName, dispatch, useEffectsErrorHandler, }) => {
136 const observable$ = typeof sourceInstance[propertyName] === 'function'
137 ? sourceInstance[propertyName]()
138 : sourceInstance[propertyName];
139 const effectAction$ = useEffectsErrorHandler
140 ? effectsErrorHandler(observable$, globalErrorHandler)
141 : observable$;
142 if (dispatch === false) {
143 return effectAction$.pipe(ignoreElements());
144 }
145 const materialized$ = effectAction$.pipe(materialize());
146 return materialized$.pipe(map((notification) => ({
147 effect: sourceInstance[propertyName],
148 notification,
149 propertyName,
150 sourceName,
151 sourceInstance,
152 })));
153 });
154 return merge(...observables$);
155}
156
157const MAX_NUMBER_OF_RETRY_ATTEMPTS = 10;
158function defaultEffectsErrorHandler(observable$, errorHandler, retryAttemptLeft = MAX_NUMBER_OF_RETRY_ATTEMPTS) {
159 return observable$.pipe(catchError((error) => {
160 if (errorHandler)
161 errorHandler.handleError(error);
162 if (retryAttemptLeft <= 1) {
163 return observable$; // last attempt
164 }
165 // Return observable that produces this particular effect
166 return defaultEffectsErrorHandler(observable$, errorHandler, retryAttemptLeft - 1);
167 }));
168}
169
170class Actions extends Observable {
171 constructor(source) {
172 super();
173 if (source) {
174 this.source = source;
175 }
176 }
177 lift(operator) {
178 const observable = new Actions();
179 observable.source = this;
180 observable.operator = operator;
181 return observable;
182 }
183}
184/** @nocollapse */ /** @nocollapse */ Actions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: Actions, deps: [{ token: ScannedActionsSubject }], target: i0.ɵɵFactoryTarget.Injectable });
185/** @nocollapse */ /** @nocollapse */ Actions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: Actions });
186i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: Actions, decorators: [{
187 type: Injectable
188 }], ctorParameters: function () {
189 return [{ type: i1.Observable, decorators: [{
190 type: Inject,
191 args: [ScannedActionsSubject]
192 }] }];
193 } });
194/**
195 * `ofType` filters an Observable of `Actions` into an Observable of the actions
196 * whose type strings are passed to it.
197 *
198 * For example, if `actions` has type `Actions<AdditionAction|SubstractionAction>`, and
199 * the type of the `Addition` action is `add`, then
200 * `actions.pipe(ofType('add'))` returns an `Observable<AdditionAction>`.
201 *
202 * Properly typing this function is hard and requires some advanced TS tricks
203 * below.
204 *
205 * Type narrowing automatically works, as long as your `actions` object
206 * starts with a `Actions<SomeUnionOfActions>` instead of generic `Actions`.
207 *
208 * For backwards compatibility, when one passes a single type argument
209 * `ofType<T>('something')` the result is an `Observable<T>`. Note, that `T`
210 * completely overrides any possible inference from 'something'.
211 *
212 * Unfortunately, for unknown 'actions: Actions' these types will produce
213 * 'Observable<never>'. In such cases one has to manually set the generic type
214 * like `actions.ofType<AdditionAction>('add')`.
215 *
216 * @usageNotes
217 *
218 * Filter the Actions stream on the "customers page loaded" action
219 *
220 * ```ts
221 * import { ofType } from '@ngrx/effects';
222 * import * fromCustomers from '../customers';
223 *
224 * this.actions$.pipe(
225 * ofType(fromCustomers.pageLoaded)
226 * )
227 * ```
228 */
229function ofType(...allowedTypes) {
230 return filter((action) => allowedTypes.some((typeOrActionCreator) => {
231 if (typeof typeOrActionCreator === 'string') {
232 // Comparing the string to type
233 return typeOrActionCreator === action.type;
234 }
235 // We are filtering by ActionCreator
236 return typeOrActionCreator.type === action.type;
237 }));
238}
239
240function reportInvalidActions(output, reporter) {
241 if (output.notification.kind === 'N') {
242 const action = output.notification.value;
243 const isInvalidAction = !isAction(action);
244 if (isInvalidAction) {
245 reporter.handleError(new Error(`Effect ${getEffectName(output)} dispatched an invalid action: ${stringify(action)}`));
246 }
247 }
248}
249function isAction(action) {
250 return (typeof action !== 'function' &&
251 action &&
252 action.type &&
253 typeof action.type === 'string');
254}
255function getEffectName({ propertyName, sourceInstance, sourceName, }) {
256 const isMethod = typeof sourceInstance[propertyName] === 'function';
257 return `"${sourceName}.${String(propertyName)}${isMethod ? '()' : ''}"`;
258}
259function stringify(action) {
260 try {
261 return JSON.stringify(action);
262 }
263 catch (_a) {
264 return action;
265 }
266}
267
268const onIdentifyEffectsKey = 'ngrxOnIdentifyEffects';
269function isOnIdentifyEffects(instance) {
270 return isFunction(instance, onIdentifyEffectsKey);
271}
272const onRunEffectsKey = 'ngrxOnRunEffects';
273function isOnRunEffects(instance) {
274 return isFunction(instance, onRunEffectsKey);
275}
276const onInitEffects = 'ngrxOnInitEffects';
277function isOnInitEffects(instance) {
278 return isFunction(instance, onInitEffects);
279}
280function isFunction(instance, functionName) {
281 return (instance &&
282 functionName in instance &&
283 typeof instance[functionName] === 'function');
284}
285
286const _ROOT_EFFECTS_GUARD = new InjectionToken('@ngrx/effects Internal Root Guard');
287const USER_PROVIDED_EFFECTS = new InjectionToken('@ngrx/effects User Provided Effects');
288const _ROOT_EFFECTS = new InjectionToken('@ngrx/effects Internal Root Effects');
289const ROOT_EFFECTS = new InjectionToken('@ngrx/effects Root Effects');
290const _FEATURE_EFFECTS = new InjectionToken('@ngrx/effects Internal Feature Effects');
291const FEATURE_EFFECTS = new InjectionToken('@ngrx/effects Feature Effects');
292const EFFECTS_ERROR_HANDLER = new InjectionToken('@ngrx/effects Effects Error Handler');
293
294class EffectSources extends Subject {
295 constructor(errorHandler, effectsErrorHandler) {
296 super();
297 this.errorHandler = errorHandler;
298 this.effectsErrorHandler = effectsErrorHandler;
299 }
300 addEffects(effectSourceInstance) {
301 this.next(effectSourceInstance);
302 }
303 /**
304 * @internal
305 */
306 toActions() {
307 return this.pipe(groupBy(getSourceForInstance), mergeMap((source$) => {
308 return source$.pipe(groupBy(effectsInstance));
309 }), mergeMap((source$) => {
310 const effect$ = source$.pipe(exhaustMap((sourceInstance) => {
311 return resolveEffectSource(this.errorHandler, this.effectsErrorHandler)(sourceInstance);
312 }), map((output) => {
313 reportInvalidActions(output, this.errorHandler);
314 return output.notification;
315 }), filter((notification) => notification.kind === 'N' && notification.value != null), dematerialize());
316 // start the stream with an INIT action
317 // do this only for the first Effect instance
318 const init$ = source$.pipe(take(1), filter(isOnInitEffects), map((instance) => instance.ngrxOnInitEffects()));
319 return merge(effect$, init$);
320 }));
321 }
322}
323/** @nocollapse */ /** @nocollapse */ EffectSources.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectSources, deps: [{ token: i0.ErrorHandler }, { token: EFFECTS_ERROR_HANDLER }], target: i0.ɵɵFactoryTarget.Injectable });
324/** @nocollapse */ /** @nocollapse */ EffectSources.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectSources });
325i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectSources, decorators: [{
326 type: Injectable
327 }], ctorParameters: function () {
328 return [{ type: i0.ErrorHandler }, { type: undefined, decorators: [{
329 type: Inject,
330 args: [EFFECTS_ERROR_HANDLER]
331 }] }];
332 } });
333function effectsInstance(sourceInstance) {
334 if (isOnIdentifyEffects(sourceInstance)) {
335 return sourceInstance.ngrxOnIdentifyEffects();
336 }
337 return '';
338}
339function resolveEffectSource(errorHandler, effectsErrorHandler) {
340 return (sourceInstance) => {
341 const mergedEffects$ = mergeEffects(sourceInstance, errorHandler, effectsErrorHandler);
342 if (isOnRunEffects(sourceInstance)) {
343 return sourceInstance.ngrxOnRunEffects(mergedEffects$);
344 }
345 return mergedEffects$;
346 };
347}
348
349class EffectsRunner {
350 constructor(effectSources, store) {
351 this.effectSources = effectSources;
352 this.store = store;
353 this.effectsSubscription = null;
354 }
355 start() {
356 if (!this.effectsSubscription) {
357 this.effectsSubscription = this.effectSources
358 .toActions()
359 .subscribe(this.store);
360 }
361 }
362 ngOnDestroy() {
363 if (this.effectsSubscription) {
364 this.effectsSubscription.unsubscribe();
365 this.effectsSubscription = null;
366 }
367 }
368}
369/** @nocollapse */ /** @nocollapse */ EffectsRunner.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRunner, deps: [{ token: EffectSources }, { token: i3.Store }], target: i0.ɵɵFactoryTarget.Injectable });
370/** @nocollapse */ /** @nocollapse */ EffectsRunner.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRunner });
371i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRunner, decorators: [{
372 type: Injectable
373 }], ctorParameters: function () { return [{ type: EffectSources }, { type: i3.Store }]; } });
374
375const ROOT_EFFECTS_INIT = '@ngrx/effects/init';
376const rootEffectsInit = createAction(ROOT_EFFECTS_INIT);
377class EffectsRootModule {
378 constructor(sources, runner, store, rootEffects, storeRootModule, storeFeatureModule, guard) {
379 this.sources = sources;
380 runner.start();
381 rootEffects.forEach((effectSourceInstance) => sources.addEffects(effectSourceInstance));
382 store.dispatch({ type: ROOT_EFFECTS_INIT });
383 }
384 addEffects(effectSourceInstance) {
385 this.sources.addEffects(effectSourceInstance);
386 }
387}
388/** @nocollapse */ /** @nocollapse */ EffectsRootModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRootModule, deps: [{ token: EffectSources }, { token: EffectsRunner }, { token: i3.Store }, { token: ROOT_EFFECTS }, { token: i3.StoreRootModule, optional: true }, { token: i3.StoreFeatureModule, optional: true }, { token: _ROOT_EFFECTS_GUARD, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
389/** @nocollapse */ /** @nocollapse */ EffectsRootModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRootModule });
390/** @nocollapse */ /** @nocollapse */ EffectsRootModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRootModule });
391i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsRootModule, decorators: [{
392 type: NgModule,
393 args: [{}]
394 }], ctorParameters: function () {
395 return [{ type: EffectSources }, { type: EffectsRunner }, { type: i3.Store }, { type: undefined, decorators: [{
396 type: Inject,
397 args: [ROOT_EFFECTS]
398 }] }, { type: i3.StoreRootModule, decorators: [{
399 type: Optional
400 }] }, { type: i3.StoreFeatureModule, decorators: [{
401 type: Optional
402 }] }, { type: undefined, decorators: [{
403 type: Optional
404 }, {
405 type: Inject,
406 args: [_ROOT_EFFECTS_GUARD]
407 }] }];
408 } });
409
410class EffectsFeatureModule {
411 constructor(root, effectSourceGroups, storeRootModule, storeFeatureModule) {
412 effectSourceGroups.forEach((group) => group.forEach((effectSourceInstance) => root.addEffects(effectSourceInstance)));
413 }
414}
415/** @nocollapse */ /** @nocollapse */ EffectsFeatureModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsFeatureModule, deps: [{ token: EffectsRootModule }, { token: FEATURE_EFFECTS }, { token: i3.StoreRootModule, optional: true }, { token: i3.StoreFeatureModule, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
416/** @nocollapse */ /** @nocollapse */ EffectsFeatureModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsFeatureModule });
417/** @nocollapse */ /** @nocollapse */ EffectsFeatureModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsFeatureModule });
418i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsFeatureModule, decorators: [{
419 type: NgModule,
420 args: [{}]
421 }], ctorParameters: function () {
422 return [{ type: EffectsRootModule }, { type: undefined, decorators: [{
423 type: Inject,
424 args: [FEATURE_EFFECTS]
425 }] }, { type: i3.StoreRootModule, decorators: [{
426 type: Optional
427 }] }, { type: i3.StoreFeatureModule, decorators: [{
428 type: Optional
429 }] }];
430 } });
431
432class EffectsModule {
433 static forFeature(featureEffects = []) {
434 return {
435 ngModule: EffectsFeatureModule,
436 providers: [
437 featureEffects,
438 {
439 provide: _FEATURE_EFFECTS,
440 multi: true,
441 useValue: featureEffects,
442 },
443 {
444 provide: USER_PROVIDED_EFFECTS,
445 multi: true,
446 useValue: [],
447 },
448 {
449 provide: FEATURE_EFFECTS,
450 multi: true,
451 useFactory: createEffects,
452 deps: [Injector, _FEATURE_EFFECTS, USER_PROVIDED_EFFECTS],
453 },
454 ],
455 };
456 }
457 static forRoot(rootEffects = []) {
458 return {
459 ngModule: EffectsRootModule,
460 providers: [
461 {
462 provide: EFFECTS_ERROR_HANDLER,
463 useValue: defaultEffectsErrorHandler,
464 },
465 EffectsRunner,
466 EffectSources,
467 Actions,
468 rootEffects,
469 {
470 provide: _ROOT_EFFECTS,
471 useValue: [rootEffects],
472 },
473 {
474 provide: _ROOT_EFFECTS_GUARD,
475 useFactory: _provideForRootGuard,
476 deps: [
477 [EffectsRunner, new Optional(), new SkipSelf()],
478 [_ROOT_EFFECTS, new Self()],
479 ],
480 },
481 {
482 provide: USER_PROVIDED_EFFECTS,
483 multi: true,
484 useValue: [],
485 },
486 {
487 provide: ROOT_EFFECTS,
488 useFactory: createEffects,
489 deps: [Injector, _ROOT_EFFECTS, USER_PROVIDED_EFFECTS],
490 },
491 ],
492 };
493 }
494}
495/** @nocollapse */ /** @nocollapse */ EffectsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
496/** @nocollapse */ /** @nocollapse */ EffectsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsModule });
497/** @nocollapse */ /** @nocollapse */ EffectsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsModule });
498i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: EffectsModule, decorators: [{
499 type: NgModule,
500 args: [{}]
501 }] });
502function createEffects(injector, effectGroups, userProvidedEffectGroups) {
503 const mergedEffects = [];
504 for (const effectGroup of effectGroups) {
505 mergedEffects.push(...effectGroup);
506 }
507 for (const userProvidedEffectGroup of userProvidedEffectGroups) {
508 mergedEffects.push(...userProvidedEffectGroup);
509 }
510 return createEffectInstances(injector, mergedEffects);
511}
512function createEffectInstances(injector, effects) {
513 return effects.map((effect) => injector.get(effect));
514}
515function _provideForRootGuard(runner, rootEffects) {
516 // check whether any effects are actually passed
517 const hasEffects = !(rootEffects.length === 1 && rootEffects[0].length === 0);
518 if (hasEffects && runner) {
519 throw new TypeError(`EffectsModule.forRoot() called twice. Feature modules should use EffectsModule.forFeature() instead.`);
520 }
521 return 'guarded';
522}
523
524/**
525 * Wraps project fn with error handling making it safe to use in Effects.
526 * Takes either a config with named properties that represent different possible
527 * callbacks or project/error callbacks that are required.
528 */
529function act(
530/** Allow to take either config object or project/error functions */
531configOrProject, errorFn) {
532 const { project, error, complete, operator, unsubscribe } = typeof configOrProject === 'function'
533 ? {
534 project: configOrProject,
535 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
536 error: errorFn,
537 operator: concatMap,
538 complete: undefined,
539 unsubscribe: undefined,
540 }
541 : Object.assign(Object.assign({}, configOrProject), { operator: configOrProject.operator || concatMap });
542 return (source) => defer(() => {
543 const subject = new Subject();
544 return merge(source.pipe(operator((input, index) => defer(() => {
545 let completed = false;
546 let errored = false;
547 let projectedCount = 0;
548 return project(input, index).pipe(materialize(), map((notification) => {
549 switch (notification.kind) {
550 case 'E':
551 errored = true;
552 return new Notification('N', error(notification.error, input));
553 case 'C':
554 completed = true;
555 return complete
556 ? new Notification('N', complete(projectedCount, input))
557 : undefined;
558 default:
559 ++projectedCount;
560 return notification;
561 }
562 }), filter((n) => n != null), dematerialize(), finalize(() => {
563 if (!completed && !errored && unsubscribe) {
564 subject.next(unsubscribe(projectedCount, input));
565 }
566 }));
567 }))), subject);
568 });
569}
570
571/**
572 * `concatLatestFrom` combines the source value
573 * and the last available value from a lazily evaluated Observable
574 * in a new array
575 *
576 * @usageNotes
577 *
578 * Select the active customer from the NgRx Store
579 *
580 * ```ts
581 * import { concatLatestFrom } from '@ngrx/effects';
582 * import * fromCustomers from '../customers';
583 *
584 * this.actions$.pipe(
585 * concatLatestFrom(() => this.store.select(fromCustomers.selectActiveCustomer))
586 * )
587 * ```
588 *
589 * Select a customer from the NgRx Store by its id that is available on the action
590 *
591 * ```ts
592 * import { concatLatestFrom } from '@ngrx/effects';
593 * import * fromCustomers from '../customers';
594 *
595 * this.actions$.pipe(
596 * concatLatestFrom((action) => this.store.select(fromCustomers.selectCustomer(action.customerId)))
597 * )
598 * ```
599 */
600function concatLatestFrom(observablesFactory) {
601 return pipe(concatMap((value) => {
602 const observables = observablesFactory(value);
603 const observablesAsArray = Array.isArray(observables)
604 ? observables
605 : [observables];
606 return of(value).pipe(withLatestFrom(...observablesAsArray));
607 }));
608}
609
610/**
611 * DO NOT EDIT
612 *
613 * This file is automatically generated at build
614 */
615
616/**
617 * Generated bundle index. Do not edit.
618 */
619
620export { Actions, EFFECTS_ERROR_HANDLER, Effect, EffectSources, EffectsFeatureModule, EffectsModule, EffectsRootModule, EffectsRunner, ROOT_EFFECTS_INIT, USER_PROVIDED_EFFECTS, act, concatLatestFrom, createEffect, defaultEffectsErrorHandler, getEffectsMetadata, mergeEffects, ofType, rootEffectsInit };