@ngrx/signals 19.0.1 → 19.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.
Files changed (39) hide show
  1. package/entities/src/helpers.d.ts +4 -4
  2. package/entities/src/index.d.ts +4 -0
  3. package/entities/src/updaters/prepend-entities.d.ts +17 -0
  4. package/entities/src/updaters/prepend-entity.d.ts +17 -0
  5. package/entities/src/updaters/upsert-entities.d.ts +17 -0
  6. package/entities/src/updaters/upsert-entity.d.ts +17 -0
  7. package/events/index.d.ts +1 -0
  8. package/events/src/case-reducer.d.ts +20 -0
  9. package/events/src/dispatcher.d.ts +33 -0
  10. package/events/src/event-creator-group.d.ts +33 -0
  11. package/events/src/event-creator.d.ts +9 -0
  12. package/events/src/event-instance.d.ts +8 -0
  13. package/events/src/events-service.d.ts +47 -0
  14. package/events/src/index.d.ts +9 -0
  15. package/events/src/inject-dispatch.d.ts +46 -0
  16. package/events/src/with-effects.d.ts +28 -0
  17. package/events/src/with-reducer.d.ts +30 -0
  18. package/fesm2022/ngrx-signals-entities.mjs +68 -10
  19. package/fesm2022/ngrx-signals-entities.mjs.map +1 -1
  20. package/fesm2022/ngrx-signals-events.mjs +320 -0
  21. package/fesm2022/ngrx-signals-events.mjs.map +1 -0
  22. package/fesm2022/ngrx-signals-rxjs-interop.mjs +9 -2
  23. package/fesm2022/ngrx-signals-rxjs-interop.mjs.map +1 -1
  24. package/fesm2022/ngrx-signals-testing.mjs +15 -0
  25. package/fesm2022/ngrx-signals-testing.mjs.map +1 -0
  26. package/fesm2022/ngrx-signals.mjs +53 -7
  27. package/fesm2022/ngrx-signals.mjs.map +1 -1
  28. package/package.json +9 -1
  29. package/rxjs-interop/src/index.d.ts +1 -1
  30. package/rxjs-interop/src/rx-method.d.ts +1 -1
  31. package/schematics-core/utility/libs-version.js +1 -1
  32. package/schematics-core/utility/libs-version.js.map +1 -1
  33. package/src/index.d.ts +3 -2
  34. package/src/signal-method.d.ts +1 -2
  35. package/src/state-source.d.ts +1 -0
  36. package/src/with-feature.d.ts +25 -0
  37. package/testing/index.d.ts +1 -0
  38. package/testing/src/index.d.ts +1 -0
  39. package/testing/src/unprotected.d.ts +4 -0
@@ -17,9 +17,9 @@ export declare function getEntityUpdaterResult(state: EntityState<any>, stateKey
17
17
  entityMapKey: string;
18
18
  idsKey: string;
19
19
  }, didMutate: DidMutate): Record<string, any>;
20
- export declare function addEntityMutably(state: EntityState<any>, entity: any, selectId: SelectEntityId<any>): DidMutate;
21
- export declare function addEntitiesMutably(state: EntityState<any>, entities: any[], selectId: SelectEntityId<any>): DidMutate;
22
- export declare function setEntityMutably(state: EntityState<any>, entity: any, selectId: SelectEntityId<any>): DidMutate;
23
- export declare function setEntitiesMutably(state: EntityState<any>, entities: any[], selectId: SelectEntityId<any>): DidMutate;
20
+ export declare function addEntityMutably(state: EntityState<any>, entity: any, selectId: SelectEntityId<any>, prepend?: boolean): DidMutate;
21
+ export declare function addEntitiesMutably(state: EntityState<any>, entities: any[], selectId: SelectEntityId<any>, prepend?: boolean): DidMutate;
22
+ export declare function setEntityMutably(state: EntityState<any>, entity: any, selectId: SelectEntityId<any>, replace?: boolean): DidMutate;
23
+ export declare function setEntitiesMutably(state: EntityState<any>, entities: any[], selectId: SelectEntityId<any>, replace?: boolean): DidMutate;
24
24
  export declare function removeEntitiesMutably(state: EntityState<any>, idsOrPredicate: EntityId[] | EntityPredicate<any>): DidMutate;
