ngssm-store 22.0.1 → 22.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,518 +1,415 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, Injectable, inject, provideAppInitializer, EnvironmentInjector, ApplicationRef, signal, runInInjectionContext, Directive, computed } from '@angular/core';
3
- import { Subject, takeUntil, BehaviorSubject, map, distinctUntilChanged } from 'rxjs';
4
- import update from 'immutability-helper';
5
-
6
- const NGSSM_REDUCER = new InjectionToken('NGSSM_REDUCER');
1
+ import * as i0 from "@angular/core";
2
+ import { ApplicationRef, Directive, EnvironmentInjector, Injectable, InjectionToken, computed, inject, makeEnvironmentProviders, provideAppInitializer, runInInjectionContext, signal } from "@angular/core";
3
+ import update from "immutability-helper";
4
+ import { Subject, takeUntil } from "rxjs";
5
+ const NGSSM_REDUCER = new InjectionToken("NGSSM_REDUCER");
7
6
  const provideReducer = (reducer) => {
8
- return makeEnvironmentProviders([{ provide: NGSSM_REDUCER, useClass: reducer, multi: true }]);
7
+ return makeEnvironmentProviders([{
8
+ provide: NGSSM_REDUCER,
9
+ useClass: reducer,
10
+ multi: true
11
+ }]);
9
12
  };
10
13
  const provideReducers = (...reducers) => {
11
- return makeEnvironmentProviders(reducers.map((reducer) => ({ provide: NGSSM_REDUCER, useClass: reducer, multi: true })));
14
+ return makeEnvironmentProviders(reducers.map((reducer) => ({
15
+ provide: NGSSM_REDUCER,
16
+ useClass: reducer,
17
+ multi: true
18
+ })));
12
19
  };
13
-
14
- const NGSSM_EFFECT = new InjectionToken('NGSSM_EFFECT');
20
+ const NGSSM_EFFECT = new InjectionToken("NGSSM_EFFECT");
15
21
  const provideEffect = (effect) => {
16
- return makeEnvironmentProviders([{ provide: NGSSM_EFFECT, useClass: effect, multi: true }]);
22
+ return makeEnvironmentProviders([{
23
+ provide: NGSSM_EFFECT,
24
+ useClass: effect,
25
+ multi: true
26
+ }]);
17
27
  };
18
28
  const provideEffects = (...effects) => {
19
- return makeEnvironmentProviders(effects.map((effect) => ({ provide: NGSSM_EFFECT, useClass: effect, multi: true })));
29
+ return makeEnvironmentProviders(effects.map((effect) => ({
30
+ provide: NGSSM_EFFECT,
31
+ useClass: effect,
32
+ multi: true
33
+ })));
20
34
  };
21
35
  const provideEffectFunc = (actionType, effectFunc) => {
22
- return makeEnvironmentProviders([
23
- {
24
- provide: NGSSM_EFFECT,
25
- useFactory: () => {
26
- const effect = {
27
- processedActions: [actionType],
28
- processAction: (_, state, action) => effectFunc(state, action),
29
- isFunc: true
30
- };
31
- return effect;
32
- },
33
- multi: true
34
- }
35
- ]);
36
+ return makeEnvironmentProviders([{
37
+ provide: NGSSM_EFFECT,
38
+ useFactory: () => {
39
+ return {
40
+ processedActions: [actionType],
41
+ processAction: (_, state, action) => effectFunc(state, action),
42
+ isFunc: true
43
+ };
44
+ },
45
+ multi: true
46
+ }]);
36
47
  };
37
-
38
- const NGSSM_STATE_INITIALIZER = new InjectionToken('NGSSM_STATE_INITIALIZER');
39
-
48
+ const NGSSM_STATE_INITIALIZER = new InjectionToken("NGSSM_STATE_INITIALIZER");
40
49
  var LogLevel;
