@angular-architects/ngrx-toolkit 20.4.1 → 20.5.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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, signal, effect, inject, PLATFORM_ID, computed, isSignal, untracked, isDevMode as isDevMode$1, DestroyRef } from '@angular/core';
2
+ import { Injectable, InjectionToken, signal, effect, inject, PLATFORM_ID, NgZone, computed, isSignal, untracked, isDevMode as isDevMode$1, DestroyRef, linkedSignal } from '@angular/core';
3
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
5
  import { Subject, switchMap, mergeMap, concatMap, exhaustMap, defer, tap, catchError, EMPTY, finalize, filter, map } from 'rxjs';
@@ -270,11 +270,11 @@ class DevtoolsSyncer {
270
270
  */
271
271
  #currentState = {};
272
272
  #currentId = 1;
273
- #connection = this.#isBrowser
273
+ #connection = inject(NgZone).runOutsideAngular(() => this.#isBrowser
274
274
  ? window.__REDUX_DEVTOOLS_EXTENSION__
275
275
  ? window.__REDUX_DEVTOOLS_EXTENSION__.connect(this.#devtoolsConfig)
276
276
  : dummyConnection
277
- : dummyConnection;
277
+ : dummyConnection);
278
278
  constructor() {
279
279
  if (!this.#isBrowser) {
280
280
  return;
@@ -1969,41 +1969,6 @@ function rxMutation(optionsOrOperation) {
1969
1969
  return mutation;
1970
1970
  }
1971
1971
 
1972
- function withMutations(mutationsFactory) {
1973
- return (store) => {
1974
- // TODO: Is this the correct usage?
1975
- const source = store;
1976
- const mutations = mutationsFactory({
1977
- ...source,
1978
- ...store.props,
1979
- ...store.methods,
1980
- ...store.stateSignals,
1981
- });
1982
- const feature = createMutationsFeature(mutations);
1983
- return feature(store);
1984
- };
1985
- }
1986
- function createMutationsFeature(mutations) {
1987
- const keys = Object.keys(mutations);
1988
- const feature = signalStoreFeature(withMethods(() => keys.reduce((acc, key) => ({
1989
- ...acc,
1990
- [key]: async (params) => {
1991
- const mutation = mutations[key];
1992
- if (!mutation) {
1993
- throw new Error(`Mutation ${key} not found`);
1994
- }
1995
- const result = await mutation(params);
1996
- return result;
1997
- },
1998
- }), {})), withComputed(() => keys.reduce((acc, key) => ({
1999
- ...acc,
2000
- [`${key}IsPending`]: mutations[key].isPending,
2001
- [`${key}Status`]: mutations[key].status,
2002
- [`${key}Error`]: mutations[key].error,
2003
- }), {})));
2004
- return feature;
2005
- }
2006
-
2007
1972
  //** Types for `withResource` */
2008
1973
  function withResource(resourceFactory) {
2009
1974
  return (store) => {
@@ -2103,6 +2068,125 @@ function mapToResource(store, name) {
2103
2068
  };
2104
2069
  }
2105
2070
 
2071
+ function withEntityResources(entityResourceFactory) {
2072
+ return (store) => {
2073
+ const resourceOrDict = entityResourceFactory({
2074
+ ...store.stateSignals,
2075
+ ...store.props,
2076
+ ...store.methods,
2077
+ });
2078
+ if (isResourceRef(resourceOrDict)) {
2079
+ return createUnnamedEntityResource(resourceOrDict)(store);
2080
+ }
2081
+ return createNamedEntityResources(resourceOrDict)(store);
2082
+ };
2083
+ }
2084
+ function createUnnamedEntityResource(resource) {
2085
+ const { idsLinked, entityMapLinked, entitiesSignal } = createEntityDerivations(resource.value);
2086
+ return signalStoreFeature(withResource(() => resource), withLinkedState(() => ({
2087
+ entityMap: entityMapLinked,
2088
+ ids: idsLinked,
2089
+ })), withComputed(() => ({
2090
+ entities: entitiesSignal,
2091
+ })));
2092
+ }
2093
+ function createNamedEntityResources(dictionary) {
2094
+ const keys = Object.keys(dictionary);
2095
+ const linkedState = {};
2096
+ const computedProps = {};
2097
+ keys.forEach((name) => {
2098
+ const ref = dictionary[name];
2099
+ const { idsLinked, entityMapLinked, entitiesSignal } = createEntityDerivations(ref.value);
2100
+ linkedState[`${String(name)}EntityMap`] = entityMapLinked;
2101
+ linkedState[`${String(name)}Ids`] = idsLinked;
2102
+ computedProps[`${String(name)}Entities`] = entitiesSignal;
2103
+ });
2104
+ return signalStoreFeature(withResource(() => dictionary), withLinkedState(() => linkedState), withComputed(() => computedProps));
2105
+ }
2106
+ /**
2107
+ * @internal
2108
+ * @description
2109
+ *
2110
+ * Creates the three entity-related signals (`ids`, `entityMap`, `entities`) from
2111
+ * a single source signal of entities. This mirrors the public contract of
2112
+ * `withEntities()`:
2113
+ * - `ids`: derived list of entity ids
2114
+ * - `entityMap`: map of id -> entity
2115
+ * - `entities`: projection of `ids` through `entityMap`
2116
+ *
2117
+ * Implementation details:
2118
+ * - Uses `withLinkedState` + `linkedSignal` for `ids` and `entityMap` so they are
2119
+ * writable state signals in the store (updaters like `addEntity` can mutate them).
2120
+ * - `entities` is a pure `computed` derived from `ids` and `entityMap`, matching
2121
+ * the pattern in `withEntities` where `entities` is computed from the two bases.
2122
+ *
2123
+ * Why not `watchState` or `effect`?
2124
+ * - `watchState` would fire for any state change in the store, not just changes
2125
+ * to the underlying resource value. That would cause unnecessary recomputation
2126
+ * and make it harder to reason about updates.
2127
+ * - `effect` would introduce side-effects and lifecycle management for syncing,
2128
+ * which is heavier and not aligned with this feature's goal to be purely
2129
+ * derived from signals. Using linked signals keeps the data flow declarative
2130
+ * and avoids imperative syncing code.
2131
+ */
2132
+ function createEntityDerivations(source) {
2133
+ const idsLinked = linkedSignal({
2134
+ source,
2135
+ computation: (list) => (list ?? []).map((e) => e.id),
2136
+ });
2137
+ const entityMapLinked = linkedSignal({
2138
+ source,
2139
+ computation: (list) => {
2140
+ const map = {};
2141
+ for (const item of list ?? []) {
2142
+ map[item.id] = item;
2143
+ }
2144
+ return map;
2145
+ },
2146
+ });
2147
+ const entitiesSignal = computed(() => {
2148
+ const ids = idsLinked();
2149
+ const map = entityMapLinked();
2150
+ return ids.map((id) => map[id]);
2151
+ }, ...(ngDevMode ? [{ debugName: "entitiesSignal" }] : []));
2152
+ return { idsLinked, entityMapLinked, entitiesSignal };
2153
+ }
2154
+
2155
+ function withMutations(mutationsFactory) {
2156
+ return (store) => {
2157
+ // TODO: Is this the correct usage?
2158
+ const source = store;
2159
+ const mutations = mutationsFactory({
2160
+ ...source,
2161
+ ...store.props,
2162
+ ...store.methods,
2163
+ ...store.stateSignals,
2164
+ });
2165
+ const feature = createMutationsFeature(mutations);
2166
+ return feature(store);
2167
+ };
2168
+ }
2169
+ function createMutationsFeature(mutations) {
2170
+ const keys = Object.keys(mutations);
2171
+ const feature = signalStoreFeature(withMethods(() => keys.reduce((acc, key) => ({
2172
+ ...acc,
2173
+ [key]: async (params) => {
2174
+ const mutation = mutations[key];
2175
+ if (!mutation) {
2176
+ throw new Error(`Mutation ${key} not found`);
2177
+ }
2178
+ const result = await mutation(params);
2179
+ return result;
2180
+ },
2181
+ }), {})), withComputed(() => keys.reduce((acc, key) => ({
2182
+ ...acc,
2183
+ [`${key}IsPending`]: mutations[key].isPending,
2184
+ [`${key}Status`]: mutations[key].status,
2185
+ [`${key}Error`]: mutations[key].error,
2186
+ }), {})));
2187
+ return feature;
2188
+ }
2189
+
2106
2190
  /**
2107
2191
  * Creates an HTTP mutation.
2108
2192
  *
@@ -2205,5 +2289,5 @@ function httpMutation(optionsOrRequest) {
2205
2289
  * Generated bundle index. Do not edit.
2206
2290
  */
2207
2291
 
2208
- export { capitalize, concatOp, createEffects, createPageArray, createReducer, deriveCallStateKeys, emptyFeature, exhaustOp, firstPage, getCallStateKeys, getCollectionArray, getDataServiceKeys, getUndoRedoKeys, gotoPage, httpMutation, 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 };
2292
+ export { capitalize, concatOp, createEffects, createPageArray, createReducer, deriveCallStateKeys, emptyFeature, exhaustOp, firstPage, getCallStateKeys, getCollectionArray, getDataServiceKeys, getUndoRedoKeys, gotoPage, httpMutation, mapToResource, mergeOp, nextPage, noPayload, patchState, payload, previousPage, provideDevtoolsConfig, renameDevtoolsName, rxMutation, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, switchOp, updateState, withCallState, withConditional, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withEntityResources, withFeatureFactory, withGlitchTracking, withImmutableState, withIndexedDB, withIndexedDB as withIndexeddb, withLocalStorage, withMapper, withMutations, withPagination, withRedux, withReset, withResource, withSessionStorage, withStorageSync, withUndoRedo };
2209
2293
  //# sourceMappingURL=angular-architects-ngrx-toolkit.mjs.map