@ngxs/store 18.1.1-dev.master-2833d17 → 18.1.1-dev.master-a8f62df
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.
- package/esm2022/src/internal/lifecycle-state-manager.mjs +2 -2
- package/esm2022/src/internal/state-context-factory.mjs +6 -6
- package/esm2022/src/internal/state-factory.mjs +78 -48
- package/esm2022/src/plugin-manager.mjs +15 -19
- package/esm2022/src/standalone-features/plugin.mjs +10 -3
- package/fesm2022/ngxs-store.mjs +104 -72
- package/fesm2022/ngxs-store.mjs.map +1 -1
- package/package.json +1 -1
- package/src/internal/state-context-factory.d.ts +1 -2
- package/src/internal/state-factory.d.ts +10 -2
- package/src/plugin-manager.d.ts +7 -7
package/fesm2022/ngxs-store.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, NgZone, PLATFORM_ID, Inject, InjectionToken, inject, INJECTOR,
|
|
2
|
+
import { Injectable, NgZone, PLATFORM_ID, Inject, InjectionToken, inject, INJECTOR, ErrorHandler, ɵisPromise as _isPromise, Optional, SkipSelf, computed, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule, APP_BOOTSTRAP_LISTENER } from '@angular/core';
|
|
3
3
|
import { Observable, config, Subject, of, forkJoin, throwError, EMPTY, from, isObservable, shareReplay as shareReplay$1, map as map$1, catchError as catchError$1, distinctUntilChanged, take as take$1, ReplaySubject } from 'rxjs';
|
|
4
4
|
import * as i1 from '@ngxs/store/internals';
|
|
5
5
|
import { ɵwrapObserverCalls as _wrapObserverCalls, ɵOrderedSubject as _OrderedSubject, ɵmemoize as _memoize, ɵgetStoreMetadata as _getStoreMetadata, ɵgetSelectorMetadata as _getSelectorMetadata, ɵMETA_KEY as _META_KEY, ɵINITIAL_STATE_TOKEN as _INITIAL_STATE_TOKEN, ɵNgxsAppBootstrappedState as _NgxsAppBootstrappedState, ɵNGXS_STATE_CONTEXT_FACTORY as _NGXS_STATE_CONTEXT_FACTORY, ɵNGXS_STATE_FACTORY as _NGXS_STATE_FACTORY, ɵensureStoreMetadata as _ensureStoreMetadata, ɵMETA_OPTIONS_KEY as _META_OPTIONS_KEY, ɵensureSelectorMetadata as _ensureSelectorMetadata } from '@ngxs/store/internals';
|
|
@@ -250,38 +250,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImpor
|
|
|
250
250
|
}], ctorParameters: () => [{ type: InternalActions }, { type: InternalNgxsExecutionStrategy }] });
|
|
251
251
|
|
|
252
252
|
class PluginManager {
|
|
253
|
-
constructor(
|
|
254
|
-
this._parentManager = _parentManager;
|
|
255
|
-
this._pluginHandlers = _pluginHandlers;
|
|
253
|
+
constructor() {
|
|
256
254
|
this.plugins = [];
|
|
255
|
+
this._parentManager = inject(PluginManager, {
|
|
256
|
+
optional: true,
|
|
257
|
+
skipSelf: true
|
|
258
|
+
});
|
|
259
|
+
this._pluginHandlers = inject(NGXS_PLUGINS, {
|
|
260
|
+
optional: true
|
|
261
|
+
});
|
|
257
262
|
this.registerHandlers();
|
|
258
263
|
}
|
|
259
|
-
get
|
|
260
|
-
return
|
|
264
|
+
get _rootPlugins() {
|
|
265
|
+
return this._parentManager?.plugins || this.plugins;
|
|
261
266
|
}
|
|
262
267
|
registerHandlers() {
|
|
263
268
|
const pluginHandlers = this.getPluginHandlers();
|
|
264
|
-
this.
|
|
269
|
+
this._rootPlugins.push(...pluginHandlers);
|
|
265
270
|
}
|
|
266
271
|
getPluginHandlers() {
|
|
267
272
|
const handlers = this._pluginHandlers || [];
|
|
268
273
|
return handlers.map((plugin) => (plugin.handle ? plugin.handle.bind(plugin) : plugin));
|
|
269
274
|
}
|
|
270
|
-
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: PluginManager, deps: [
|
|
275
|
+
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: PluginManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
271
276
|
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: PluginManager }); }
|
|
272
277
|
}
|
|
273
278
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: PluginManager, decorators: [{
|
|
274
279
|
type: Injectable
|
|
275
|
-
}], ctorParameters: () => [
|
|
276
|
-
type: Optional
|
|
277
|
-
}, {
|
|
278
|
-
type: SkipSelf
|
|
279
|
-
}] }, { type: undefined, decorators: [{
|
|
280
|
-
type: Inject,
|
|
281
|
-
args: [NGXS_PLUGINS]
|
|
282
|
-
}, {
|
|
283
|
-
type: Optional
|
|
284
|
-
}] }] });
|
|
280
|
+
}], ctorParameters: () => [] });
|
|
285
281
|
|
|
286
282
|
const ɵɵunhandledRxjsErrorCallbacks = new WeakMap();
|
|
287
283
|
const existingHandler = config.onUnhandledError;
|
|
@@ -1025,25 +1021,25 @@ class StateContextFactory {
|
|
|
1025
1021
|
/**
|
|
1026
1022
|
* Create the state context
|
|
1027
1023
|
*/
|
|
1028
|
-
createStateContext(
|
|
1024
|
+
createStateContext(path) {
|
|
1029
1025
|
const root = this._internalStateOperations.getRootStateOperations();
|
|
1030
1026
|
return {
|
|
1031
1027
|
getState() {
|
|
1032
1028
|
const currentAppState = root.getState();
|
|
1033
|
-
return getState(currentAppState,
|
|
1029
|
+
return getState(currentAppState, path);
|
|
1034
1030
|
},
|
|
1035
1031
|
patchState(val) {
|
|
1036
1032
|
const currentAppState = root.getState();
|
|
1037
1033
|
const patchOperator = simplePatch(val);
|
|
1038
|
-
setStateFromOperator(root, currentAppState, patchOperator,
|
|
1034
|
+
setStateFromOperator(root, currentAppState, patchOperator, path);
|
|
1039
1035
|
},
|
|
1040
1036
|
setState(val) {
|
|
1041
1037
|
const currentAppState = root.getState();
|
|
1042
1038
|
if (isStateOperator(val)) {
|
|
1043
|
-
setStateFromOperator(root, currentAppState, val,
|
|
1039
|
+
setStateFromOperator(root, currentAppState, val, path);
|
|
1044
1040
|
}
|
|
1045
1041
|
else {
|
|
1046
|
-
setStateValue(root, currentAppState, val,
|
|
1042
|
+
setStateValue(root, currentAppState, val, path);
|
|
1047
1043
|
}
|
|
1048
1044
|
},
|
|
1049
1045
|
dispatch(actions) {
|
|
@@ -1237,6 +1233,12 @@ class StateFactory {
|
|
|
1237
1233
|
this._actionsSubscription = null;
|
|
1238
1234
|
this._propGetter = inject(ɵPROP_GETTER);
|
|
1239
1235
|
this._ngxsUnhandledErrorHandler = null;
|
|
1236
|
+
// Instead of going over the states list every time an action is dispatched,
|
|
1237
|
+
// we are constructing a map of action types to lists of action metadata.
|
|
1238
|
+
// If the `@@Init` action is handled in two different states, the action
|
|
1239
|
+
// metadata list will contain two objects that have the state `instance` and
|
|
1240
|
+
// method names to be used as action handlers (decorated with `@Action(InitState)`).
|
|
1241
|
+
this._actionTypeToMetasMap = new Map();
|
|
1240
1242
|
this._states = [];
|
|
1241
1243
|
this._statesByName = {};
|
|
1242
1244
|
this._statePaths = {};
|
|
@@ -1277,6 +1279,11 @@ class StateFactory {
|
|
|
1277
1279
|
return context;
|
|
1278
1280
|
});
|
|
1279
1281
|
}
|
|
1282
|
+
get actionTypeToMetasMap() {
|
|
1283
|
+
return this._parentFactory
|
|
1284
|
+
? this._parentFactory.actionTypeToMetasMap
|
|
1285
|
+
: this._actionTypeToMetasMap;
|
|
1286
|
+
}
|
|
1280
1287
|
get states() {
|
|
1281
1288
|
return this._parentFactory ? this._parentFactory.states : this._states;
|
|
1282
1289
|
}
|
|
@@ -1331,6 +1338,7 @@ class StateFactory {
|
|
|
1331
1338
|
bootstrappedStores.push(stateMap);
|
|
1332
1339
|
}
|
|
1333
1340
|
this.states.push(stateMap);
|
|
1341
|
+
this.hydrateActionMetasMap(stateMap);
|
|
1334
1342
|
}
|
|
1335
1343
|
return bootstrappedStores;
|
|
1336
1344
|
}
|
|
@@ -1377,55 +1385,53 @@ class StateFactory {
|
|
|
1377
1385
|
// Determines whether the dispatched action has been handled, this is assigned
|
|
1378
1386
|
// to `true` within the below `for` loop if any `actionMetas` has been found.
|
|
1379
1387
|
let actionHasBeenHandled = false;
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
// action will be canceled.
|
|
1401
|
-
// For instance if any action handler would've had such statement:
|
|
1402
|
-
// `handler(ctx) { return EMPTY; }`
|
|
1403
|
-
// then the action will be canceled.
|
|
1404
|
-
// See https://github.com/ngxs/store/issues/1568
|
|
1405
|
-
result = result.pipe(mergeMap((value) => {
|
|
1406
|
-
if (_isPromise(value)) {
|
|
1407
|
-
return from(value);
|
|
1408
|
-
}
|
|
1409
|
-
if (isObservable(value)) {
|
|
1410
|
-
return value;
|
|
1411
|
-
}
|
|
1412
|
-
return of(value);
|
|
1413
|
-
}), defaultIfEmpty({}));
|
|
1414
|
-
if (actionMeta.options.cancelUncompleted) {
|
|
1415
|
-
// todo: ofActionDispatched should be used with action class
|
|
1416
|
-
result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
|
|
1388
|
+
const actionMetas = this.actionTypeToMetasMap.get(type);
|
|
1389
|
+
if (actionMetas) {
|
|
1390
|
+
for (const actionMeta of actionMetas) {
|
|
1391
|
+
const stateContext = this._stateContextFactory.createStateContext(actionMeta.path);
|
|
1392
|
+
let result;
|
|
1393
|
+
try {
|
|
1394
|
+
result = actionMeta.instance[actionMeta.fn](stateContext, action);
|
|
1395
|
+
// We need to use `isPromise` instead of checking whether
|
|
1396
|
+
// `result instanceof Promise`. In zone.js patched environments, `global.Promise`
|
|
1397
|
+
// is the `ZoneAwarePromise`. Some APIs, which are likely not patched by zone.js
|
|
1398
|
+
// for certain reasons, might not work with `instanceof`. For instance, the dynamic
|
|
1399
|
+
// import returns a native promise (not a `ZoneAwarePromise`), causing this check to
|
|
1400
|
+
// be falsy.
|
|
1401
|
+
if (_isPromise(result)) {
|
|
1402
|
+
result = from(result);
|
|
1403
|
+
}
|
|
1404
|
+
if (isObservable(result)) {
|
|
1405
|
+
result = result.pipe(mergeMap((value) => {
|
|
1406
|
+
if (_isPromise(value)) {
|
|
1407
|
+
return from(value);
|
|
1417
1408
|
}
|
|
1409
|
+
if (isObservable(value)) {
|
|
1410
|
+
return value;
|
|
1411
|
+
}
|
|
1412
|
+
return of(value);
|
|
1413
|
+
}),
|
|
1414
|
+
// If this observable has completed without emitting any values,
|
|
1415
|
+
// we wouldn't want to complete the entire chain of actions.
|
|
1416
|
+
// If any observable completes, then the action will be canceled.
|
|
1417
|
+
// For instance, if any action handler had a statement like
|
|
1418
|
+
// `handler(ctx) { return EMPTY; }`, then the action would be canceled.
|
|
1419
|
+
// See https://github.com/ngxs/store/issues/1568
|
|
1420
|
+
defaultIfEmpty({}));
|
|
1421
|
+
if (actionMeta.options.cancelUncompleted) {
|
|
1422
|
+
// todo: ofActionDispatched should be used with action class
|
|
1423
|
+
result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
|
|
1418
1424
|
}
|
|
1419
|
-
else {
|
|
1420
|
-
result = of({}).pipe(shareReplay());
|
|
1421
|
-
}
|
|
1422
|
-
results.push(result);
|
|
1423
1425
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
+
else {
|
|
1427
|
+
result = of({}).pipe(shareReplay());
|
|
1426
1428
|
}
|
|
1427
|
-
actionHasBeenHandled = true;
|
|
1428
1429
|
}
|
|
1430
|
+
catch (e) {
|
|
1431
|
+
result = throwError(e);
|
|
1432
|
+
}
|
|
1433
|
+
results.push(result);
|
|
1434
|
+
actionHasBeenHandled = true;
|
|
1429
1435
|
}
|
|
1430
1436
|
}
|
|
1431
1437
|
// The `NgxsUnhandledActionsLogger` is a tree-shakable class which functions
|
|
@@ -1435,9 +1441,7 @@ class StateFactory {
|
|
|
1435
1441
|
// The `NgxsUnhandledActionsLogger` will not be resolved by the injector if the
|
|
1436
1442
|
// `NgxsDevelopmentModule` is not provided. It's enough to check whether the `injector.get`
|
|
1437
1443
|
// didn't return `null` so we may ensure the module has been imported.
|
|
1438
|
-
|
|
1439
|
-
unhandledActionsLogger.warn(action);
|
|
1440
|
-
}
|
|
1444
|
+
unhandledActionsLogger?.warn(action);
|
|
1441
1445
|
}
|
|
1442
1446
|
if (!results.length) {
|
|
1443
1447
|
results.push(of({}));
|
|
@@ -1473,6 +1477,28 @@ class StateFactory {
|
|
|
1473
1477
|
// its lifecycle is in 'bootstrapped' state.
|
|
1474
1478
|
return this.statesByName[name] && valueIsBootstrappedInInitialState;
|
|
1475
1479
|
}
|
|
1480
|
+
hydrateActionMetasMap({ path, actions, instance }) {
|
|
1481
|
+
const actionTypeToMetasMap = this.actionTypeToMetasMap;
|
|
1482
|
+
for (const actionType of Object.keys(actions)) {
|
|
1483
|
+
// Initialize the map entry if it does not already exist for that
|
|
1484
|
+
// action type. Note that action types may overlap between states,
|
|
1485
|
+
// as the same action can be handled by different states.
|
|
1486
|
+
if (!actionTypeToMetasMap.has(actionType)) {
|
|
1487
|
+
actionTypeToMetasMap.set(actionType, []);
|
|
1488
|
+
}
|
|
1489
|
+
const extendedActionMetas = actionTypeToMetasMap.get(actionType);
|
|
1490
|
+
extendedActionMetas.push(
|
|
1491
|
+
// This involves combining each individual action metadata with
|
|
1492
|
+
// the state instance and the path—essentially everything needed
|
|
1493
|
+
// to invoke an action. This eliminates the need to loop over states
|
|
1494
|
+
// every time an action is dispatched.
|
|
1495
|
+
...actions[actionType].map(actionMeta => ({
|
|
1496
|
+
...actionMeta,
|
|
1497
|
+
path,
|
|
1498
|
+
instance
|
|
1499
|
+
})));
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1476
1502
|
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory, deps: [{ token: i0.Injector }, { token: NgxsConfig }, { token: StateFactory, optional: true, skipSelf: true }, { token: InternalActions }, { token: InternalDispatchedActionResults }, { token: StateContextFactory }, { token: _INITIAL_STATE_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1477
1503
|
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory }); }
|
|
1478
1504
|
}
|
|
@@ -1705,7 +1731,7 @@ class LifecycleStateManager {
|
|
|
1705
1731
|
}
|
|
1706
1732
|
}
|
|
1707
1733
|
_getStateContext(mappedStore) {
|
|
1708
|
-
return this._stateContextFactory.createStateContext(mappedStore);
|
|
1734
|
+
return this._stateContextFactory.createStateContext(mappedStore.path);
|
|
1709
1735
|
}
|
|
1710
1736
|
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: LifecycleStateManager, deps: [{ token: Store }, { token: InternalStateOperations }, { token: StateContextFactory }, { token: i1.ɵNgxsAppBootstrappedState }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1711
1737
|
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: LifecycleStateManager, providedIn: 'root' }); }
|
|
@@ -2293,7 +2319,13 @@ function provideStates(states, ...features) {
|
|
|
2293
2319
|
* ```
|
|
2294
2320
|
*/
|
|
2295
2321
|
function withNgxsPlugin(plugin) {
|
|
2296
|
-
return makeEnvironmentProviders([
|
|
2322
|
+
return makeEnvironmentProviders([
|
|
2323
|
+
{ provide: NGXS_PLUGINS, useClass: plugin, multi: true },
|
|
2324
|
+
// We should inject the `PluginManager` to retrieve `NGXS_PLUGINS` and
|
|
2325
|
+
// register those plugins. The plugin can be added from inside the child
|
|
2326
|
+
// route, so the plugin manager should be re-injected.
|
|
2327
|
+
{ provide: ENVIRONMENT_INITIALIZER, useValue: () => inject(PluginManager), multi: true }
|
|
2328
|
+
]);
|
|
2297
2329
|
}
|
|
2298
2330
|
|
|
2299
2331
|
/**
|