41
- (function (LogLevel) {
42
- LogLevel["debug"] = "Debug";
43
- LogLevel["information"] = "Information";
44
- LogLevel["error"] = "Error";
50
+ (function(LogLevel) {
51
+ LogLevel["debug"] = "Debug";
52
+ LogLevel["information"] = "Information";
53
+ LogLevel["error"] = "Error";
45
54
  })(LogLevel || (LogLevel = {}));
46
-
47
- class Logger {
48
- _logEvents$ = new Subject();
49
- get logEvents$() {
50
- return this._logEvents$.asObservable();
51
- }
52
- debug(message, payload) {
53
- this.log(LogLevel.debug, message, payload);
54
- }
55
- information(message, payload) {
56
- this.log(LogLevel.information, message, payload);
57
- }
58
- error(message, payload) {
59
- this.log(LogLevel.error, message, payload);
60
- }
61
- log(level, message, payload) {
62
- this._logEvents$.next({
63
- level,
64
- message,
65
- payload
66
- });
67
- }
68
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Logger, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
69
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Logger, providedIn: 'root' });
70
- }
71
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Logger, decorators: [{
72
- type: Injectable,
73
- args: [{
74
- providedIn: 'root'
75
- }]
76
- }] });
77
-
78
- class ConsoleAppender {
79
- logger = inject(Logger);
80
- stopEvent$ = new Subject();
81
- start(contextName) {
82
- this.logger.logEvents$.pipe(takeUntil(this.stopEvent$)).subscribe((logEvent) => {
83
- let logFunction;
84
- switch (logEvent.level) {
85
- case LogLevel.error:
86
- logFunction = console.error;
87
- break;
88
- default:
89
- logFunction = console.log;
90
- break;
91
- }
92
- const now = new Date().toLocaleString();
93
- const prefix = contextName ? `[${contextName}] ` : '';
94
- if (logEvent.payload) {
95
- logFunction(`${prefix}[${now}] [${logEvent.level}] ${logEvent.message}`, logEvent.payload);
96
- }
97
- else {
98
- logFunction(`${prefix}[${now}] [${logEvent.level}] ${logEvent.message}`);
99
- }
100
- });
101
- }
102
- stop() {
103
- this.stopEvent$.next(true);
104
- }
105
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleAppender, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
106
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleAppender, providedIn: 'root' });
107
- }
108
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ConsoleAppender, decorators: [{
109
- type: Injectable,
110
- args: [{
111
- providedIn: 'root'
112
- }]
113
- }] });
114
-
115
- const NGSSM_CONSOLE_APPENDER_NAME = new InjectionToken('NGSSM_CONSOLE_APPENDER_NAME');
55
+ var Logger = class Logger {
56
+ _logEvents$ = new Subject();
57
+ get logEvents$() {
58
+ return this._logEvents$.asObservable();
59
+ }
60
+ debug(message, payload) {
61
+ this.log(LogLevel.debug, message, payload);
62
+ }
63
+ information(message, payload) {
64
+ this.log(LogLevel.information, message, payload);
65
+ }
66
+ error(message, payload) {
67
+ this.log(LogLevel.error, message, payload);
68
+ }
69
+ log(level, message, payload) {
70
+ this._logEvents$.next({
71
+ level,
72
+ message,
73
+ payload
74
+ });
75
+ }
76
+ static ɵfac = i0.ɵɵngDeclareFactory({
77
+ minVersion: "12.0.0",
78
+ version: "22.2.0",
79
+ ngImport: i0,
80
+ type: Logger,
81
+ deps: [],
82
+ target: i0.ɵɵFactoryTarget.Injectable
83
+ });
84
+ static ɵprov = i0.ɵɵngDeclareInjectable({
85
+ minVersion: "12.0.0",
86
+ version: "22.2.0",
87
+ ngImport: i0,
88
+ type: Logger,
89
+ providedIn: "root"
90
+ });
91
+ };
92
+ i0.ɵɵngDeclareClassMetadata({
93
+ minVersion: "12.0.0",
94
+ version: "22.2.0",
95
+ ngImport: i0,
96
+ type: Logger,
97
+ decorators: [{
98
+ type: Injectable,
99
+ args: [{ providedIn: "root" }]
100
+ }]
101
+ });
102
+ var ConsoleAppender = class ConsoleAppender {
103
+ logger = inject(Logger);
104
+ stopEvent$ = new Subject();
105
+ start(contextName) {
106
+ this.logger.logEvents$.pipe(takeUntil(this.stopEvent$)).subscribe((logEvent) => {
107
+ let logFunction;
108
+ switch (logEvent.level) {
109
+ case LogLevel.error:
110
+ logFunction = console.error;
111
+ break;
112
+ default: logFunction = console.log;
113
+ }
114
+ const now = (/* @__PURE__ */ new Date()).toLocaleString();
115
+ const prefix = contextName ? `[${contextName}] ` : "";
116
+ if (logEvent.payload) logFunction(`${prefix}[${now}] [${logEvent.level}] ${logEvent.message}`, logEvent.payload);
117
+ else logFunction(`${prefix}[${now}] [${logEvent.level}] ${logEvent.message}`);
118
+ });
119
+ }
120
+ stop() {
121
+ this.stopEvent$.next(true);
122
+ }
123
+ static ɵfac = i0.ɵɵngDeclareFactory({
124
+ minVersion: "12.0.0",
125
+ version: "22.2.0",
126
+ ngImport: i0,
127
+ type: ConsoleAppender,
128
+ deps: [],
129
+ target: i0.ɵɵFactoryTarget.Injectable
130
+ });
131
+ static ɵprov = i0.ɵɵngDeclareInjectable({
132
+ minVersion: "12.0.0",
133
+ version: "22.2.0",
134
+ ngImport: i0,
135
+ type: ConsoleAppender,
136
+ providedIn: "root"
137
+ });
138
+ };
139
+ i0.ɵɵngDeclareClassMetadata({
140
+ minVersion: "12.0.0",
141
+ version: "22.2.0",
142
+ ngImport: i0,
143
+ type: ConsoleAppender,
144
+ decorators: [{
145
+ type: Injectable,
146
+ args: [{ providedIn: "root" }]
147
+ }]
148
+ });
149
+ const NGSSM_CONSOLE_APPENDER_NAME = new InjectionToken("NGSSM_CONSOLE_APPENDER_NAME");
116
150
  const startConsoleAppenderFactory = () => {
117
- return () => {
118
- const name = inject(NGSSM_CONSOLE_APPENDER_NAME);
119
- const consoleAppender = inject(ConsoleAppender);
120
- consoleAppender.start(name);
121
- };
151
+ return () => {
152
+ const name = inject(NGSSM_CONSOLE_APPENDER_NAME);
153
+ inject(ConsoleAppender).start(name);
154
+ };
122
155
  };
