@angular-architects/ngrx-toolkit 20.0.3 → 20.3.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,9 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, signal, effect, inject, PLATFORM_ID, computed, isSignal, untracked, isDevMode as isDevMode$1 } from '@angular/core';
3
- import { watchState, getState, signalStoreFeature, withMethods, withHooks, patchState as patchState$1, withState, withComputed, withProps } from '@ngrx/signals';
2
+ import { Injectable, InjectionToken, signal, effect, inject, PLATFORM_ID, computed, isSignal, untracked, isDevMode as isDevMode$1, DestroyRef } from '@angular/core';
3
+ import { watchState, getState, signalStoreFeature, withMethods, withHooks, patchState as patchState$1, withState, withComputed, withProps, withLinkedState } from '@ngrx/signals';
4
4
  import { isPlatformBrowser, isPlatformServer } from '@angular/common';
5
- import { Subject } from 'rxjs';
5
+ import { Subject, switchMap, mergeMap, concatMap, exhaustMap, defer, tap, catchError, EMPTY, finalize } from 'rxjs';
6
6
  import { removeEntity, setAllEntities, updateEntity, addEntity } from '@ngrx/signals/entities';
7
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
8
 
8
9
  const DEVTOOLS_FEATURE = Symbol('DEVTOOLS_FEATURE');
9
10
  function createDevtoolsFeature(options) {
@@ -1781,9 +1782,287 @@ function withFeatureFactory(factoryFn) {
1781
1782
  };
1782
1783
  }
1783
1784
 