25
25
  export declare function updateEntitiesMutably(state: EntityState<any>, idsOrPredicate: EntityId[] | EntityPredicate<any>, changes: EntityChanges<any>, selectId: SelectEntityId<any>): DidMutate;
@@ -1,5 +1,7 @@
1
1
  export { addEntity } from './updaters/add-entity';
2
2
  export { addEntities } from './updaters/add-entities';
3
+ export { prependEntity } from './updaters/prepend-entity';
4
+ export { prependEntities } from './updaters/prepend-entities';
3
5
  export { removeEntity } from './updaters/remove-entity';
4
6
  export { removeEntities } from './updaters/remove-entities';
5
7
  export { removeAllEntities } from './updaters/remove-all-entities';
@@ -9,6 +11,8 @@ export { setAllEntities } from './updaters/set-all-entities';
9
11
  export { updateEntity } from './updaters/update-entity';
10
12
  export { updateEntities } from './updaters/update-entities';
11
13
  export { updateAllEntities } from './updaters/update-all-entities';
14
+ export { upsertEntity } from './updaters/upsert-entity';
15
+ export { upsertEntities } from './updaters/upsert-entities';
12
16
  export { entityConfig } from './entity-config';
13
17
  export { EntityId, EntityMap, EntityProps, EntityState, NamedEntityProps, NamedEntityState, SelectEntityId, } from './models';
14
18
  export { withEntities } from './with-entities';