123
156
  const provideConsoleAppender = (name) => {
124
- return makeEnvironmentProviders([
125
- {
126
- provide: NGSSM_CONSOLE_APPENDER_NAME,
127
- useValue: name
128
- },
129
- provideAppInitializer(startConsoleAppenderFactory())
130
- ]);
157
+ return makeEnvironmentProviders([{
158
+ provide: NGSSM_CONSOLE_APPENDER_NAME,
159
+ useValue: name
160
+ }, provideAppInitializer(startConsoleAppenderFactory())]);
131
161
  };
132
-
133
162
  const featureStateSpecifications = [];
134
163
  const NgSsmFeatureState = (specification) => {
135
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
136
- return (target) => {
137
- featureStateSpecifications.push(specification);
138
- };
164
+ return (target) => {
165
+ featureStateSpecifications.push(specification);
166
+ };
139
167
  };
140
- /**
141
- * The `Store` class is a centralized state management system for Angular applications.
142
- * It manages the application state, processes actions using reducers, and handles side effects using effects.
143
- * The class integrates both RxJS (`BehaviorSubject`) and Angular signals for reactive state management.
144
- *
145
- * ### Features:
146
- * - Centralized state management with support for reducers and effects.
147
- * - Reactive state updates using both RxJS and Angular signals.
148
- * - Modular initialization of feature states, reducers, and effects.
149
- * - Sequential action processing with an action queue.
150
- * - Logging for debugging and monitoring state changes and action processing.
151
- *
152
- * ### Usage:
153
- * - Dispatch actions using `dispatchAction` or `dispatchActionType`.
154
- * - Subscribe to state updates using `state$` (RxJS) or `state` (Angular signal).
155
- */
156
- class Store {
157
- // If true, an action is processed in a macro-task by using setTimoeout. Otherwise, Promise.resolve() is used
158
- // When using micro task, an issue can occur with angular root effects that want to process state or action signals.
159
- // They can be executed after a list of actions is processed. In that case, some actions are never processed by the effects.
160
- useMacroTasks = true;
161
- // If true, a call to ApplicationRef.tick is made after an action is processed and the state is updated.
162
- forceChangeDetectionAfterActionProcessed = false;
163
- // Logger service for debugging and monitoring.
164
- logger = inject(Logger);
165
- // Array of reducers to process state updates.
166
- reducers = inject(NGSSM_REDUCER, { optional: true });
167
- // Array of effects to handle side effects.
168
- effects = inject(NGSSM_EFFECT, { optional: true });
169
- // Array of state initializers to set up the initial state.
170
- initializers = inject(NGSSM_STATE_INITIALIZER, { optional: true });
171
- // Angular's `EnvironmentInjector` for running effects in the correct context.
172
- injector = inject(EnvironmentInjector);
173
- applicationRef = inject(ApplicationRef);
174
- // The current state of the application, managed as a BehaviorSubject for RxJS compatibility.
175
- _state$ = new BehaviorSubject({});
176
- // A queue to ensure actions are processed sequentially.
177
- actionQueue = [];
178
- // Maps action types to their corresponding reducers.
179
- reducersPerActionType = new Map();
180
- // Maps action types to their corresponding effects.
181
- effectsPerActionType = new Map();
182
- // The current state of the application, managed as an Angular signal for signal-based reactivity.
183
- _stateSignal = signal({}, /* @ts-ignore */
184
- ...(ngDevMode ? [{ debugName: "_stateSignal" }] : /* istanbul ignore next */ []));
185
- // The most recently action processed by reducers, managed as an Angular signal.
186
- _processedAction = signal({ type: '' }, /* @ts-ignore */
187
- ...(ngDevMode ? [{ debugName: "_processedAction" }] : /* istanbul ignore next */ []));
188
- // The most recently action processed by reducers, managed as an observable.
189
- _processedAction$ = new BehaviorSubject({ type: '' });
190
- /**
191
- * Initializes the `Store` with reducers, effects, and state initializers.
192
- * Also sets up the initial state and registers reducers and effects.
193
- */
194
- constructor() {
195
- // Synchronize the RxJS state with the Angular signal state.
196
- this._state$.subscribe((value) => this._stateSignal.set(value));
197
- this.logger.information('[Store] ---> state initialization...');
198
- let state = this._state$.getValue();
199
- // Initialize feature states.
200
- state = featureStateSpecifications.reduce((p, c) => update(p, { [c.featureStateKey]: { $set: c.initialState } }), state);
201
- // Apply state initializers.
202
- (this.initializers ?? []).forEach((initializer) => {
203
- this.logger.information('[Store] ------> calling initializer', initializer);
204
- state = initializer.initializeState(state);
205
- });
206
- // Update the state with the initialized values.
207
- this._state$.next(state);
208
- // Register reducers and effects.
209
- this.logger.information(`[Store] ---> initialization of ${(this.reducers ?? []).length} reducers...`);
210
- this.initializeProcessors(this.reducers ?? [], this.reducersPerActionType, (r) => r.processedActions);
211
- this.logger.information(`[Store] ---> initialization of ${(this.effects ?? []).length} effects...`);
212
- this.initializeProcessors(this.effects ?? [], this.effectsPerActionType, (e) => e.processedActions);
213
- }
214
- /**
215
- * Returns the current state as an RxJS observable.
216
- * Useful for subscribing to state changes in a reactive manner.
217
- */
218
- get state$() {
219
- return this._state$.asObservable();
220
- }
221
- /**
222
- * Returns the most recently action processed by reducers as an Angular signal.
223
- * Useful for accessing the last processed action in a reactive manner.
224
- * This signal is updated before processing the effects.
225
- */
226
- get processedAction() {
227
- return this._processedAction.asReadonly();
228
- }
229
- /**
230
- * Returns the most recently action processed by reducers as an observale.
231
- * Useful for accessing the last processed action in a reactive manner.
232
- * This signal is updated before processing the effects.
233
- */
234
- get processedAction$() {
235
- return this._processedAction$.asObservable();
236
- }
237
- /**
238
- * Returns the current state as an Angular signal.
239
- * Useful for signal-based reactivity in Angular components.
240
- */
241
- get state() {
242
- return this._stateSignal.asReadonly();
243
- }
244
- /**
245
- * Dispatches an action to the store.
246
- * The action is added to the action queue and processed sequentially.
247
- *
248
- * @param action - The action to dispatch.
249
- */
250
- dispatchAction(action) {
251
- this.actionQueue.push(action);
252
- this.logger.debug(`Action of type '${action.type}' added to the queue => ${this.actionQueue.length} pending actions`, action);
253
- this.addTaskForNextAction();
254
- }
255
- /**
256
- * Dispatches an action by its type.
257
- * This is a shorthand for dispatching actions without additional payload.
258
- *
259
- * @param type - The type of the action to dispatch.
260
- */
261
- dispatchActionType(type) {
262
- this.dispatchAction({ type });
263
- }
264
- /**
265
- * Processes the next action in the action queue.
266
- * Applies reducers to update the state and executes effects for side effects.
267
- */
268
- processNextAction() {
269
- const nextAction = this.actionQueue.shift();
270
- if (!nextAction) {
271
- this.logger.debug('[processNextAction] No action to process');
272
- return;
273
- }
274
- this.logger.information(`[processNextAction] Start processing action '${nextAction.type}...`, nextAction);
275
- try {
276
- // Apply reducers to update the state.
277
- const updatedState = this.applyReducers(nextAction);
278
- if (this.forceChangeDetectionAfterActionProcessed) {
279
- this.applicationRef.tick();
280
- }
281
- // Execute effects for the action.
282
- const effects = this.effectsPerActionType.get(nextAction.type) ?? [];
283
- this.logger.debug(`[Store] ${effects.length} effects found to process the action ${nextAction.type}`, effects);
284
- effects.forEach((effect) => {
285
- if (effect.isFunc === true) {
286
- runInInjectionContext(this.injector, () => this.runEffect(effect, updatedState, nextAction));
287
- }
288
- else {
289
- this.runEffect(effect, updatedState, nextAction);
290
- }
291
- });
292
- }
293
- catch (error) {
294
- this.logger.error(`Error when processing action ${nextAction.type}`, {
295
- error,
296
- action: nextAction
297
- });
298
- }
299
- finally {
300
- this.logger.information(`[processNextAction] action '${nextAction.type} processed.`, nextAction);
301
- // Process the next action asynchronously
302
- this.addTaskForNextAction();
303
- }
304
- }
305
- /**
306
- * Applies reducers to the current state based on the dispatched action.
307
- * Updates the state if there are changes and sets the processed action signal.
308
- *
309
- * @param nextAction - The action being processed.
310
- * @returns The updated state after applying reducers.
311
- */
312
- applyReducers(nextAction) {
313
- try {
314
- const reducers = this.reducersPerActionType.get(nextAction.type) ?? [];
315
- this.logger.debug(`[Store] ${reducers.length} reducers found to process the action ${nextAction.type}`, reducers);
316
- const currentState = this._state$.getValue();
317
- const updatedState = reducers.reduce((p, c) => c.updateState(p, nextAction), currentState);
318
- if (updatedState !== currentState) {
319
- this._state$.next(updatedState);
320
- }
321
- return updatedState;
322
- }
323
- finally {
324
- this.logger.debug(`[Store] Notify action ${nextAction.type} as processed`);
325
- this._processedAction.set(nextAction);
326
- this._processedAction$.next(nextAction);
327
- }
328
- }
329
- /**
330
- * Executes an effect for a given action.
331
- * Handles any errors that occur during effect execution.
332
- *
333
- * @param effect - The effect to execute.
334
- * @param updatedState - The updated state after reducers have been applied.
335
- * @param nextAction - The action being processed.
336
- */
337
- runEffect(effect, updatedState, nextAction) {
338
- try {
339
- effect.processAction(this, updatedState, nextAction);
340
- }
341
- catch (error) {
342
- this.logger.error(`Unable to process action ${nextAction.type} by effect ${effect}`, {
343
- error,
344
- action: nextAction,
345
- processor: effect
346
- });
347
- }
348
- }
349
- /**
350
- * Initializes reducers or effects and maps them to their corresponding action types.
351
- *
352
- * @param processors - The array of reducers or effects to initialize.
353
- * @param processorMap - The map to store processors by action type.
354
- * @param getProcessedActions - A function to retrieve the action types processed by a processor.
355
- */
356
- initializeProcessors(processors, processorMap, getProcessedActions) {
357
- processors.forEach((processor) => {
358
- this.logger.information('[Store] ------> initialization of ', processor);
359
- getProcessedActions(processor).forEach((actionType) => {
360
- const storedProcessors = processorMap.get(actionType) ?? [];
361
- if (storedProcessors.length === 0) {
362
- processorMap.set(actionType, storedProcessors);
363
- }
364
- storedProcessors.push(processor);
365
- });
366
- });
367
- }
368
- addTaskForNextAction() {
369
- if (this.useMacroTasks) {
370
- setTimeout(() => this.processNextAction());
371
- }
372
- else {
373
- Promise.resolve().then(() => this.processNextAction());
374
- }
375
- }
376
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Store, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
377
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Store, providedIn: 'root' });
378
- }
379
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: Store, decorators: [{
380
- type: Injectable,
381
- args: [{
382
- providedIn: 'root'
383
- }]
384
- }], ctorParameters: () => [] });
385
-
386
- const NGSSM_COMPONENT_WITH_FEATURE_STATE = new InjectionToken('NGSSM_COMPONENT_WITH_FEATURE_STATE');
387
-
168
+ var Store = class Store {
169
+ useMacroTasks = true;
170
+ forceChangeDetectionAfterActionProcessed = false;
171
+ logger = inject(Logger);
172
+ reducers = inject(NGSSM_REDUCER, { optional: true });
173
+ effects = inject(NGSSM_EFFECT, { optional: true });
174
+ initializers = inject(NGSSM_STATE_INITIALIZER, { optional: true });
175
+ injector = inject(EnvironmentInjector);
176
+ applicationRef = inject(ApplicationRef);
177
+ actionQueue = [];
178
+ reducersPerActionType = /* @__PURE__ */ new Map();
179
+ effectsPerActionType = /* @__PURE__ */ new Map();
180
+ _stateSignal = signal({}, ...ngDevMode ? [{ debugName: "_stateSignal" }] : /* istanbul ignore next */ []);
181
+ _processedAction = signal({ type: "" }, ...ngDevMode ? [{ debugName: "_processedAction" }] : /* istanbul ignore next */ []);
182
+ constructor() {
183
+ this.logger.information("[Store] ---> state initialization...");
184
+ let state = this._stateSignal();
185
+ state = featureStateSpecifications.reduce((p, c) => update(p, { [c.featureStateKey]: { $set: c.initialState } }), state);
186
+ (this.initializers ?? []).forEach((initializer) => {
187
+ this.logger.information("[Store] ------> calling initializer", initializer);
188
+ state = initializer.initializeState(state);
189
+ });
190
+ this._stateSignal.set(state);
191
+ this.logger.information(`[Store] ---> initialization of ${(this.reducers ?? []).length} reducers...`);
192
+ this.initializeProcessors(this.reducers ?? [], this.reducersPerActionType, (r) => r.processedActions);
193
+ this.logger.information(`[Store] ---> initialization of ${(this.effects ?? []).length} effects...`);
194
+ this.initializeProcessors(this.effects ?? [], this.effectsPerActionType, (e) => e.processedActions);
195
+ }
196
+ get processedAction() {
197
+ return this._processedAction.asReadonly();
198
+ }
199
+ get state() {
200
+ return this._stateSignal.asReadonly();
201
+ }
202
+ dispatchAction(action) {
203
+ this.actionQueue.push(action);
204
+ this.logger.debug(`Action of type '${action.type}' added to the queue => ${this.actionQueue.length} pending actions`, action);
205
+ this.addTaskForNextAction();
206
+ }
207
+ dispatchActionType(type) {
208
+ this.dispatchAction({ type });
209
+ }
210
+ processNextAction() {
211
+ const nextAction = this.actionQueue.shift();
212
+ if (!nextAction) {
213
+ this.logger.debug("[processNextAction] No action to process");
214
+ return;
215
+ }
216
+ this.logger.information(`[processNextAction] Start processing action '${nextAction.type}...`, nextAction);
217
+ try {
218
+ const updatedState = this.applyReducers(nextAction);
219
+ if (this.forceChangeDetectionAfterActionProcessed) this.applicationRef.tick();
220
+ const effects = this.effectsPerActionType.get(nextAction.type) ?? [];
221
+ this.logger.debug(`[Store] ${effects.length} effects found to process the action ${nextAction.type}`, effects);
222
+ effects.forEach((effect) => {
223
+ if (effect.isFunc === true) runInInjectionContext(this.injector, () => this.runEffect(effect, updatedState, nextAction));
224
+ else this.runEffect(effect, updatedState, nextAction);
225
+ });
226
+ } catch (error) {
227
+ this.logger.error(`Error when processing action ${nextAction.type}`, {
228
+ error,
229
+ action: nextAction
230
+ });
231
+ } finally {
232
+ this.logger.information(`[processNextAction] action '${nextAction.type} processed.`, nextAction);
233
+ this.addTaskForNextAction();
234
+ }
235
+ }
236
+ applyReducers(nextAction) {
237
+ try {
238
+ const reducers = this.reducersPerActionType.get(nextAction.type) ?? [];
239
+ this.logger.debug(`[Store] ${reducers.length} reducers found to process the action ${nextAction.type}`, reducers);
240
+ const currentState = this._stateSignal();
241
+ const updatedState = reducers.reduce((p, c) => c.updateState(p, nextAction), currentState);
242
+ if (updatedState !== currentState) this._stateSignal.set(updatedState);
243
+ return updatedState;
244
+ } finally {
245
+ this.logger.debug(`[Store] Notify action ${nextAction.type} as processed`);
246
+ this._processedAction.set(nextAction);
247
+ }
248
+ }
249
+ runEffect(effect, updatedState, nextAction) {
250
+ try {
251
+ effect.processAction(this, updatedState, nextAction);
252
+ } catch (error) {
253
+ this.logger.error(`Unable to process action ${nextAction.type} by effect ${effect}`, {
254
+ error,
255
+ action: nextAction,
256
+ processor: effect
257
+ });
258
+ }
259
+ }
260
+ initializeProcessors(processors, processorMap, getProcessedActions) {
261
+ processors.forEach((processor) => {
262
+ this.logger.information("[Store] ------> initialization of ", processor);
263
+ getProcessedActions(processor).forEach((actionType) => {
264
+ const storedProcessors = processorMap.get(actionType) ?? [];
265
+ if (storedProcessors.length === 0) processorMap.set(actionType, storedProcessors);
266
+ storedProcessors.push(processor);
267
+ });
268
+ });
269
+ }
270
+ addTaskForNextAction() {
271
+ if (this.useMacroTasks) setTimeout(() => this.processNextAction());
272
+ else Promise.resolve().then(() => this.processNextAction());
273
+ }
274
+ static ɵfac = i0.ɵɵngDeclareFactory({
275
+ minVersion: "12.0.0",
276
+ version: "22.2.0",
277
+ ngImport: i0,
278
+ type: Store,
279
+ deps: [],
280
+ target: i0.ɵɵFactoryTarget.Injectable
281
+ });
282
+ static ɵprov = i0.ɵɵngDeclareInjectable({
283
+ minVersion: "12.0.0",
284
+ version: "22.2.0",
285
+ ngImport: i0,
286
+ type: Store,
287
+ providedIn: "root"
288
+ });
289
+ };
290
+ i0.ɵɵngDeclareClassMetadata({
291
+ minVersion: "12.0.0",
292
+ version: "22.2.0",
293
+ ngImport: i0,
294
+ type: Store,
295
+ decorators: [{
296
+ type: Injectable,
297
+ args: [{ providedIn: "root" }]
298
+ }],
299
+ ctorParameters: () => []
300
+ });
301
+ const NGSSM_COMPONENT_WITH_FEATURE_STATE = new InjectionToken("NGSSM_COMPONENT_WITH_FEATURE_STATE");
388
302
  var NgssmStoreActionType;