1785
+ const switchOp = {
1786
+ rxJsOperator: switchMap,
1787
+ exhaustSemantics: false,
1788
+ };
1789
+ const mergeOp = {
1790
+ rxJsOperator: mergeMap,
1791
+ exhaustSemantics: false,
1792
+ };
1793
+ const concatOp = {
1794
+ rxJsOperator: concatMap,
1795
+ exhaustSemantics: false,
1796
+ };
1797
+ const exhaustOp = {
1798
+ rxJsOperator: exhaustMap,
1799
+ exhaustSemantics: true,
1800
+ };
1801
+
1802
+ /**
1803
+ * Creates a mutation that leverages RxJS.
1804
+ *
1805
+ * For each mutation the following options can be defined:
1806
+ * - `operation`: A function that defines the mutation logic. It returns an Observable.
1807
+ * - `onSuccess`: A callback that is called when the mutation is successful.
1808
+ * - `onError`: A callback that is called when the mutation fails.
1809
+ * - `operator`: An optional wrapper of an RxJS flattening operator. By default `concat` sematics are used.
1810
+ * - `injector`: An optional Angular injector to use for dependency injection.
1811
+ *
1812
+ * The `operation` is the only mandatory option.
1813
+ *
1814
+ * ```typescript
1815
+ * export type Params = {
1816
+ * value: number;
1817
+ * };
1818
+ *
1819
+ * export const CounterStore = signalStore(
1820
+ * { providedIn: 'root' },
1821
+ * withState({ counter: 0 }),
1822
+ * withMutations((store) => ({
1823
+ * increment: rxMutation({
1824
+ * operation: (params: Params) => {
1825
+ * return calcSum(store.counter(), params.value);
1826
+ * },
1827
+ * operator: concatOp,
1828
+ * onSuccess: (result) => {
1829
+ * console.log('result', result);
1830
+ * patchState(store, { counter: result });
1831
+ * },
1832
+ * onError: (error) => {
1833
+ * console.error('Error occurred:', error);
1834
+ * },
1835
+ * }),
1836
+ * })),
1837
+ * );
1838
+ *
1839
+ * function calcSum(a: number, b: number): Observable<number> {
1840
+ * return of(a + b);
1841
+ * }
1842
+ * ```
1843
+ *
1844
+ * @param options
1845
+ * @returns
1846
+ */
1847
+ function rxMutation(options) {
1848
+ const inputSubject = new Subject();
1849
+ const flatteningOp = options.operator ?? concatOp;
1850
+ const destroyRef = options.injector?.get(DestroyRef) ?? inject(DestroyRef);
1851
+ const callCount = signal(0, ...(ngDevMode ? [{ debugName: "callCount" }] : []));
1852
+ const errorSignal = signal(undefined, ...(ngDevMode ? [{ debugName: "errorSignal" }] : []));
1853
+ const idle = signal(true, ...(ngDevMode ? [{ debugName: "idle" }] : []));
1854
+ const isPending = computed(() => callCount() > 0, ...(ngDevMode ? [{ debugName: "isPending" }] : []));
1855
+ const status = computed(() => {
1856
+ if (idle()) {
1857
+ return 'idle';
1858
+ }
1859
+ if (callCount() > 0) {
1860
+ return 'pending';
1861
+ }
1862
+ if (errorSignal()) {
1863
+ return 'error';
1864
+ }
1865
+ return 'success';
1866
+ }, ...(ngDevMode ? [{ debugName: "status" }] : []));
1867
+ const initialInnerStatus = 'idle';
1868
+ let innerStatus = initialInnerStatus;
1869
+ let lastResult;
1870
+ inputSubject
1871
+ .pipe(flatteningOp.rxJsOperator((input) => defer(() => {
1872
+ callCount.update((c) => c + 1);
1873
+ idle.set(false);
1874
+ return options.operation(input.param).pipe(tap((result) => {
1875
+ options.onSuccess?.(result, input.param);
1876
+ innerStatus = 'success';
1877
+ errorSignal.set(undefined);
1878
+ lastResult = result;
1879
+ }), catchError((error) => {
1880
+ options.onError?.(error, input.param);
1881
+ errorSignal.set(error);
1882
+ innerStatus = 'error';
1883
+ return EMPTY;
1884
+ }), finalize(() => {
1885
+ callCount.update((c) => c - 1);
1886
+ if (innerStatus === 'success') {
1887
+ input.resolve({
1888
+ status: 'success',
1889
+ value: lastResult,
1890
+ });
1891
+ }
1892
+ else if (innerStatus === 'error') {
1893
+ input.resolve({
1894
+ status: 'error',
1895
+ error: errorSignal(),
1896
+ });
1897
+ }
1898
+ else {
1899
+ input.resolve({
1900
+ status: 'aborted',
1901
+ });
1902
+ }
1903
+ innerStatus = initialInnerStatus;
1904
+ }));
1905
+ })), takeUntilDestroyed(destroyRef))
1906
+ .subscribe();
1907
+ const mutationFn = (param) => {
1908
+ return new Promise((resolve) => {
1909
+ if (callCount() > 0 && flatteningOp.exhaustSemantics) {
1910
+ resolve({
1911
+ status: 'aborted',
1912
+ });
1913
+ }
1914
+ else {
1915
+ inputSubject.next({
1916
+ param,
1917
+ resolve,
1918
+ });
1919
+ }
1920
+ });
1921
+ };
1922
+ const mutation = mutationFn;
1923
+ mutation.status = status;
1924
+ mutation.isPending = isPending;
1925
+ mutation.error = errorSignal;
1926
+ return mutation;
1927
+ }
1928
+
1929
+ function withMutations(mutationsFactory) {
1930
+ return (store) => {
1931
+ // TODO: Is this the correct usage?
1932
+ const source = store;
1933
+ const mutations = mutationsFactory({
1934
+ ...source,
1935
+ ...store.props,
1936
+ ...store.methods,
1937
+ ...store.stateSignals,
1938
+ });
1939
+ const feature = createMutationsFeature(mutations);
1940
+ return feature(store);
1941
+ };
1942
+ }
1943
+ function createMutationsFeature(mutations) {
1944
+ const keys = Object.keys(mutations);
1945
+ const feature = signalStoreFeature(withMethods(() => keys.reduce((acc, key) => ({
1946
+ ...acc,
1947
+ [key]: async (params) => {
1948
+ const mutation = mutations[key];
1949
+ if (!mutation) {
1950
+ throw new Error(`Mutation ${key} not found`);
1951
+ }
1952
+ const result = await mutation(params);
1953
+ return result;
1954
+ },
1955
+ }), {})), withComputed(() => keys.reduce((acc, key) => ({
1956
+ ...acc,
1957
+ [`${key}IsPending`]: mutations[key].isPending,
1958
+ [`${key}Status`]: mutations[key].status,
1959
+ [`${key}Error`]: mutations[key].error,
1960
+ }), {})));
1961
+ return feature;
1962
+ }
1963
+
1964
+ //** Types for `withResource` */
1965
+ function withResource(resourceFactory) {
1966
+ return (store) => {
1967
+ const resourceOrDictionary = resourceFactory({
1968
+ ...store.stateSignals,
1969
+ ...store.props,
1970
+ ...store.methods,
1971
+ });
1972
+ if (isResourceRef(resourceOrDictionary)) {
1973
+ return createUnnamedResource(resourceOrDictionary)(store);
1974
+ }
1975
+ else {
1976
+ return createNamedResource(resourceOrDictionary)(store);
1977
+ }
1978
+ };
1979
+ }
1980
+ function createUnnamedResource(resource) {
1981
+ function hasValue() {
1982
+ return resource.hasValue();
1983
+ }
1984
+ return signalStoreFeature(withLinkedState(() => ({ value: resource.value })), withProps(() => ({
1985
+ status: resource.status,
1986
+ error: resource.error,
1987
+ isLoading: resource.isLoading,
1988
+ })), withMethods(() => ({
1989
+ hasValue,
1990
+ _reload: () => resource.reload(),
1991
+ })));
1992
+ }
1993
+ function createNamedResource(dictionary) {
1994
+ const keys = Object.keys(dictionary);
1995
+ const state = keys.reduce((state, resourceName) => ({
1996
+ ...state,
1997
+ [`${resourceName}Value`]: dictionary[resourceName].value,
1998
+ }), {});
1999
+ const props = keys.reduce((props, resourceName) => ({
2000
+ ...props,
2001
+ [`${resourceName}Status`]: dictionary[resourceName].status,
2002
+ [`${resourceName}Error`]: dictionary[resourceName].error,
2003
+ [`${resourceName}IsLoading`]: dictionary[resourceName].isLoading,
2004
+ }), {});
2005
+ const methods = keys.reduce((methods, resourceName) => {
2006
+ return {
2007
+ ...methods,
2008
+ [`${resourceName}HasValue`]: () => dictionary[resourceName].hasValue(),
2009
+ [`_${resourceName}Reload`]: () => dictionary[resourceName].reload(),
2010
+ };
2011
+ }, {});
2012
+ return signalStoreFeature(withLinkedState(() => state), withProps(() => props), withMethods(() => methods));
2013
+ }
2014
+ function isResourceRef(value) {
2015
+ return (value !== null &&
2016
+ typeof value === 'object' &&
2017
+ 'value' in value &&
2018
+ isSignal(value.value) &&
2019
+ 'status' in value &&
2020
+ 'error' in value &&
2021
+ 'isLoading' in value &&
2022
+ 'hasValue' in value &&
2023
+ 'reload' in value);
2024
+ }
2025
+ //** Implementation of `mapToResource` */
2026
+ /**
2027
+ * @experimental
2028
+ * @description
2029
+ *
2030
+ * Maps a named resource to type `Resource<T>`.
2031
+ *
2032
+ * @usageNotes
2033
+ *
2034
+ * ```ts
2035
+ * const store = signalStore(
2036
+ * withState({ userId: undefined as number | undefined }),
2037
+ * withResource(({ userId }) => ({
2038
+ * user: httpResource<User[]>(() => '/users', { defaultValue: [] }),
2039
+ * }))
2040
+ * );
2041
+ * const userResource = mapToResource(store, 'user');
2042
+ * userResource satisfies Resource<User[]>;
2043
+ * ```
2044
+ *
2045
+ * @param store The store instance to map the resource to.
2046
+ * @param name The name of the resource to map.
2047
+ * @returns `ResourceRef<T>`
2048
+ */
2049
+ function mapToResource(store, name) {
2050
+ const resourceName = String(name);
2051
+ function hasValue() {
2052
+ return store[`${resourceName}HasValue`]();
2053
+ }
2054
+ return {
2055
+ value: store[`${resourceName}Value`],
2056
+ status: store[`${resourceName}Status`],
2057
+ error: store[`${resourceName}Error`],
2058
+ isLoading: store[`${resourceName}IsLoading`],
2059
+ hasValue,
2060
+ };
2061
+ }
2062
+
1784
2063
  /**
1785
2064
  * Generated bundle index. Do not edit.
1786
2065
  */
