@angular-architects/ngrx-toolkit 20.4.2 → 20.6.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.
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as _ngrx_signals from '@ngrx/signals';
2
2
  import { StateSource, patchState as patchState$1, WritableStateSource, PartialStateUpdater, SignalStoreFeature, EmptyFeatureResult, SignalStoreFeatureResult, StateSignals } from '@ngrx/signals';
3
3
  import { ValueProvider, Signal, ProviderToken, WritableSignal, Injector, ResourceStatus, Resource, ResourceRef } from '@angular/core';
4
4
  import { Observable, ObservableInput, OperatorFunction, ObservedValueOf } from 'rxjs';
5
- import { EntityId, NamedEntityState } from '@ngrx/signals/entities';
5
+ import { EntityId, NamedEntityState, EntityState as EntityState$1, EntityProps, NamedEntityProps } from '@ngrx/signals/entities';
6
6
  import { HttpHeaders, HttpContext, HttpParams, HttpProgressEvent } from '@angular/common/http';
7
7
 
8
8
  /**
@@ -53,7 +53,7 @@ type DevtoolsOptions = {
53
53
  * We use them (function calls) instead of a config object,
54
54
  * because of tree-shaking.
55
55
  */
56
- type DevtoolsFeature = {
56
+ type DevtoolsFeature$1 = {
57
57
  [DEVTOOLS_FEATURE]: true;
58
58
  } & Partial<DevtoolsOptions>;
59
59
 
@@ -83,7 +83,7 @@ type DevtoolsFeature = {
83
83
  * ```
84
84
  *
85
85
  */
86
- declare function withDisabledNameIndices(): DevtoolsFeature;
86
+ declare function withDisabledNameIndices(): DevtoolsFeature$1;
87
87
 
88
88
  /**
89
89
  * It tracks all state changes of the State, including intermediary updates
@@ -114,7 +114,7 @@ declare function withDisabledNameIndices(): DevtoolsFeature;
114
114
  *
115
115
  * Without `withGlitchTracking`, the DevTools would only show the final value of 3.
116
116
  */
117
- declare function withGlitchTracking(): DevtoolsFeature;
117
+ declare function withGlitchTracking(): DevtoolsFeature$1;
118
118
 
119
119
  /**
120
120
  * Allows you to define a function to map the state.
@@ -143,7 +143,7 @@ declare function withGlitchTracking(): DevtoolsFeature;
143
143
  *
144
144
  * @param map function which maps the state
145
145
  */
146
- declare function withMapper<State extends object>(map: (state: State) => Record<string, unknown>): DevtoolsFeature;
146
+ declare function withMapper<State extends object>(map: (state: State) => Record<string, unknown>): DevtoolsFeature$1;
147
147
 
148
148
  /**
149
149
  * Renames the name of a store how it appears in the Devtools.
@@ -166,6 +166,7 @@ declare const patchState: PatchFn;
166
166
  */
167
167
  declare function updateState<State extends object>(stateSource: WritableStateSource<State>, action: string, ...updaters: Array<Partial<NoInfer<State>> | PartialStateUpdater<NoInfer<State>>>): void;
168
168
 
169
+ type DevtoolsFeature = DevtoolsFeature$1;
169
170
  declare global {
170
171
  interface Window {
171
172
  __REDUX_DEVTOOLS_EXTENSION__: ReduxDevtoolsExtension | undefined;
@@ -1049,54 +1050,6 @@ interface RxMutationOptions<Parameter, Result> {
1049
1050
  */
1050
1051
  declare function rxMutation<Parameter, Result>(optionsOrOperation: RxMutationOptions<Parameter, Result> | Operation<Parameter, Observable<Result>>): Mutation<Parameter, Result>;
1051
1052
 
1052
- type MutationsDictionary = Record<string, Mutation<any, any>>;
1053
- type MethodsDictionary = Record<string, Function>;
1054
- type NamedMutationProps<T extends MutationsDictionary> = {
1055
- [Prop in keyof T as `${Prop & string}IsPending`]: Signal<boolean>;
1056
- } & {
1057
- [Prop in keyof T as `${Prop & string}Status`]: Signal<MutationStatus>;
1058
- } & {
1059
- [Prop in keyof T as `${Prop & string}Error`]: Signal<Error | undefined>;
1060
- };
1061
- type NamedMutationMethods<T extends MutationsDictionary> = {
1062
- [Prop in keyof T as `${Prop & string}`]: T[Prop] extends Mutation<infer P, infer R> ? Mutation<P, R> : never;
1063
- };
1064
- type NamedMutationResult<T extends MutationsDictionary> = EmptyFeatureResult & {
1065
- props: NamedMutationProps<T>;
1066
- methods: NamedMutationMethods<T>;
1067
- };
1068
- /**
1069
- * Adds mutation methods to the store. Also, for each mutation method, several
1070
- * Signals are added informing about the mutation's status and errors.
1071
- *
1072
- * ```typescript
1073
- * export type Params = {
1074
- * value: number;
1075
- * };
1076
- *
1077
- * export const CounterStore = signalStore(
1078
- * { providedIn: 'root' },
1079
- * withState({ counter: 0 }),
1080
- * withMutations((store) => ({
1081
- * increment: rxMutation({ ... }),
1082
- * })),
1083
- * );
1084
- * ```
1085
- *
1086
- * There are several types of mutations. In the example shown, an {@link module:rx-mutation.rxMutation | rxMutation}
1087
- * leveraging RxJS is used
1088
- *
1089
- * For the defined `increment` mutation, several the following properties and
1090
- * methods are added to the store:
1091
- * - `increment(params: Params): Promise<MutationResult<number>>`: The mutation method.
1092
- * - `incrementIsPending`: A signal indicating if the mutation is in progress.
1093
- * - `incrementStatus`: A signal representing the current status of the mutation.
1094
- * - `incrementError`: A signal containing any error that occurred during the mutation.
1095
- *
1096
- * @param mutationsFactory
1097
- */
1098
- declare function withMutations<Input extends SignalStoreFeatureResult, Result extends MutationsDictionary>(mutationsFactory: (store: Input['props'] & Input['methods'] & WritableStateSource<Input['state']> & StateSignals<Input['state']>) => Result): SignalStoreFeature<Input, NamedMutationResult<Result>>;
1099
-
1100
1053
  type ResourceResult<T> = {
1101
1054
  state: {
1102
1055
  value: T;
@@ -1236,6 +1189,165 @@ type MappedResource<Store extends Record<string, unknown>, Name extends string>
1236
1189
  */
1237
1190
  declare function mapToResource<Name extends ResourceNames<Store>, Store extends Record<string, unknown>>(store: Store, name: Name): MappedResource<Store, Name>;
1238
1191
 
1192
+ /**
1193
+ * @experimental
1194
+ * @description
1195
+ *
1196
+ * Integrates array-based `Resource` data into Entity-style state for NgRx SignalStore.
1197
+ * This feature builds on {@link withResource} to provide an entity view over
1198
+ * array resources.
1199
+ *
1200
+ * - For a single (unnamed) resource: exposes `value`, `status`, `error`, `isLoading`
1201
+ * from the underlying resource (via `withResource`), and derives
1202
+ * `ids`, `entityMap`, and `entities` via `withLinkedState`/`withComputed`.
1203
+ * - For multiple (named) resources: registers each resource by name and exposes
1204
+ * the same members prefixed with the resource name, e.g. `todosIds`,
1205
+ * `todosEntityMap`, `todosEntities`, along with `todosValue`, `todosStatus`, etc.
1206
+ *
1207
+ * No effects are used. All derived signals are linked to the resource's value
1208
+ * through `withLinkedState`, so entity updaters such as `addEntity`, `updateEntity`,
1209
+ * and `removeEntity` mutate the store's entity view without directly writing to the
1210
+ * resource. The source of truth remains the resource value.
1211
+ *
1212
+ * @usageNotes
1213
+ *
1214
+ * Unnamed resource example:
1215
+ *
1216
+ * ```ts
1217
+ * type Todo = { id: number; title: string; completed: boolean };
1218
+ *
1219
+ * const Store = signalStore(
1220
+ * { providedIn: 'root' },
1221
+ * withEntityResources(() =>
1222
+ * resource({ loader: () => Promise.resolve([] as Todo[]), defaultValue: [] }),
1223
+ * ),
1224
+ * );
1225
+ *
1226
+ * const store = TestBed.inject(Store);
1227
+ * store.status(); // 'idle' | 'loading' | 'resolved' | 'error'
1228
+ * store.value(); // Todo[]
1229
+ * store.ids(); // EntityId[]
1230
+ * store.entityMap(); // Record<EntityId, Todo>
1231
+ * store.entities(); // Todo[]
1232
+ *
1233
+ * // Works with @ngrx/signals/entities updaters
1234
+ * patchState(store, addEntity({ id: 1, title: 'X', completed: false }));
1235
+ * ```
1236
+ *
1237
+ * Named resources example:
1238
+ *
1239
+ * ```ts
1240
+ * const Store = signalStore(
1241
+ * { providedIn: 'root' },
1242
+ * withEntityResources(() => ({
1243
+ * todos: resource({ loader: () => Promise.resolve([] as Todo[]), defaultValue: [] }),
1244
+ * projects: resource({ loader: () => Promise.resolve([] as { id: number; name: string }[]), defaultValue: [] }),
1245
+ * })),
1246
+ * );
1247
+ *
1248
+ * const store = TestBed.inject(Store);
1249
+ * store.todosValue();
1250
+ * store.todosIds();
1251
+ * store.todosEntityMap();
1252
+ * store.todosEntities();
1253
+ * patchState(store, addEntity({ id: 2, title: 'Y', completed: true }, { collection: 'todos' }));
1254
+ * ```
1255
+ *
1256
+ * @see {@link withResource}
1257
+ */
1258
+ declare function withEntityResources<Input extends SignalStoreFeatureResult, Entity extends {
1259
+ id: EntityId;
1260
+ }>(resourceFactory: (store: Input['props'] & Input['methods'] & StateSignals<Input['state']>) => ResourceRef<readonly Entity[] | Entity[] | undefined>): SignalStoreFeature<Input, EntityResourceResult<Entity>>;
1261
+ declare function withEntityResources<Input extends SignalStoreFeatureResult, Dictionary extends EntityDictionary>(resourceFactory: (store: Input['props'] & Input['methods'] & StateSignals<Input['state']>) => Dictionary): SignalStoreFeature<Input, NamedEntityResourceResult<Dictionary>>;
1262
+ /**
1263
+ * @internal
1264
+ * @description
1265
+ *
1266
+ * Type composition notes: we intentionally do not duplicate or re-declare
1267
+ * types that already exist in `@ngrx/signals/entities` or in this library's
1268
+ * `with-resource` feature. Instead, we compose the resulting API via
1269
+ * intersections of those public contracts.
1270
+ *
1271
+ * Rationale:
1272
+ * - Keeps our types in sync with upstream sources and avoids drift.
1273
+ * - Reduces maintenance overhead and duplication.
1274
+ * - Ensures consumers benefit automatically from upstream typing fixes.
1275
+ *
1276
+ * Concretely:
1277
+ * - For unnamed resources we return `ResourceResult<Entity>` intersected with
1278
+ * `EntityState<Entity>` and `EntityProps<Entity>`.
1279
+ * - For named resources we return `NamedResourceResult<T>` intersected with
1280
+ * `NamedEntityState<E, Name>` and `NamedEntityProps<E, Name>` for each entry.
1281
+ */
1282
+ type EntityResourceResult<Entity> = {
1283
+ state: ResourceResult<Entity>['state'] & EntityState$1<Entity>;
1284
+ props: ResourceResult<Entity>['props'] & EntityProps<Entity>;
1285
+ methods: ResourceResult<Entity>['methods'];
1286
+ };
1287
+ type ArrayElement<T> = T extends readonly (infer E)[] | (infer E)[] ? E : never;
1288
+ type InferEntityFromSignal<T> = T extends Signal<infer V> ? ArrayElement<V> : never;
1289
+ type MergeUnion<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
1290
+ type EntityDictionary = Record<string, ResourceRef<readonly unknown[] | unknown[] | undefined>>;
1291
+ type MergeNamedEntityStates<T extends EntityDictionary> = MergeUnion<{
1292
+ [Prop in keyof T]: Prop extends string ? InferEntityFromSignal<T[Prop]['value']> extends infer E ? E extends never ? never : NamedEntityState<E, Prop> : never : never;
1293
+ }[keyof T]>;
1294
+ type MergeNamedEntityProps<T extends EntityDictionary> = MergeUnion<{
1295
+ [Prop in keyof T]: Prop extends string ? InferEntityFromSignal<T[Prop]['value']> extends infer E ? E extends never ? never : NamedEntityProps<E, Prop> : never : never;
1296
+ }[keyof T]>;
1297
+ type NamedEntityResourceResult<T extends EntityDictionary> = {
1298
+ state: NamedResourceResult<T>['state'] & MergeNamedEntityStates<T>;
1299
+ props: NamedResourceResult<T>['props'] & MergeNamedEntityProps<T>;
1300
+ methods: NamedResourceResult<T>['methods'];
1301
+ };
1302
+
1303
+ type MutationsDictionary = Record<string, Mutation<any, any>>;
1304
+ type MethodsDictionary = Record<string, Function>;
1305
+ type NamedMutationProps<T extends MutationsDictionary> = {
1306
+ [Prop in keyof T as `${Prop & string}IsPending`]: Signal<boolean>;
1307
+ } & {
1308
+ [Prop in keyof T as `${Prop & string}Status`]: Signal<MutationStatus>;
1309
+ } & {
1310
+ [Prop in keyof T as `${Prop & string}Error`]: Signal<Error | undefined>;
1311
+ };
1312
+ type NamedMutationMethods<T extends MutationsDictionary> = {
1313
+ [Prop in keyof T as `${Prop & string}`]: T[Prop] extends Mutation<infer P, infer R> ? Mutation<P, R> : never;
1314
+ };
1315
+ type NamedMutationResult<T extends MutationsDictionary> = EmptyFeatureResult & {
1316
+ props: NamedMutationProps<T>;
1317
+ methods: NamedMutationMethods<T>;
1318
+ };
1319
+ /**
1320
+ * Adds mutation methods to the store. Also, for each mutation method, several
1321
+ * Signals are added informing about the mutation's status and errors.
1322
+ *
1323
+ * ```typescript
1324
+ * export type Params = {
1325
+ * value: number;
1326
+ * };
1327
+ *
1328
+ * export const CounterStore = signalStore(
1329
+ * { providedIn: 'root' },
1330
+ * withState({ counter: 0 }),
1331
+ * withMutations((store) => ({
1332
+ * increment: rxMutation({ ... }),
1333
+ * })),
1334
+ * );
1335
+ * ```
1336
+ *
1337
+ * There are several types of mutations. In the example shown, an {@link module:rx-mutation.rxMutation | rxMutation}
1338
+ * leveraging RxJS is used
1339
+ *
1340
+ * For the defined `increment` mutation, several the following properties and
1341
+ * methods are added to the store:
1342
+ * - `increment(params: Params): Promise<MutationResult<number>>`: The mutation method.
1343
+ * - `incrementIsPending`: A signal indicating if the mutation is in progress.
1344
+ * - `incrementStatus`: A signal representing the current status of the mutation.
1345
+ * - `incrementError`: A signal containing any error that occurred during the mutation.
1346
+ *
1347
+ * @param mutationsFactory
1348
+ */
1349
+ declare function withMutations<Input extends SignalStoreFeatureResult, Result extends MutationsDictionary>(mutationsFactory: (store: Input['props'] & Input['methods'] & WritableStateSource<Input['state']> & StateSignals<Input['state']>) => Result): SignalStoreFeature<Input, NamedMutationResult<Result>>;
1350
+
1239
1351
  type HttpMutationRequest = {
1240
1352
  url: string;
1241
1353
  method: string;
@@ -1319,5 +1431,5 @@ type HttpMutation<Parameter, Result> = Mutation<Parameter, Result> & {
1319
1431
  */
1320
1432
  declare function httpMutation<Parameter, Result>(optionsOrRequest: HttpMutationOptions<Parameter, Result> | ((param: Parameter) => HttpMutationRequest)): HttpMutation<Parameter, Result>;
1321
1433
 
1322
- 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 };
1323
- export type { CallState, CallStateSignals, CallStateSlice, DataService, DataServiceComputed, DataServiceMethods, DataServiceState, Entity, Filter, HttpMutation, HttpMutationOptions, HttpMutationRequest, MethodsDictionary, Mutation, MutationResult, MutationStatus, NamedCallStateSignals, NamedCallStateSlice, NamedDataServiceComputed, NamedDataServiceMethods, NamedDataServiceState, NamedMutationResult, NamedPaginationServiceSignals, NamedPaginationServiceState, NormalizedUndoRedoOptions, Operation, Page, PaginationServiceSignals, PaginationServiceState, ReduxDevtoolsConfig, RxMutationOptions, SetCallState, SetPaginationState, StackItem, SyncConfig };
1434
+ 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 };
1435
+ export type { CallState, CallStateSignals, CallStateSlice, DataService, DataServiceComputed, DataServiceMethods, DataServiceState, DevtoolsFeature, Entity, EntityDictionary, EntityResourceResult, Filter, HttpMutation, HttpMutationOptions, HttpMutationRequest, MethodsDictionary, Mutation, MutationResult, MutationStatus, NamedCallStateSignals, NamedCallStateSlice, NamedDataServiceComputed, NamedDataServiceMethods, NamedDataServiceState, NamedEntityResourceResult, NamedMutationResult, NamedPaginationServiceSignals, NamedPaginationServiceState, NormalizedUndoRedoOptions, Operation, Page, PaginationServiceSignals, PaginationServiceState, ReduxDevtoolsConfig, RxMutationOptions, SetCallState, SetPaginationState, StackItem, SyncConfig };
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@angular-architects/ngrx-toolkit",
3
- "version": "20.4.2",
3
+ "version": "20.6.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "GitHub",
7
7
  "url": "https://github.com/angular-architects/ngrx-toolkit"
8
8
  },
9
9
  "peerDependencies": {
10
- "@angular/core": "^20.0.0",
11
- "@angular/common": "^20.0.0",
12
- "@ngrx/signals": "^20.0.0",
13
- "@ngrx/store": "^20.0.0",
10
+ "@angular/core": "^20.0.0 || ^21.0.0",
11
+ "@angular/common": "^20.0.0 || ^21.0.0",
12
+ "@ngrx/signals": "^20.0.0 || ^21.0.0",
13
+ "@ngrx/store": "^20.0.0 || ^21.0.0",
14
14
  "rxjs": "^7.0.0"
15
15
  },
16
16
  "peerDependenciesMeta": {