389
- (function (NgssmStoreActionType) {
390
- NgssmStoreActionType["registerFeatureState"] = "[NgssmStoreActionType] registerFeatureState";
391
- NgssmStoreActionType["unregisterFeatureState"] = "[NgssmStoreActionType] unregisterFeatureState";
303
+ (function(NgssmStoreActionType) {
304
+ NgssmStoreActionType["registerFeatureState"] = "[NgssmStoreActionType] registerFeatureState";
305
+ NgssmStoreActionType["unregisterFeatureState"] = "[NgssmStoreActionType] unregisterFeatureState";
392
306
  })(NgssmStoreActionType || (NgssmStoreActionType = {}));
393
-
394
- class NgssmRegisterFeatureStateAction {
395
- featureStateKey;
396
- initialValue;
397
- type = NgssmStoreActionType.registerFeatureState;
398
- constructor(featureStateKey, initialValue) {
399
- this.featureStateKey = featureStateKey;
400
- this.initialValue = initialValue;
401
- }
402
- }
403
-
404
- class NgssmUnregisterFeatureStateAction {
405
- featureStateKey;
406
- type = NgssmStoreActionType.unregisterFeatureState;
407
- constructor(featureStateKey) {
408
- this.featureStateKey = featureStateKey;
409
- }
410
- }
411
-
307
+ var NgssmRegisterFeatureStateAction = class {
308
+ featureStateKey;
309
+ initialValue;
310
+ type = NgssmStoreActionType.registerFeatureState;
311
+ constructor(featureStateKey, initialValue) {
312
+ this.featureStateKey = featureStateKey;
313
+ this.initialValue = initialValue;
314
+ }
315
+ };
316
+ var NgssmUnregisterFeatureStateAction = class {
317
+ featureStateKey;
318
+ type = NgssmStoreActionType.unregisterFeatureState;
319
+ constructor(featureStateKey) {
320
+ this.featureStateKey = featureStateKey;
321
+ }
322
+ };
412
323
  const registerFeatureState = (featureStateKey, initialValue) => {
413
- return () => {
414
- inject(Store).dispatchAction(new NgssmRegisterFeatureStateAction(featureStateKey, initialValue));
415
- };
324
+ return () => {
325
+ inject(Store).dispatchAction(new NgssmRegisterFeatureStateAction(featureStateKey, initialValue));
326
+ };
416
327
  };
417
328
  const provideNgssmFeatureState = (featureStateKey, initialValue) => {
418
- return makeEnvironmentProviders([provideAppInitializer(registerFeatureState(featureStateKey, initialValue))]);
329
+ return makeEnvironmentProviders([provideAppInitializer(registerFeatureState(featureStateKey, initialValue))]);
419
330
  };
420
-
421
- // export interface ComponentWithFeatureState {
422
- // featureStateKey: string;
423
- // initialValue: object;
424
- // }
425
- // export const NGSSM_COMPONENT_WITH_FEATURE_STATE = new InjectionToken<ComponentWithFeatureState>('NGSSM_COMPONENT_WITH_FEATURE_STATE');
426
- class ProvideNgssmFeatureStateDirective {
427
- component = inject(NGSSM_COMPONENT_WITH_FEATURE_STATE);
428
- store = inject(Store);
429
- constructor() {
430
- this.store.dispatchAction(new NgssmRegisterFeatureStateAction(this.component.featureStateKey, this.component.initialState));
431
- }
432
- ngOnDestroy() {
433
- this.store.dispatchAction(new NgssmUnregisterFeatureStateAction(this.component.featureStateKey));
434
- }
435
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideNgssmFeatureStateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
436
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ProvideNgssmFeatureStateDirective, isStandalone: true, selector: "[provideNgssmFeatureState]", ngImport: i0 });
437
- }
438
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideNgssmFeatureStateDirective, decorators: [{
439
- type: Directive,
440
- args: [{
441
- // eslint-disable-next-line @angular-eslint/directive-selector
442
- selector: '[provideNgssmFeatureState]'
443
- }]
444
- }], ctorParameters: () => [] });
445
-
446
- class FeatureStateReducer {
447
- processedActions = [NgssmStoreActionType.registerFeatureState, NgssmStoreActionType.unregisterFeatureState];
448
- updateState(state, action) {
449
- switch (action.type) {
450
- case NgssmStoreActionType.registerFeatureState: {
451
- const registerFeatureStateAction = action;
452
- return update(state, {
453
- [registerFeatureStateAction.featureStateKey]: { $set: registerFeatureStateAction.initialValue }
454
- });
455
- }
456
- case NgssmStoreActionType.unregisterFeatureState: {
457
- const unregisterFeatureStateAction = action;
458
- return update(state, {
459
- $unset: [unregisterFeatureStateAction.featureStateKey]
460
- });
461
- }
462
- }
463
- return state;
464
- }
465
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FeatureStateReducer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
466
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FeatureStateReducer });
467
- }
468
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: FeatureStateReducer, decorators: [{
469
- type: Injectable
470
- }] });
471
-
472
- class NgSsmComponent {
473
- store = inject(Store);
474
- _unsubscribeAll$ = new Subject();
475
- get unsubscribeAll$() {
476
- return this._unsubscribeAll$.asObservable();
477
- }
478
- ngOnDestroy() {
479
- this._unsubscribeAll$.next();
480
- this._unsubscribeAll$.complete();
481
- }
482
- watch(selector) {
483
- return this.store.state$.pipe(map((state) => selector(state)), distinctUntilChanged(), takeUntil(this.unsubscribeAll$));
484
- }
485
- dispatchAction(action) {
486
- this.store.dispatchAction(action);
487
- }
488
- dispatchActionType(actionType) {
489
- this.store.dispatchActionType(actionType);
490
- }
491
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgSsmComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
492
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: NgSsmComponent, isStandalone: true, ngImport: i0 });
493
- }
494
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgSsmComponent, decorators: [{
495
- type: Directive,
496
- args: [{}]
497
- }] });
498
-
499
- const ACTION_DISPATCHER = new InjectionToken('ACTION_DISPATCHER');
331
+ var ProvideNgssmFeatureStateDirective = class ProvideNgssmFeatureStateDirective {
332
+ component = inject(NGSSM_COMPONENT_WITH_FEATURE_STATE);
333
+ store = inject(Store);
334
+ constructor() {
335
+ this.store.dispatchAction(new NgssmRegisterFeatureStateAction(this.component.featureStateKey, this.component.initialState));
336
+ }
337
+ ngOnDestroy() {
338
+ this.store.dispatchAction(new NgssmUnregisterFeatureStateAction(this.component.featureStateKey));
339
+ }
340
+ static ɵfac = i0.ɵɵngDeclareFactory({
341
+ minVersion: "12.0.0",
342
+ version: "22.2.0",
343
+ ngImport: i0,
344
+ type: ProvideNgssmFeatureStateDirective,
345
+ deps: [],
346
+ target: i0.ɵɵFactoryTarget.Directive
347
+ });
348
+ static ɵdir = i0.ɵɵngDeclareDirective({
349
+ minVersion: "14.0.0",
350
+ version: "22.2.0",
351
+ type: ProvideNgssmFeatureStateDirective,
352
+ isStandalone: true,
353
+ selector: "[provideNgssmFeatureState]",
354
+ ngImport: i0
355
+ });
356
+ };
357
+ i0.ɵɵngDeclareClassMetadata({
358
+ minVersion: "12.0.0",
359
+ version: "22.2.0",
360
+ ngImport: i0,
361
+ type: ProvideNgssmFeatureStateDirective,
362
+ decorators: [{
363
+ type: Directive,
364
+ args: [{ selector: "[provideNgssmFeatureState]" }]
365
+ }],
366
+ ctorParameters: () => []
367
+ });
368
+ var FeatureStateReducer = class FeatureStateReducer {
369
+ processedActions = [NgssmStoreActionType.registerFeatureState, NgssmStoreActionType.unregisterFeatureState];
370
+ updateState(state, action) {
371
+ switch (action.type) {
372
+ case NgssmStoreActionType.registerFeatureState: {
373
+ const registerFeatureStateAction = action;
374
+ return update(state, { [registerFeatureStateAction.featureStateKey]: { $set: registerFeatureStateAction.initialValue } });
375
+ }
376
+ case NgssmStoreActionType.unregisterFeatureState: return update(state, { $unset: [action.featureStateKey] });
377
+ }
378
+ return state;
379
+ }
380
+ static ɵfac = i0.ɵɵngDeclareFactory({
381
+ minVersion: "12.0.0",
382
+ version: "22.2.0",
383
+ ngImport: i0,
384
+ type: FeatureStateReducer,
385
+ deps: [],
386
+ target: i0.ɵɵFactoryTarget.Injectable
387
+ });
388
+ static ɵprov = i0.ɵɵngDeclareInjectable({
389
+ minVersion: "12.0.0",
390
+ version: "22.2.0",
391
+ ngImport: i0,
392
+ type: FeatureStateReducer
393
+ });
394
+ };
395
+ i0.ɵɵngDeclareClassMetadata({
396
+ minVersion: "12.0.0",
397
+ version: "22.2.0",
398
+ ngImport: i0,
399
+ type: FeatureStateReducer,
400
+ decorators: [{ type: Injectable }]
401
+ });
402
+ const ACTION_DISPATCHER = new InjectionToken("ACTION_DISPATCHER");
500
403
  const provideNgssmStore = () => {
501
- return makeEnvironmentProviders([provideReducers(FeatureStateReducer), { provide: ACTION_DISPATCHER, useExisting: Store }]);
404
+ return makeEnvironmentProviders([provideReducers(FeatureStateReducer), {
405
+ provide: ACTION_DISPATCHER,
406
+ useExisting: Store
407
+ }]);
502
408
  };