1787
2066
 
1788
- export { capitalize, createEffects, createPageArray, createReducer, deriveCallStateKeys, emptyFeature, firstPage, getCallStateKeys, getCollectionArray, getDataServiceKeys, getUndoRedoKeys, gotoPage, nextPage, noPayload, patchState, payload, previousPage, provideDevtoolsConfig, renameDevtoolsName, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, updateState, withCallState, withConditional, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withFeatureFactory, withGlitchTracking, withImmutableState, withIndexedDB, withIndexedDB as withIndexeddb, withLocalStorage, withMapper, withPagination, withRedux, withReset, withSessionStorage, withStorageSync, withUndoRedo };
2067
+ export { capitalize, concatOp, createEffects, createPageArray, createReducer, deriveCallStateKeys, emptyFeature, exhaustOp, firstPage, getCallStateKeys, getCollectionArray, getDataServiceKeys, getUndoRedoKeys, gotoPage, mapToResource, mergeOp, nextPage, noPayload, patchState, payload, previousPage, provideDevtoolsConfig, renameDevtoolsName, rxMutation, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, switchOp, updateState, withCallState, withConditional, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withFeatureFactory, withGlitchTracking, withImmutableState, withIndexedDB, withIndexedDB as withIndexeddb, withLocalStorage, withMapper, withMutations, withPagination, withRedux, withReset, withResource, withSessionStorage, withStorageSync, withUndoRedo };
1789
2068
  //# sourceMappingURL=angular-architects-ngrx-toolkit.mjs.map