@@ -0,0 +1,17 @@
1
+ import { PartialStateUpdater } from '@ngrx/signals';
2
+ import { EntityId, EntityState, NamedEntityState, SelectEntityId } from '../models';
3
+ export declare function prependEntities<Entity extends {
4
+ id: EntityId;
5
+ }>(entities: Entity[]): PartialStateUpdater<EntityState<Entity>>;
6
+ export declare function prependEntities<Entity, Collection extends string>(entities: Entity[], config: {
7
+ collection: Collection;
8
+ selectId: SelectEntityId<NoInfer<Entity>>;
9
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
10
+ export declare function prependEntities<Entity extends {
11
+ id: EntityId;
12
+ }, Collection extends string>(entities: Entity[], config: {
13
+ collection: Collection;
14
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
15
+ export declare function prependEntities<Entity>(entities: Entity[], config: {
16
+ selectId: SelectEntityId<NoInfer<Entity>>;
17
+ }): PartialStateUpdater<EntityState<Entity>>;
@@ -0,0 +1,17 @@
1
+ import { PartialStateUpdater } from '@ngrx/signals';
2
+ import { EntityId, EntityState, NamedEntityState, SelectEntityId } from '../models';
3
+ export declare function prependEntity<Entity extends {
4
+ id: EntityId;
5
+ }>(entity: Entity): PartialStateUpdater<EntityState<Entity>>;
6
+ export declare function prependEntity<Entity, Collection extends string>(entity: Entity, config: {
7
+ collection: Collection;
8
+ selectId: SelectEntityId<NoInfer<Entity>>;
9
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
10
+ export declare function prependEntity<Entity extends {
11
+ id: EntityId;
12
+ }, Collection extends string>(entity: Entity, config: {
13
+ collection: Collection;
14
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
15
+ export declare function prependEntity<Entity>(entity: Entity, config: {
16
+ selectId: SelectEntityId<NoInfer<Entity>>;
17
+ }): PartialStateUpdater<EntityState<Entity>>;
@@ -0,0 +1,17 @@
1
+ import { PartialStateUpdater } from '@ngrx/signals';
2
+ import { EntityId, EntityState, NamedEntityState, SelectEntityId } from '../models';
3
+ export declare function upsertEntities<Entity extends {
4
+ id: EntityId;
5
+ }>(entities: Entity[]): PartialStateUpdater<EntityState<Entity>>;
6
+ export declare function upsertEntities<Entity, Collection extends string>(entities: Entity[], config: {
7
+ collection: Collection;
8
+ selectId: SelectEntityId<NoInfer<Entity>>;
9
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
10
+ export declare function upsertEntities<Entity extends {
11
+ id: EntityId;
12
+ }, Collection extends string>(entities: Entity[], config: {
13
+ collection: Collection;
14
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
15
+ export declare function upsertEntities<Entity>(entities: Entity[], config: {
16
+ selectId: SelectEntityId<NoInfer<Entity>>;
17
+ }): PartialStateUpdater<EntityState<Entity>>;
@@ -0,0 +1,17 @@
1
+ import { PartialStateUpdater } from '@ngrx/signals';
2
+ import { EntityId, EntityState, NamedEntityState, SelectEntityId } from '../models';
3
+ export declare function upsertEntity<Entity extends {
4
+ id: EntityId;
5
+ }>(entity: Entity): PartialStateUpdater<EntityState<Entity>>;
6
+ export declare function upsertEntity<Entity, Collection extends string>(entity: Entity, config: {
7
+ collection: Collection;
8
+ selectId: SelectEntityId<NoInfer<Entity>>;
9
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
10
+ export declare function upsertEntity<Entity extends {
11
+ id: EntityId;
12
+ }, Collection extends string>(entity: Entity, config: {
13
+ collection: Collection;
14
+ }): PartialStateUpdater<NamedEntityState<Entity, Collection>>;
15
+ export declare function upsertEntity<Entity>(entity: Entity, config: {
16
+ selectId: SelectEntityId<NoInfer<Entity>>;
17
+ }): PartialStateUpdater<EntityState<Entity>>;
@@ -0,0 +1 @@
1
+ export * from './src/index';
@@ -0,0 +1,20 @@
1
+ import { PartialStateUpdater } from '@ngrx/signals';
2
+ import { EventCreator } from './event-creator';
3
+ export type CaseReducerResult<State extends object, EventCreators extends EventCreator<string, any>[]> = {
4
+ reducer: CaseReducer<State, EventCreators>;
5
+ events: EventCreators;
6
+ };
7
+ type CaseReducer<State extends object, EventCreators extends EventCreator<string, any>[]> = (event: {
8
+ [K in keyof EventCreators]: ReturnType<EventCreators[K]>;
9
+ }[number]) => Partial<State> | PartialStateUpdater<State> | Array<Partial<State> | PartialStateUpdater<State>>;
10
+ /**
11
+ * @experimental
12
+ * @description
13
+ *
14
+ * Creates a case reducer that can be used with the `withReducer` feature.
15
+ */
16
+ export declare function on<State extends object, EventCreators extends EventCreator<string, any>[]>(...args: [
17
+ ...events: [...EventCreators],
18
+ reducer: CaseReducer<NoInfer<State>, NoInfer<EventCreators>>
19
+ ]): CaseReducerResult<State, EventCreators>;
20
+ export {};
@@ -0,0 +1,33 @@
1
+ import { EventInstance } from './event-instance';
2
+ import { Events, ReducerEvents } from './events-service';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * @experimental
6
+ * @description
7
+ *
8
+ * Globally provided service for dispatching events.
9
+ *
10
+ * @usageNotes
11
+ *
12
+ * ```ts
13
+ * import { Dispatcher, event } from '@ngrx/signals/events';
14
+ *
15
+ * const increment = event('[Counter Page] Increment');
16
+ *
17
+ * \@Component({ \/* ... *\/ })
18
+ * class Counter {
19
+ * readonly #dispatcher = inject(Dispatcher);
20
+ *
21
+ * increment(): void {
22
+ * this.#dispatcher.dispatch(increment());
23
+ * }
24
+ * }
25
+ * ```
26
+ */
27
+ export declare class Dispatcher {
28
+ protected readonly reducerEvents: ReducerEvents;
29
+ protected readonly events: Events;
30
+ dispatch(event: EventInstance<string, unknown>): void;
31
+ static ɵfac: i0.ɵɵFactoryDeclaration<Dispatcher, never>;
32
+ static ɵprov: i0.ɵɵInjectableDeclaration<Dispatcher>;
33
+ }
@@ -0,0 +1,33 @@
1
+ import { Prettify } from '@ngrx/signals';
2
+ import { EventCreator } from './event-creator';
3
+ type EventType<Source extends string, EventName extends string> = `[${Source}] ${EventName}`;
4
+ type EventCreatorGroup<Source extends string, Events extends Record<string, any>> = {
5
+ [EventName in keyof Events]: EventName extends string ? EventCreator<EventType<Source, EventName>, Events[EventName]> : never;
6
+ };
7
+ /**
8
+ * @experimental
9
+ * @description
10
+ *
11
+ * Creates a group of event creators.
12
+ *
13
+ * @usageNotes
14
+ *
15
+ * ```ts
16
+ * import { type } from '@ngrx/signals';
17
+ * import { eventGroup } from '@ngrx/signals/events';
18
+ *
19
+ * const counterPageEvents = eventGroup({
20
+ * source: 'Counter Page',
21
+ * events: {
22
+ * increment: type<void>(),
23
+ * decrement: type<void>(),
24
+ * set: type<number>(),
25
+ * },
26
+ * });
27
+ * ```
28
+ */
29
+ export declare function eventGroup<Source extends string, Events extends Record<string, unknown>>(config: {
30
+ source: Source;
31
+ events: Events;
32
+ }): Prettify<EventCreatorGroup<Source, Events>>;
33
+ export {};
@@ -0,0 +1,9 @@
1
+ import { EventInstance } from './event-instance';
2
+ /**
3
+ * @experimental
4
+ */
5
+ export type EventCreator<Type extends string, Payload> = ((payload: Payload) => EventInstance<Type, Payload>) & {
6
+ type: Type;
7
+ };
8
+ export declare function event<Type extends string>(type: Type): EventCreator<Type, void>;
9
+ export declare function event<Type extends string, Payload>(type: Type, payload: Payload): EventCreator<Type, Payload>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @experimental
3
+ */
4
+ export type EventInstance<Type extends string, Payload> = {
5
+ type: Type;
6
+ payload: Payload;
7
+ };
8
+ export declare function isEventInstance(value: unknown): value is EventInstance<string, unknown>;
@@ -0,0 +1,47 @@
1
+ import { Observable } from 'rxjs';
2
+ import { EventInstance } from './event-instance';
3
+ import { EventCreator } from './event-creator';
4
+ import * as i0 from "@angular/core";
5
+ export declare const EVENTS: unique symbol;
6
+ export declare const SOURCE_TYPE: unique symbol;
7
+ declare abstract class BaseEvents {
8
+ on(): Observable<EventInstance<string, unknown>>;
9
+ on<EventCreators extends EventCreator<string, any>[]>(...events: [...EventCreators]): Observable<{
10
+ [K in keyof EventCreators]: ReturnType<EventCreators[K]>;
11
+ }[number]>;
12
+ }
13
+ /**
14
+ * @experimental
15
+ * @description
16
+ *
17
+ * Globally provided service for listening to dispatched events.
18
+ *
19
+ * @usageNotes
20
+ *
21
+ * ```ts
22
+ * import { event, Events } from '@ngrx/signals/events';
23
+ *
24
+ * const increment = event('[Counter Page] Increment');
25
+ *
26
+ * \@Component({ \/* ... *\/ })
27
+ * class Counter {
28
+ * readonly #events = inject(Events);
29
+ *
30
+ * constructor() {
31
+ * this.#events
32
+ * .on(increment)
33
+ * .pipe(takeUntilDestroyed())
34
+ * .subscribe(() => \/* handle increment event *\/);
35
+ * }
36
+ * }
37
+ * ```
38
+ */
39
+ export declare class Events extends BaseEvents {
40
+ static ɵfac: i0.ɵɵFactoryDeclaration<Events, never>;
41
+ static ɵprov: i0.ɵɵInjectableDeclaration<Events>;
42
+ }
43
+ export declare class ReducerEvents extends BaseEvents {
44
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReducerEvents, never>;
45
+ static ɵprov: i0.ɵɵInjectableDeclaration<ReducerEvents>;
46
+ }
47
+ export {};
@@ -0,0 +1,9 @@
1
+ export { on } from './case-reducer';
2
+ export { Dispatcher } from './dispatcher';
3
+ export { event, EventCreator } from './event-creator';
4
+ export { eventGroup } from './event-creator-group';
5
+ export { EventInstance } from './event-instance';
6
+ export { Events } from './events-service';
7
+ export { injectDispatch } from './inject-dispatch';
8
+ export { withEffects } from './with-effects';
9
+ export { withReducer } from './with-reducer';
@@ -0,0 +1,46 @@
1
+ import { Injector } from '@angular/core';
2
+ import { Prettify } from '@ngrx/signals';
3
+ import { EventCreator } from './event-creator';
4
+ type InjectDispatchResult<EventGroup extends Record<string, EventCreator<string, any>>> = {
5
+ [EventName in keyof EventGroup]: Parameters<EventGroup[EventName]> extends [
6
+ infer Payload
7
+ ] ? (payload: Payload) => void : () => void;
8
+ };
9
+ /**
10
+ * @experimental
11
+ * @description
12
+ *
13
+ * Creates self-dispatching events for a given event group.
14
+ *
15
+ * @usageNotes
16
+ *
17
+ * ```ts
18
+ * import { type } from '@ngrx/signals';
19
+ * import { eventGroup, injectDispatch } from '@ngrx/signals/events';
20
+ *
21
+ * const counterPageEvents = eventGroup({
22
+ * source: 'Counter Page',
23
+ * events: {
24
+ * increment: type<void>(),
25
+ * decrement: type<void>(),
26
+ * },
27
+ * });
28
+ *
29
+ * \@Component({ \/* ... *\/ })
30
+ * class Counter {
31
+ * readonly dispatch = injectDispatch(counterPageEvents);
32
+ *
33
+ * increment(): void {
34
+ * this.dispatch.increment();
35
+ * }
36
+ *
37
+ * decrement(): void {
38
+ * this.dispatch.decrement();
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function injectDispatch<EventGroup extends Record<string, EventCreator<string, any>>>(events: EventGroup, config?: {
44
+ injector?: Injector;
45
+ }): Prettify<InjectDispatchResult<EventGroup>>;
46
+ export {};
@@ -0,0 +1,28 @@
1
+ import { Observable } from 'rxjs';
2
+ import { EmptyFeatureResult, Prettify, SignalStoreFeature, SignalStoreFeatureResult, StateSignals, WritableStateSource } from '@ngrx/signals';
3
+ /**
4
+ * @experimental
5
+ * @description
6
+ *
7
+ * SignalStore feature for defining side effects.
8
+ *
9
+ * @usageNotes
10
+ *
11
+ * ```ts
12
+ * import { signalStore, withState } from '@ngrx/signals';
13
+ * import { event, Events, withEffects } from '@ngrx/signals/events';
14
+ *
15
+ * const increment = event('[Counter Page] Increment');
16
+ * const decrement = event('[Counter Page] Decrement');
17
+ *
18
+ * const CounterStore = signalStore(
19
+ * withState({ count: 0 }),
20
+ * withEffects(({ count }, events = inject(Events)) => ({
21
+ * logCount$: events.on(increment, decrement).pipe(
22
+ * tap(({ type }) => console.log(type, count())),
23
+ * ),
24
+ * })),
25
+ * );
26
+ * ```
27
+ */
28
+ export declare function withEffects<Input extends SignalStoreFeatureResult>(effectsFactory: (store: Prettify<StateSignals<Input['state']> & Input['props'] & Input['methods'] & WritableStateSource<Prettify<Input['state']>>>) => Record<string, Observable<unknown>>): SignalStoreFeature<Input, EmptyFeatureResult>;
@@ -0,0 +1,30 @@
1
+ import { EmptyFeatureResult, SignalStoreFeature } from '@ngrx/signals';
2
+ import { CaseReducerResult } from './case-reducer';
3
+ import { EventCreator } from './event-creator';
4
+ /**
5
+ * @experimental
6
+ * @description
7
+ *
8
+ * SignalStore feature for defining state changes based on dispatched events.
9
+ *
10
+ * @usageNotes
11
+ *
12
+ * ```ts
13
+ * import { signalStore, type, withState } from '@ngrx/signals';
14
+ * import { event, on, withReducer } from '@ngrx/signals/events';
15
+ *
16
+ * const set = event('[Counter Page] Set', type<number>());
17
+ *
18
+ * const CounterStore = signalStore(
19
+ * withState({ count: 0 }),
20
+ * withReducer(
21
+ * on(set, ({ payload }) => ({ count: payload })),
22
+ * ),
23
+ * );
24
+ * ```
25
+ */
26
+ export declare function withReducer<State extends object>(...caseReducers: CaseReducerResult<State, EventCreator<string, any>[]>[]): SignalStoreFeature<{
27
+ state: State;
28
+ props: {};
29
+ methods: {};
30
+ }, EmptyFeatureResult>;
@@ -41,39 +41,46 @@ function getEntityUpdaterResult(state, stateKeys, didMutate) {
41
41
  }
42
42
  }
43
43
  }
44
- function addEntityMutably(state, entity, selectId) {
44
+ function addEntityMutably(state, entity, selectId, prepend = false) {
45
45
  const id = selectId(entity);
46
46
  if (state.entityMap[id]) {
47
47
  return DidMutate.None;
48
48
  }
49
49
  state.entityMap[id] = entity;
50
- state.ids.push(id);
50
+ if (prepend) {
51
+ state.ids.unshift(id);
52
+ }
53
+ else {
54
+ state.ids.push(id);
55
+ }
51
56
  return DidMutate.Both;
52
57
  }
53
- function addEntitiesMutably(state, entities, selectId) {
58
+ function addEntitiesMutably(state, entities, selectId, prepend = false) {
54
59
  let didMutate = DidMutate.None;
55
60
  for (const entity of entities) {
56
- const result = addEntityMutably(state, entity, selectId);
61
+ const result = addEntityMutably(state, entity, selectId, prepend);
57
62
  if (result === DidMutate.Both) {
58
63
  didMutate = result;
59
64
  }
60
65
  }
61
66
  return didMutate;
62
67
  }
63
- function setEntityMutably(state, entity, selectId) {
68
+ function setEntityMutably(state, entity, selectId, replace = true) {
64
69
  const id = selectId(entity);
65
70
  if (state.entityMap[id]) {
66
- state.entityMap[id] = entity;
71
+ state.entityMap[id] = replace
72
+ ? entity
73
+ : { ...state.entityMap[id], ...entity };
67
74
  return DidMutate.Entities;
68
75
  }
69
76
  state.entityMap[id] = entity;
70
77
  state.ids.push(id);
71
78
  return DidMutate.Both;
72
79
  }
73
- function setEntitiesMutably(state, entities, selectId) {
80
+ function setEntitiesMutably(state, entities, selectId, replace = true) {
74
81
  let didMutate = DidMutate.None;
75
82
  for (const entity of entities) {
76
- const result = setEntityMutably(state, entity, selectId);
83
+ const result = setEntityMutably(state, entity, selectId, replace);
77
84
  if (didMutate === DidMutate.Both) {
78
85
  continue;
79
86
  }
@@ -122,7 +129,9 @@ function updateEntitiesMutably(state, idsOrPredicate, changes, selectId) {
122
129
  state.ids = state.ids.map((id) => newIds[id] ?? id);
123
130
  didMutate = DidMutate.Both;
124
131
  }
125
- if (ngDevMode && state.ids.length !== Object.keys(state.entityMap).length) {
132
+ if (typeof ngDevMode !== 'undefined' &&
133
+ ngDevMode &&
134
+ state.ids.length !== Object.keys(state.entityMap).length) {
126
135
  console.warn('@ngrx/signals/entities: Entities with IDs:', ids, 'are not updated correctly.', 'Make sure to apply valid changes when using `updateEntity`,', '`updateEntities`, and `updateAllEntities` updaters.');
127
136
  }
128
137
  return didMutate;
@@ -148,6 +157,35 @@ function addEntities(entities, config) {
148
157
  };
149
158
  }
150
159
 
160
+ function prependEntity(entity, config) {
161
+ const selectId = getEntityIdSelector(config);
162
+ const stateKeys = getEntityStateKeys(config);
163
+ return (state) => {
164
+ const clonedState = cloneEntityState(state, stateKeys);
165
+ const didMutate = addEntityMutably(clonedState, entity, selectId, true);
166
+ return getEntityUpdaterResult(clonedState, stateKeys, didMutate);
167
+ };
168
+ }
169
+
170
+ function prependEntities(entities, config) {
171
+ const selectId = getEntityIdSelector(config);
172
+ const stateKeys = getEntityStateKeys(config);
173
+ return (state) => {
174
+ const clonedState = cloneEntityState(state, stateKeys);
175
+ const uniqueEntities = [];
176
+ const seenIds = new Set();
177
+ for (const entity of entities) {
178
+ const id = selectId(entity);
179
+ if (!seenIds.has(id)) {
180
+ uniqueEntities.unshift(entity);
181
+ seenIds.add(id);
182
+ }
183
+ }
184
+ const didMutate = addEntitiesMutably(clonedState, uniqueEntities, selectId, true);
185
+ return getEntityUpdaterResult(clonedState, stateKeys, didMutate);
186
+ };
187
+ }
188
+
151
189
  function removeEntity(id, config) {
152
190
  const stateKeys = getEntityStateKeys(config);
153
191
  return (state) => {
@@ -238,6 +276,26 @@ function updateAllEntities(changes, config) {
238
276
  };
239
277
  }
240
278
 
279
+ function upsertEntity(entity, config) {
280
+ const selectId = getEntityIdSelector(config);
281
+ const stateKeys = getEntityStateKeys(config);
282
+ return (state) => {
283
+ const clonedState = cloneEntityState(state, stateKeys);
284
+ const didMutate = setEntityMutably(clonedState, entity, selectId, false);
285
+ return getEntityUpdaterResult(clonedState, stateKeys, didMutate);
286
+ };
287
+ }
288
+
289
+ function upsertEntities(entities, config) {
290
+ const selectId = getEntityIdSelector(config);
291
+ const stateKeys = getEntityStateKeys(config);
292
+ return (state) => {
293
+ const clonedState = cloneEntityState(state, stateKeys);
294
+ const didMutate = setEntitiesMutably(clonedState, entities, selectId, false);
295
+ return getEntityUpdaterResult(clonedState, stateKeys, didMutate);
296
+ };
297
+ }
298
+
241
299
  function entityConfig(config) {
242
300
  return config;
243
301
  }
@@ -260,5 +318,5 @@ function withEntities(config) {
260
318
  * Generated bundle index. Do not edit.
261
319
  */
262
320
 
263
- export { addEntities, addEntity, entityConfig, removeAllEntities, removeEntities, removeEntity, setAllEntities, setEntities, setEntity, updateAllEntities, updateEntities, updateEntity, withEntities };
321
+ export { addEntities, addEntity, entityConfig, prependEntities, prependEntity, removeAllEntities, removeEntities, removeEntity, setAllEntities, setEntities, setEntity, updateAllEntities, updateEntities, updateEntity, upsertEntities, upsertEntity, withEntities };
264
322
  //# sourceMappingURL=ngrx-signals-entities.mjs.map