503
-
504
409
  const createSignal = (selector) => {
505
- const store = inject(Store);
506
- return computed(() => selector(store.state()));
410
+ const store = inject(Store);
411
+ return computed(() => selector(store.state()));
507
412
  };
413
+ export { ACTION_DISPATCHER, ConsoleAppender, FeatureStateReducer, LogLevel, Logger, NGSSM_COMPONENT_WITH_FEATURE_STATE, NGSSM_CONSOLE_APPENDER_NAME, NGSSM_EFFECT, NGSSM_REDUCER, NGSSM_STATE_INITIALIZER, NgSsmFeatureState, NgssmRegisterFeatureStateAction, NgssmStoreActionType, NgssmUnregisterFeatureStateAction, ProvideNgssmFeatureStateDirective, Store, createSignal, provideConsoleAppender, provideEffect, provideEffectFunc, provideEffects, provideNgssmFeatureState, provideNgssmStore, provideReducer, provideReducers, startConsoleAppenderFactory };
508
414
 
509
- /*
510
- * Public API Surface of ngssm-store
511
- */
512
-
513
- /**
514
- * Generated bundle index. Do not edit.
515
- */
516
-
517
- export { ACTION_DISPATCHER, ConsoleAppender, FeatureStateReducer, LogLevel, Logger, NGSSM_COMPONENT_WITH_FEATURE_STATE, NGSSM_CONSOLE_APPENDER_NAME, NGSSM_EFFECT, NGSSM_REDUCER, NGSSM_STATE_INITIALIZER, NgSsmComponent, NgSsmFeatureState, NgssmRegisterFeatureStateAction, NgssmStoreActionType, NgssmUnregisterFeatureStateAction, ProvideNgssmFeatureStateDirective, Store, createSignal, provideConsoleAppender, provideEffect, provideEffectFunc, provideEffects, provideNgssmFeatureState, provideNgssmStore, provideReducer, provideReducers, startConsoleAppenderFactory };
518
- //# sourceMappingURL=ngssm-store.mjs.map
415
+ //# sourceMappingURL=ngssm-store.mjs.map