Index: node_modules/@reduxjs/toolkit/src/entities/create_adapter.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/create_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/create_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,47 @@
+import type { EntityAdapter, EntityId, EntityAdapterOptions } from './models'
+import { createInitialStateFactory } from './entity_state'
+import { createSelectorsFactory } from './state_selectors'
+import { createSortedStateAdapter } from './sorted_state_adapter'
+import { createUnsortedStateAdapter } from './unsorted_state_adapter'
+import type { WithRequiredProp } from '../tsHelpers'
+
+export function createEntityAdapter<T, Id extends EntityId>(
+  options: WithRequiredProp<EntityAdapterOptions<T, Id>, 'selectId'>,
+): EntityAdapter<T, Id>
+
+export function createEntityAdapter<T extends { id: EntityId }>(
+  options?: Omit<EntityAdapterOptions<T, T['id']>, 'selectId'>,
+): EntityAdapter<T, T['id']>
+
+/**
+ *
+ * @param options
+ *
+ * @public
+ */
+export function createEntityAdapter<T>(
+  options: EntityAdapterOptions<T, EntityId> = {},
+): EntityAdapter<T, EntityId> {
+  const {
+    selectId,
+    sortComparer,
+  }: Required<EntityAdapterOptions<T, EntityId>> = {
+    sortComparer: false,
+    selectId: (instance: any) => instance.id,
+    ...options,
+  }
+
+  const stateAdapter = sortComparer
+    ? createSortedStateAdapter(selectId, sortComparer)
+    : createUnsortedStateAdapter(selectId)
+  const stateFactory = createInitialStateFactory(stateAdapter)
+  const selectorsFactory = createSelectorsFactory<T, EntityId>()
+
+  return {
+    selectId,
+    sortComparer,
+    ...stateFactory,
+    ...selectorsFactory,
+    ...stateAdapter,
+  }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/entity_state.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/entity_state.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/entity_state.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,38 @@
+import type {
+  EntityId,
+  EntityState,
+  EntityStateAdapter,
+  EntityStateFactory,
+} from './models'
+
+export function getInitialEntityState<T, Id extends EntityId>(): EntityState<
+  T,
+  Id
+> {
+  return {
+    ids: [],
+    entities: {} as Record<Id, T>,
+  }
+}
+
+export function createInitialStateFactory<T, Id extends EntityId>(
+  stateAdapter: EntityStateAdapter<T, Id>,
+): EntityStateFactory<T, Id> {
+  function getInitialState(
+    state?: undefined,
+    entities?: readonly T[] | Record<Id, T>,
+  ): EntityState<T, Id>
+  function getInitialState<S extends object>(
+    additionalState: S,
+    entities?: readonly T[] | Record<Id, T>,
+  ): EntityState<T, Id> & S
+  function getInitialState(
+    additionalState: any = {},
+    entities?: readonly T[] | Record<Id, T>,
+  ): any {
+    const state = Object.assign(getInitialEntityState(), additionalState)
+    return entities ? stateAdapter.setAll(state, entities) : state
+  }
+
+  return { getInitialState }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/index.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/index.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/index.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,8 @@
+export { createEntityAdapter } from './create_adapter'
+export type {
+  EntityState,
+  EntityAdapter,
+  Update,
+  IdSelector,
+  Comparer,
+} from './models'
Index: node_modules/@reduxjs/toolkit/src/entities/models.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/models.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/models.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,198 @@
+import type { Draft } from 'immer'
+import type { PayloadAction } from '../createAction'
+import type { CastAny, Id } from '../tsHelpers'
+import type { UncheckedIndexedAccess } from '../uncheckedindexed.js'
+import type { GetSelectorsOptions } from './state_selectors'
+
+/**
+ * @public
+ */
+export type EntityId = number | string
+
+/**
+ * @public
+ */
+export type Comparer<T> = (a: T, b: T) => number
+
+/**
+ * @public
+ */
+export type IdSelector<T, Id extends EntityId> = (model: T) => Id
+
+/**
+ * @public
+ */
+export type Update<T, Id extends EntityId> = { id: Id; changes: Partial<T> }
+
+/**
+ * @public
+ */
+export interface EntityState<T, Id extends EntityId> {
+  ids: Id[]
+  entities: Record<Id, T>
+}
+
+/**
+ * @public
+ */
+export interface EntityAdapterOptions<T, Id extends EntityId> {
+  selectId?: IdSelector<T, Id>
+  sortComparer?: false | Comparer<T>
+}
+
+export type PreventAny<S, T, Id extends EntityId> = CastAny<
+  S,
+  EntityState<T, Id>
+>
+
+export type DraftableEntityState<T, Id extends EntityId> =
+  | EntityState<T, Id>
+  | Draft<EntityState<T, Id>>
+
+/**
+ * @public
+ */
+export interface EntityStateAdapter<T, Id extends EntityId> {
+  addOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entity: T,
+  ): S
+  addOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    action: PayloadAction<T>,
+  ): S
+
+  addMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: readonly T[] | Record<Id, T>,
+  ): S
+  addMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: PayloadAction<readonly T[] | Record<Id, T>>,
+  ): S
+
+  setOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entity: T,
+  ): S
+  setOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    action: PayloadAction<T>,
+  ): S
+  setMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: readonly T[] | Record<Id, T>,
+  ): S
+  setMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: PayloadAction<readonly T[] | Record<Id, T>>,
+  ): S
+  setAll<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: readonly T[] | Record<Id, T>,
+  ): S
+  setAll<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: PayloadAction<readonly T[] | Record<Id, T>>,
+  ): S
+
+  removeOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    key: Id,
+  ): S
+  removeOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    key: PayloadAction<Id>,
+  ): S
+
+  removeMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    keys: readonly Id[],
+  ): S
+  removeMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    keys: PayloadAction<readonly Id[]>,
+  ): S
+
+  removeAll<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+  ): S
+
+  updateOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    update: Update<T, Id>,
+  ): S
+  updateOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    update: PayloadAction<Update<T, Id>>,
+  ): S
+
+  updateMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    updates: ReadonlyArray<Update<T, Id>>,
+  ): S
+  updateMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    updates: PayloadAction<ReadonlyArray<Update<T, Id>>>,
+  ): S
+
+  upsertOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entity: T,
+  ): S
+  upsertOne<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entity: PayloadAction<T>,
+  ): S
+
+  upsertMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: readonly T[] | Record<Id, T>,
+  ): S
+  upsertMany<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+    entities: PayloadAction<readonly T[] | Record<Id, T>>,
+  ): S
+}
+
+/**
+ * @public
+ */
+export interface EntitySelectors<T, V, IdType extends EntityId> {
+  selectIds: (state: V) => IdType[]
+  selectEntities: (state: V) => Record<IdType, T>
+  selectAll: (state: V) => T[]
+  selectTotal: (state: V) => number
+  selectById: (state: V, id: IdType) => Id<UncheckedIndexedAccess<T>>
+}
+
+/**
+ * @public
+ */
+export interface EntityStateFactory<T, Id extends EntityId> {
+  getInitialState(
+    state?: undefined,
+    entities?: Record<Id, T> | readonly T[],
+  ): EntityState<T, Id>
+  getInitialState<S extends object>(
+    state: S,
+    entities?: Record<Id, T> | readonly T[],
+  ): EntityState<T, Id> & S
+}
+
+/**
+ * @public
+ */
+export interface EntityAdapter<T, Id extends EntityId>
+  extends EntityStateAdapter<T, Id>,
+    EntityStateFactory<T, Id>,
+    Required<EntityAdapterOptions<T, Id>> {
+  getSelectors(
+    selectState?: undefined,
+    options?: GetSelectorsOptions,
+  ): EntitySelectors<T, EntityState<T, Id>, Id>
+  getSelectors<V>(
+    selectState: (state: V) => EntityState<T, Id>,
+    options?: GetSelectorsOptions,
+  ): EntitySelectors<T, V, Id>
+}
Index: node_modules/@reduxjs/toolkit/src/entities/sorted_state_adapter.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/sorted_state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/sorted_state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,266 @@
+import type {
+  IdSelector,
+  Comparer,
+  EntityStateAdapter,
+  Update,
+  EntityId,
+  DraftableEntityState,
+} from './models'
+import { createStateOperator } from './state_adapter'
+import { createUnsortedStateAdapter } from './unsorted_state_adapter'
+import {
+  selectIdValue,
+  ensureEntitiesArray,
+  splitAddedUpdatedEntities,
+  getCurrent,
+} from './utils'
+
+// Borrowed from Replay
+export function findInsertIndex<T>(
+  sortedItems: T[],
+  item: T,
+  comparisonFunction: Comparer<T>,
+): number {
+  let lowIndex = 0
+  let highIndex = sortedItems.length
+  while (lowIndex < highIndex) {
+    let middleIndex = (lowIndex + highIndex) >>> 1
+    const currentItem = sortedItems[middleIndex]
+    const res = comparisonFunction(item, currentItem)
+    if (res >= 0) {
+      lowIndex = middleIndex + 1
+    } else {
+      highIndex = middleIndex
+    }
+  }
+
+  return lowIndex
+}
+
+export function insert<T>(
+  sortedItems: T[],
+  item: T,
+  comparisonFunction: Comparer<T>,
+): T[] {
+  const insertAtIndex = findInsertIndex(sortedItems, item, comparisonFunction)
+
+  sortedItems.splice(insertAtIndex, 0, item)
+
+  return sortedItems
+}
+
+export function createSortedStateAdapter<T, Id extends EntityId>(
+  selectId: IdSelector<T, Id>,
+  comparer: Comparer<T>,
+): EntityStateAdapter<T, Id> {
+  type R = DraftableEntityState<T, Id>
+
+  const { removeOne, removeMany, removeAll } =
+    createUnsortedStateAdapter(selectId)
+
+  function addOneMutably(entity: T, state: R): void {
+    return addManyMutably([entity], state)
+  }
+
+  function addManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+    existingIds?: Id[],
+  ): void {
+    newEntities = ensureEntitiesArray(newEntities)
+
+    const existingKeys = new Set<Id>(existingIds ?? getCurrent(state.ids))
+    const addedKeys = new Set<Id>();
+    const models = newEntities.filter(
+      (model) => {
+          const modelId = selectIdValue(model, selectId);
+          const notAdded = !addedKeys.has(modelId);
+          if (notAdded) addedKeys.add(modelId);
+          return !existingKeys.has(modelId) && notAdded;
+      }
+    )
+
+    if (models.length !== 0) {
+      mergeFunction(state, models)
+    }
+  }
+
+  function setOneMutably(entity: T, state: R): void {
+    return setManyMutably([entity], state)
+  }
+
+  function setManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    let deduplicatedEntities = {} as Record<Id, T>;
+    newEntities = ensureEntitiesArray(newEntities)
+    if (newEntities.length !== 0) {
+      for (const item of newEntities) {
+        const entityId = selectId(item);
+        // For multiple items with the same ID, we should keep the last one.
+        deduplicatedEntities[entityId] = item;
+        delete (state.entities as Record<Id, T>)[entityId]
+      }
+      newEntities = ensureEntitiesArray(deduplicatedEntities);
+      mergeFunction(state, newEntities)
+    }
+  }
+
+  function setAllMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    newEntities = ensureEntitiesArray(newEntities)
+    state.entities = {} as Record<Id, T>
+    state.ids = []
+
+    addManyMutably(newEntities, state, [])
+  }
+
+  function updateOneMutably(update: Update<T, Id>, state: R): void {
+    return updateManyMutably([update], state)
+  }
+
+  function updateManyMutably(
+    updates: ReadonlyArray<Update<T, Id>>,
+    state: R,
+  ): void {
+    let appliedUpdates = false
+    let replacedIds = false
+
+    for (let update of updates) {
+      const entity: T | undefined = (state.entities as Record<Id, T>)[update.id]
+      if (!entity) {
+        continue
+      }
+
+      appliedUpdates = true
+
+      Object.assign(entity, update.changes)
+      const newId = selectId(entity)
+
+      if (update.id !== newId) {
+        // We do support the case where updates can change an item's ID.
+        // This makes things trickier - go ahead and swap the IDs in state now.
+        replacedIds = true
+        delete (state.entities as Record<Id, T>)[update.id]
+        const oldIndex = (state.ids as Id[]).indexOf(update.id)
+        state.ids[oldIndex] = newId
+        ;(state.entities as Record<Id, T>)[newId] = entity
+      }
+    }
+
+    if (appliedUpdates) {
+      mergeFunction(state, [], appliedUpdates, replacedIds)
+    }
+  }
+
+  function upsertOneMutably(entity: T, state: R): void {
+    return upsertManyMutably([entity], state)
+  }
+
+  function upsertManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    const [added, updated, existingIdsArray] = splitAddedUpdatedEntities<T, Id>(
+      newEntities,
+      selectId,
+      state,
+    )
+
+    if (added.length) {
+      addManyMutably(added, state, existingIdsArray)
+    }
+    if (updated.length) {
+      updateManyMutably(updated, state)
+    }
+  }
+
+  function areArraysEqual(a: readonly unknown[], b: readonly unknown[]) {
+    if (a.length !== b.length) {
+      return false
+    }
+
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] === b[i]) {
+        continue
+      }
+      return false
+    }
+    return true
+  }
+
+  type MergeFunction = (
+    state: R,
+    addedItems: readonly T[],
+    appliedUpdates?: boolean,
+    replacedIds?: boolean,
+  ) => void
+
+  const mergeFunction: MergeFunction = (
+    state,
+    addedItems,
+    appliedUpdates,
+    replacedIds,
+  ) => {
+    const currentEntities = getCurrent(state.entities)
+    const currentIds = getCurrent(state.ids)
+
+    const stateEntities = state.entities as Record<Id, T>
+
+    let ids: Iterable<Id> = currentIds
+    if (replacedIds) {
+      ids = new Set(currentIds)
+    }
+
+    let sortedEntities: T[] = []
+    for (const id of ids) {
+      const entity = currentEntities[id]
+      if (entity) {
+        sortedEntities.push(entity)
+      }
+    }
+    const wasPreviouslyEmpty = sortedEntities.length === 0
+
+    // Insert/overwrite all new/updated
+    for (const item of addedItems) {
+      stateEntities[selectId(item)] = item
+
+      if (!wasPreviouslyEmpty) {
+        // Binary search insertion generally requires fewer comparisons
+        insert(sortedEntities, item, comparer)
+      }
+    }
+
+    if (wasPreviouslyEmpty) {
+      // All we have is the incoming values, sort them
+      sortedEntities = addedItems.slice().sort(comparer)
+    } else if (appliedUpdates) {
+      // We should have a _mostly_-sorted array already
+      sortedEntities.sort(comparer)
+    }
+
+    const newSortedIds = sortedEntities.map(selectId)
+
+    if (!areArraysEqual(currentIds, newSortedIds)) {
+      state.ids = newSortedIds
+    }
+  }
+
+  return {
+    removeOne,
+    removeMany,
+    removeAll,
+    addOne: createStateOperator(addOneMutably),
+    updateOne: createStateOperator(updateOneMutably),
+    upsertOne: createStateOperator(upsertOneMutably),
+    setOne: createStateOperator(setOneMutably),
+    setMany: createStateOperator(setManyMutably),
+    setAll: createStateOperator(setAllMutably),
+    addMany: createStateOperator(addManyMutably),
+    updateMany: createStateOperator(updateManyMutably),
+    upsertMany: createStateOperator(upsertManyMutably),
+  }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/state_adapter.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,58 @@
+import { createNextState, isDraft } from '../immerImports'
+import type { Draft } from 'immer'
+import type { EntityId, DraftableEntityState, PreventAny } from './models'
+import type { PayloadAction } from '../createAction'
+import { isFSA } from '../createAction'
+
+export const isDraftTyped = isDraft as <T>(
+  value: T | Draft<T>,
+) => value is Draft<T>
+
+export function createSingleArgumentStateOperator<T, Id extends EntityId>(
+  mutator: (state: DraftableEntityState<T, Id>) => void,
+) {
+  const operator = createStateOperator(
+    (_: undefined, state: DraftableEntityState<T, Id>) => mutator(state),
+  )
+
+  return function operation<S extends DraftableEntityState<T, Id>>(
+    state: PreventAny<S, T, Id>,
+  ): S {
+    return operator(state as S, undefined)
+  }
+}
+
+export function createStateOperator<T, Id extends EntityId, R>(
+  mutator: (arg: R, state: DraftableEntityState<T, Id>) => void,
+) {
+  return function operation<S extends DraftableEntityState<T, Id>>(
+    state: S,
+    arg: R | PayloadAction<R>,
+  ): S {
+    function isPayloadActionArgument(
+      arg: R | PayloadAction<R>,
+    ): arg is PayloadAction<R> {
+      return isFSA(arg)
+    }
+
+    const runMutator = (draft: DraftableEntityState<T, Id>) => {
+      if (isPayloadActionArgument(arg)) {
+        mutator(arg.payload, draft)
+      } else {
+        mutator(arg, draft)
+      }
+    }
+
+    if (isDraftTyped<DraftableEntityState<T, Id>>(state)) {
+      // we must already be inside a `createNextState` call, likely because
+      // this is being wrapped in `createReducer` or `createSlice`.
+      // It's safe to just pass the draft to the mutator.
+      runMutator(state)
+
+      // since it's a draft, we'll just return it
+      return state
+    }
+
+    return createNextState(state, runMutator)
+  }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/state_selectors.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/state_selectors.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/state_selectors.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,73 @@
+import type { CreateSelectorFunction, Selector } from 'reselect'
+import { createDraftSafeSelector } from '../createDraftSafeSelector'
+import type { EntityId, EntitySelectors, EntityState } from './models'
+
+type AnyCreateSelectorFunction = CreateSelectorFunction<any, any, any>
+
+export type GetSelectorsOptions = {
+  createSelector?: AnyCreateSelectorFunction
+}
+
+export function createSelectorsFactory<T, Id extends EntityId>() {
+  function getSelectors(
+    selectState?: undefined,
+    options?: GetSelectorsOptions,
+  ): EntitySelectors<T, EntityState<T, Id>, Id>
+  function getSelectors<V>(
+    selectState: (state: V) => EntityState<T, Id>,
+    options?: GetSelectorsOptions,
+  ): EntitySelectors<T, V, Id>
+  function getSelectors<V>(
+    selectState?: (state: V) => EntityState<T, Id>,
+    options: GetSelectorsOptions = {},
+  ): EntitySelectors<T, any, Id> {
+    const {
+      createSelector = createDraftSafeSelector as AnyCreateSelectorFunction,
+    } = options
+
+    const selectIds = (state: EntityState<T, Id>) => state.ids
+
+    const selectEntities = (state: EntityState<T, Id>) => state.entities
+
+    const selectAll = createSelector(
+      selectIds,
+      selectEntities,
+      (ids, entities): T[] => ids.map((id) => entities[id]!),
+    )
+
+    const selectId = (_: unknown, id: Id) => id
+
+    const selectById = (entities: Record<Id, T>, id: Id) => entities[id]
+
+    const selectTotal = createSelector(selectIds, (ids) => ids.length)
+
+    if (!selectState) {
+      return {
+        selectIds,
+        selectEntities,
+        selectAll,
+        selectTotal,
+        selectById: createSelector(selectEntities, selectId, selectById),
+      }
+    }
+
+    const selectGlobalizedEntities = createSelector(
+      selectState as Selector<V, EntityState<T, Id>>,
+      selectEntities,
+    )
+
+    return {
+      selectIds: createSelector(selectState, selectIds),
+      selectEntities: selectGlobalizedEntities,
+      selectAll: createSelector(selectState, selectAll),
+      selectTotal: createSelector(selectState, selectTotal),
+      selectById: createSelector(
+        selectGlobalizedEntities,
+        selectId,
+        selectById,
+      ),
+    }
+  }
+
+  return { getSelectors }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/tests/entity_slice_enhancer.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/entity_slice_enhancer.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/entity_slice_enhancer.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,59 @@
+import { createEntityAdapter, createSlice } from '../..'
+import type {
+  PayloadAction,
+  Slice,
+  SliceCaseReducers,
+  UnknownAction,
+} from '../..'
+import type { EntityId, EntityState, IdSelector } from '../models'
+import type { BookModel } from './fixtures/book'
+
+describe('Entity Slice Enhancer', () => {
+  let slice: Slice<EntityState<BookModel, BookModel['id']>>
+
+  beforeEach(() => {
+    const indieSlice = entitySliceEnhancer({
+      name: 'book',
+      selectId: (book: BookModel) => book.id,
+    })
+    slice = indieSlice
+  })
+
+  it('exposes oneAdded', () => {
+    const book = {
+      id: '0',
+      title: 'Der Steppenwolf',
+      author: 'Herman Hesse',
+    }
+    const action = slice.actions.oneAdded(book)
+    const oneAdded = slice.reducer(undefined, action as UnknownAction)
+    expect(oneAdded.entities['0']).toBe(book)
+  })
+})
+
+interface EntitySliceArgs<T, Id extends EntityId> {
+  name: string
+  selectId: IdSelector<T, Id>
+  modelReducer?: SliceCaseReducers<T>
+}
+
+function entitySliceEnhancer<T, Id extends EntityId>({
+  name,
+  selectId,
+  modelReducer,
+}: EntitySliceArgs<T, Id>) {
+  const modelAdapter = createEntityAdapter({
+    selectId,
+  })
+
+  return createSlice({
+    name,
+    initialState: modelAdapter.getInitialState(),
+    reducers: {
+      oneAdded(state, action: PayloadAction<T>) {
+        modelAdapter.addOne(state, action.payload)
+      },
+      ...modelReducer,
+    },
+  })
+}
Index: node_modules/@reduxjs/toolkit/src/entities/tests/entity_state.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/entity_state.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/entity_state.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,104 @@
+import type { EntityAdapter } from '../index'
+import { createEntityAdapter } from '../index'
+import type { PayloadAction } from '../../createAction'
+import { createAction } from '../../createAction'
+import { createSlice } from '../../createSlice'
+import type { BookModel } from './fixtures/book'
+
+describe('Entity State', () => {
+  let adapter: EntityAdapter<BookModel, string>
+
+  beforeEach(() => {
+    adapter = createEntityAdapter({
+      selectId: (book: BookModel) => book.id,
+    })
+  })
+
+  it('should let you get the initial state', () => {
+    const initialState = adapter.getInitialState()
+
+    expect(initialState).toEqual({
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you provide additional initial state properties', () => {
+    const additionalProperties = { isHydrated: true }
+
+    const initialState = adapter.getInitialState(additionalProperties)
+
+    expect(initialState).toEqual({
+      ...additionalProperties,
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you provide initial entities', () => {
+    const book1: BookModel = { id: 'a', title: 'First' }
+
+    const initialState = adapter.getInitialState(undefined, [book1])
+
+    expect(initialState).toEqual({
+      ids: [book1.id],
+      entities: { [book1.id]: book1 },
+    })
+
+    const additionalProperties = { isHydrated: true }
+
+    const initialState2 = adapter.getInitialState(additionalProperties, [book1])
+
+    expect(initialState2).toEqual({
+      ...additionalProperties,
+      ids: [book1.id],
+      entities: { [book1.id]: book1 },
+    })
+  })
+
+  it('should allow methods to be passed as reducers', () => {
+    const upsertBook = createAction<BookModel>('otherBooks/upsert')
+
+    const booksSlice = createSlice({
+      name: 'books',
+      initialState: adapter.getInitialState(),
+      reducers: {
+        addOne: adapter.addOne,
+        removeOne(state, action: PayloadAction<string>) {
+          // TODO The nested `produce` calls don't mutate `state` here as I would have expected.
+          // TODO (note that `state` here is actually an Immer Draft<S>, from `createReducer`)
+          // TODO However, this works if we _return_ the new plain result value instead
+          // TODO See https://github.com/immerjs/immer/issues/533
+          const result = adapter.removeOne(state, action)
+          return result
+        },
+      },
+      extraReducers: (builder) => {
+        builder.addCase(upsertBook, (state, action) => {
+          return adapter.upsertOne(state, action)
+        })
+      },
+    })
+
+    const { addOne, removeOne } = booksSlice.actions
+    const { reducer } = booksSlice
+
+    const selectors = adapter.getSelectors()
+
+    const book1: BookModel = { id: 'a', title: 'First' }
+    const book1a: BookModel = { id: 'a', title: 'Second' }
+
+    const afterAddOne = reducer(undefined, addOne(book1))
+    expect(afterAddOne.entities[book1.id]).toBe(book1)
+
+    const afterRemoveOne = reducer(afterAddOne, removeOne(book1.id))
+    expect(afterRemoveOne.entities[book1.id]).toBeUndefined()
+    expect(selectors.selectTotal(afterRemoveOne)).toBe(0)
+
+    const afterUpsertFirst = reducer(afterRemoveOne, upsertBook(book1))
+    const afterUpsertSecond = reducer(afterUpsertFirst, upsertBook(book1a))
+
+    expect(afterUpsertSecond.entities[book1.id]).toEqual(book1a)
+    expect(selectors.selectTotal(afterUpsertSecond)).toBe(1)
+  })
+})
Index: node_modules/@reduxjs/toolkit/src/entities/tests/fixtures/book.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/fixtures/book.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/fixtures/book.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,26 @@
+export interface BookModel {
+  id: string
+  title: string
+  author?: string
+}
+
+export const AClockworkOrange: BookModel = Object.freeze({
+  id: 'aco',
+  title: 'A Clockwork Orange',
+})
+
+export const AnimalFarm: BookModel = Object.freeze({
+  id: 'af',
+  title: 'Animal Farm',
+})
+
+export const TheGreatGatsby: BookModel = Object.freeze({
+  id: 'tgg',
+  title: 'The Great Gatsby',
+})
+
+export const TheHobbit: BookModel = Object.freeze({
+  id: 'th',
+  title: 'The Hobbit',
+  author: 'J. R. R. Tolkien',
+})
Index: node_modules/@reduxjs/toolkit/src/entities/tests/sorted_state_adapter.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/sorted_state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/sorted_state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,1181 @@
+import type { PayloadAction } from '@reduxjs/toolkit'
+import {
+  configureStore,
+  createAction,
+  createSlice,
+  nanoid,
+} from '@reduxjs/toolkit'
+import { createNextState } from '../..'
+import { createEntityAdapter } from '../create_adapter'
+import type { EntityAdapter, EntityState } from '../models'
+import type { BookModel } from './fixtures/book'
+import {
+  AClockworkOrange,
+  AnimalFarm,
+  TheGreatGatsby,
+  TheHobbit,
+} from './fixtures/book'
+
+describe('Sorted State Adapter', () => {
+  let adapter: EntityAdapter<BookModel, string>
+  let state: EntityState<BookModel, string>
+
+  beforeAll(() => {
+    //eslint-disable-next-line
+    Object.defineProperty(Array.prototype, 'unwantedField', {
+      enumerable: true,
+      configurable: true,
+      value: 'This should not appear anywhere',
+    })
+  })
+
+  afterAll(() => {
+    delete (Array.prototype as any).unwantedField
+  })
+
+  beforeEach(() => {
+    adapter = createEntityAdapter({
+      selectId: (book: BookModel) => book.id,
+      sortComparer: (a, b) => {
+        return a.title.localeCompare(b.title)
+      },
+    })
+
+    state = { ids: [], entities: {} }
+  })
+
+  it('should let you add one entity to the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    expect(withOneEntity).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you add one entity to the state as an FSA', () => {
+    const bookAction = createAction<BookModel>('books/add')
+    const withOneEntity = adapter.addOne(state, bookAction(TheGreatGatsby))
+
+    expect(withOneEntity).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should not change state if you attempt to re-add an entity', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const readded = adapter.addOne(withOneEntity, TheGreatGatsby)
+
+    expect(readded).toBe(withOneEntity)
+  })
+
+  it('should let you add many entities to the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withManyMore = adapter.addMany(withOneEntity, [
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    expect(withManyMore).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you add many entities to the state from a dictionary', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withManyMore = adapter.addMany(withOneEntity, {
+      [AClockworkOrange.id]: AClockworkOrange,
+      [AnimalFarm.id]: AnimalFarm,
+    })
+
+    expect(withManyMore).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should remove existing and add new ones on setAll', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withAll = adapter.setAll(withOneEntity, [
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    expect(withAll).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should remove existing and add new ones on setAll when passing in a dictionary', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withAll = adapter.setAll(withOneEntity, {
+      [AClockworkOrange.id]: AClockworkOrange,
+      [AnimalFarm.id]: AnimalFarm,
+    })
+
+    expect(withAll).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should remove existing and add new ones on addAll (deprecated)', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withAll = adapter.setAll(withOneEntity, [
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    expect(withAll).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you add remove an entity from the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withoutOne = adapter.removeOne(withOneEntity, TheGreatGatsby.id)
+
+    expect(withoutOne).toEqual({
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you remove many entities by id from the state', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    const withoutMany = adapter.removeMany(withAll, [
+      TheGreatGatsby.id,
+      AClockworkOrange.id,
+    ])
+
+    expect(withoutMany).toEqual({
+      ids: [AnimalFarm.id],
+      entities: {
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you remove all entities from the state', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    const withoutAll = adapter.removeAll(withAll)
+
+    expect(withoutAll).toEqual({
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you update an entity in the state', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should not change state if you attempt to update an entity that has not been added', () => {
+    const withUpdates = adapter.updateOne(state, {
+      id: TheGreatGatsby.id,
+      changes: { title: 'A New Title' },
+    })
+
+    expect(withUpdates).toBe(state)
+  })
+
+  it('Replaces an existing entity if you change the ID while updating', () => {
+    const a = { id: 'a', title: 'First' }
+    const b = { id: 'b', title: 'Second' }
+    const c = { id: 'c', title: 'Third' }
+    const d = { id: 'd', title: 'Fourth' }
+    const withAdded = adapter.setAll(state, [a, b, c])
+
+    const withUpdated = adapter.updateOne(withAdded, {
+      id: 'b',
+      changes: {
+        id: 'c',
+      },
+    })
+
+    const { ids, entities } = withUpdated
+
+    expect(ids).toEqual(['a', 'c'])
+    expect(entities.a).toBeTruthy()
+    expect(entities.b).not.toBeTruthy()
+    expect(entities.c).toBeTruthy()
+    expect(entities.c!.id).toBe('c')
+    expect(entities.c!.title).toBe('Second')
+  })
+
+  it('should not change ids state if you attempt to update an entity that does not impact sorting', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+    const changes = { title: 'The Great Gatsby II' }
+
+    const withUpdates = adapter.updateOne(withAll, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withAll.ids).toBe(withUpdates.ids)
+  })
+
+  it('should let you update the id of entity', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { id: 'A New Id' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [changes.id],
+      entities: {
+        [changes.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should resort correctly if same id but sort key update', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AnimalFarm,
+      AClockworkOrange,
+    ])
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.updateOne(withAll, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [AClockworkOrange.id, TheGreatGatsby.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should resort correctly if the id and sort key update', () => {
+    const withOne = adapter.setAll(state, [
+      TheGreatGatsby,
+      AnimalFarm,
+      AClockworkOrange,
+    ])
+    const changes = { id: 'A New Id', title: 'A New Hope' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [AClockworkOrange.id, changes.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [changes.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should maintain a stable sorting order when updating items', () => {
+    interface OrderedEntity {
+      id: string
+      order: number
+      ts: number
+    }
+    const sortedItemsAdapter = createEntityAdapter<OrderedEntity>({
+      sortComparer: (a, b) => a.order - b.order,
+    })
+    const withInitialItems = sortedItemsAdapter.setAll(
+      sortedItemsAdapter.getInitialState(),
+      [
+        { id: 'C', order: 3, ts: 0 },
+        { id: 'A', order: 1, ts: 0 },
+        { id: 'F', order: 4, ts: 0 },
+        { id: 'B', order: 2, ts: 0 },
+        { id: 'D', order: 3, ts: 0 },
+        { id: 'E', order: 3, ts: 0 },
+      ],
+    )
+
+    expect(withInitialItems.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F'])
+
+    const updated = sortedItemsAdapter.updateOne(withInitialItems, {
+      id: 'C',
+      changes: { ts: 5 },
+    })
+
+    expect(updated.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F'])
+
+    const updated2 = sortedItemsAdapter.updateOne(withInitialItems, {
+      id: 'D',
+      changes: { ts: 6 },
+    })
+
+    expect(updated2.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F'])
+  })
+
+  it('should let you update many entities by id in the state', () => {
+    const firstChange = { title: 'Zack' }
+    const secondChange = { title: 'Aaron' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby, AClockworkOrange])
+
+    const withUpdates = adapter.updateMany(withMany, [
+      { id: TheGreatGatsby.id, changes: firstChange },
+      { id: AClockworkOrange.id, changes: secondChange },
+    ])
+
+    expect(withUpdates).toEqual({
+      ids: [AClockworkOrange.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: {
+          ...AClockworkOrange,
+          ...secondChange,
+        },
+      },
+    })
+  })
+
+  it('should let you add one entity to the state with upsert()', () => {
+    const withOneEntity = adapter.upsertOne(state, TheGreatGatsby)
+    expect(withOneEntity).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you update an entity in the state with upsert()', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.upsertOne(withOne, {
+      ...TheGreatGatsby,
+      ...changes,
+    })
+    expect(withUpdates).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should let you upsert many entities in the state', () => {
+    const firstChange = { title: 'Zack' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, [
+      { ...TheGreatGatsby, ...firstChange },
+      AClockworkOrange,
+    ])
+
+    expect(withUpserts).toEqual({
+      ids: [AClockworkOrange.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should do nothing when upsertMany is given an empty array', () => {
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, [])
+
+    expect(withUpserts).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should throw when upsertMany is passed undefined or null', async () => {
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const fakeRequest = (response: null | undefined) =>
+      new Promise((resolve) => setTimeout(() => resolve(response), 50))
+
+    const undefinedBooks = (await fakeRequest(undefined)) as BookModel[]
+    expect(() => adapter.upsertMany(withMany, undefinedBooks)).toThrow()
+
+    const nullBooks = (await fakeRequest(null)) as BookModel[]
+    expect(() => adapter.upsertMany(withMany, nullBooks)).toThrow()
+  })
+
+  it('should let you upsert many entities in the state when passing in a dictionary', () => {
+    const firstChange = { title: 'Zack' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, {
+      [TheGreatGatsby.id]: { ...TheGreatGatsby, ...firstChange },
+      [AClockworkOrange.id]: AClockworkOrange,
+    })
+
+    expect(withUpserts).toEqual({
+      ids: [AClockworkOrange.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should let you add a new entity then apply changes to it', () => {
+    const firstChange = { author: TheHobbit.author }
+    const secondChange = { title: 'Zack' }
+    const withMany = adapter.setAll(state, [AClockworkOrange])
+
+    const withUpserts = adapter.upsertMany(withMany, [
+      {...TheGreatGatsby}, { ...TheGreatGatsby, ...firstChange }, {...TheGreatGatsby, ...secondChange}
+    ])
+
+    expect(withUpserts).toEqual({
+      ids: [AClockworkOrange.id, TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+          ...secondChange,
+        },
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should let you add a new entity in the state with setOne() and keep the sorting', () => {
+    const withMany = adapter.setAll(state, [AnimalFarm, TheHobbit])
+    const withOneMore = adapter.setOne(withMany, TheGreatGatsby)
+    expect(withOneMore).toEqual({
+      ids: [AnimalFarm.id, TheGreatGatsby.id, TheHobbit.id],
+      entities: {
+        [AnimalFarm.id]: AnimalFarm,
+        [TheHobbit.id]: TheHobbit,
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you replace an entity in the state with setOne()', () => {
+    let withOne = adapter.setOne(state, TheHobbit)
+    const changeWithoutAuthor = { id: TheHobbit.id, title: 'Silmarillion' }
+    withOne = adapter.setOne(withOne, changeWithoutAuthor)
+
+    expect(withOne).toEqual({
+      ids: [TheHobbit.id],
+      entities: {
+        [TheHobbit.id]: changeWithoutAuthor,
+      },
+    })
+  })
+
+  it('should do nothing when setMany is given an empty array', () => {
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.setMany(withMany, [])
+
+    expect(withUpserts).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you set many entities in the state', () => {
+    const firstChange = { id: TheHobbit.id, title: 'Silmarillion' }
+    const withMany = adapter.setAll(state, [TheHobbit])
+
+    const withSetMany = adapter.setMany(withMany, [
+      firstChange,
+      AClockworkOrange,
+    ])
+
+    expect(withSetMany).toEqual({
+      ids: [AClockworkOrange.id, TheHobbit.id],
+      entities: {
+        [TheHobbit.id]: firstChange,
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should work consistent with Unsorted State Adapter adding duplicate ids', () => {
+    const unsortedAdaptor = createEntityAdapter({
+      selectId: (book: BookModel) => book.id
+    });
+
+    const firstEntry = {id: AClockworkOrange.id, author: TheHobbit.author }
+    const secondEntry = {id: AClockworkOrange.id, title: 'Zack' }
+    const withNothingSorted = adapter.setAll(state, []);
+    const withNothingUnsorted = unsortedAdaptor.setAll(state, []);
+    const withOneSorted = adapter.addMany(withNothingSorted, [
+      { ...AClockworkOrange, ...firstEntry }, {...AClockworkOrange, ...secondEntry}
+    ])
+    const withOneUnsorted = adapter.addMany(withNothingUnsorted, [
+      { ...AClockworkOrange, ...firstEntry }, {...AClockworkOrange, ...secondEntry}
+    ])
+
+    expect(withOneSorted).toEqual(withOneUnsorted);
+  })
+
+  it('should work consistent with Unsorted State Adapter adding duplicate ids', () => {
+    const unsortedAdaptor = createEntityAdapter({
+      selectId: (book: BookModel) => book.id
+    });
+
+    const firstEntry = {id: AClockworkOrange.id, author: TheHobbit.author }
+    const secondEntry = {id: AClockworkOrange.id, title: 'Zack' }
+    const withNothingSorted = adapter.setAll(state, [TheHobbit]);
+    const withNothingUnsorted = unsortedAdaptor.setAll(state, [TheHobbit]);
+    const withOneSorted = adapter.setMany(withNothingSorted, [
+      { ...AClockworkOrange, ...firstEntry, id: 'th' }, {...AClockworkOrange, ...secondEntry, id: 'th'}
+    ])
+    const withOneUnsorted = unsortedAdaptor.setMany(withNothingUnsorted, [
+      { ...AClockworkOrange, ...firstEntry, id: 'th' }, {...AClockworkOrange, ...secondEntry, id: 'th'}
+    ])
+
+    expect(withOneSorted).toEqual(withOneUnsorted);
+  })
+
+  it('should let you set many entities in the state when passing in a dictionary', () => {
+    const changeWithoutAuthor = { id: TheHobbit.id, title: 'Silmarillion' }
+    const withMany = adapter.setAll(state, [TheHobbit])
+
+    const withSetMany = adapter.setMany(withMany, {
+      [TheHobbit.id]: changeWithoutAuthor,
+      [AClockworkOrange.id]: AClockworkOrange,
+    })
+
+    expect(withSetMany).toEqual({
+      ids: [AClockworkOrange.id, TheHobbit.id],
+      entities: {
+        [TheHobbit.id]: changeWithoutAuthor,
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it("only returns one entry for that id in the id's array", () => {
+    const book1: BookModel = { id: 'a', title: 'First' }
+    const book2: BookModel = { id: 'b', title: 'Second' }
+    const initialState = adapter.getInitialState()
+    const withItems = adapter.addMany(initialState, [book1, book2])
+
+    expect(withItems.ids).toEqual(['a', 'b'])
+    const withUpdate = adapter.updateOne(withItems, {
+      id: 'a',
+      changes: { id: 'b' },
+    })
+
+    expect(withUpdate.ids).toEqual(['b'])
+    expect(withUpdate.entities['b']!.title).toBe(book1.title)
+  })
+
+  it('should minimize the amount of sorting work needed', () => {
+    const INITIAL_ITEMS = 10_000
+    const ADDED_ITEMS = 1_000
+
+    type Entity = { id: string; name: string; position: number }
+
+    let numSorts = 0
+
+    const adaptor = createEntityAdapter({
+      selectId: (entity: Entity) => entity.id,
+      sortComparer: (a, b) => {
+        numSorts++
+        if (a.position < b.position) return -1
+        else if (a.position > b.position) return 1
+        return 0
+      },
+    })
+
+    function generateItems(count: number) {
+      const items: readonly Entity[] = new Array(count)
+        .fill(undefined)
+        .map((x, i) => ({
+          name: `${i}`,
+          position: Math.random(),
+          id: nanoid(),
+        }))
+      return items
+    }
+
+    const entitySlice = createSlice({
+      name: 'entity',
+      initialState: adaptor.getInitialState(),
+      reducers: {
+        updateOne: adaptor.updateOne,
+        upsertOne: adaptor.upsertOne,
+        upsertMany: adaptor.upsertMany,
+        addMany: adaptor.addMany,
+      },
+    })
+
+    const store = configureStore({
+      reducer: {
+        entity: entitySlice.reducer,
+      },
+      middleware: (getDefaultMiddleware) => {
+        return getDefaultMiddleware({
+          serializableCheck: false,
+          immutableCheck: false,
+        })
+      },
+    })
+
+    numSorts = 0
+
+    const logComparisons = false
+
+    function measureComparisons(name: string, cb: () => void) {
+      numSorts = 0
+      const start = new Date().getTime()
+      cb()
+      const end = new Date().getTime()
+      const duration = end - start
+
+      if (logComparisons) {
+        console.log(
+          `${name}: sortComparer called ${numSorts.toLocaleString()} times in ${duration.toLocaleString()}ms`,
+        )
+      }
+    }
+
+    const initialItems = generateItems(INITIAL_ITEMS)
+
+    measureComparisons('Original Setup', () => {
+      store.dispatch(entitySlice.actions.upsertMany(initialItems))
+    })
+
+    expect(numSorts).toBeLessThan(INITIAL_ITEMS * 20)
+
+    measureComparisons('Insert One (random)', () => {
+      store.dispatch(
+        entitySlice.actions.upsertOne({
+          id: nanoid(),
+          position: Math.random(),
+          name: 'test',
+        }),
+      )
+    })
+
+    expect(numSorts).toBeLessThan(50)
+
+    measureComparisons('Insert One (middle)', () => {
+      store.dispatch(
+        entitySlice.actions.upsertOne({
+          id: nanoid(),
+          position: 0.5,
+          name: 'test',
+        }),
+      )
+    })
+
+    expect(numSorts).toBeLessThan(50)
+
+    measureComparisons('Insert One (end)', () => {
+      store.dispatch(
+        entitySlice.actions.upsertOne({
+          id: nanoid(),
+          position: 0.9998,
+          name: 'test',
+        }),
+      )
+    })
+
+    expect(numSorts).toBeLessThan(50)
+
+    const addedItems = generateItems(ADDED_ITEMS)
+    measureComparisons('Add Many', () => {
+      store.dispatch(entitySlice.actions.addMany(addedItems))
+    })
+
+    expect(numSorts).toBeLessThan(ADDED_ITEMS * 20)
+
+    // These numbers will vary because of the randomness, but generally
+    // with 10K items the old code had 200K+ sort calls, while the new code
+    // is around 13K sort calls.
+    expect(numSorts).toBeLessThan(20_000)
+
+    const { ids } = store.getState().entity
+    const middleItemId = ids[(ids.length / 2) | 0]
+
+    measureComparisons('Update One (end)', () => {
+      store.dispatch(
+        // Move this middle item near the end
+        entitySlice.actions.updateOne({
+          id: middleItemId,
+          changes: {
+            position: 0.99999,
+          },
+        }),
+      )
+    })
+
+    const SORTING_COUNT_BUFFER = 100
+
+    expect(numSorts).toBeLessThan(
+      INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER,
+    )
+
+    measureComparisons('Update One (middle)', () => {
+      store.dispatch(
+        // Move this middle item near the end
+        entitySlice.actions.updateOne({
+          id: middleItemId,
+          changes: {
+            position: 0.42,
+          },
+        }),
+      )
+    })
+
+    expect(numSorts).toBeLessThan(
+      INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER,
+    )
+
+    measureComparisons('Update One (replace)', () => {
+      store.dispatch(
+        // Move this middle item near the end
+        entitySlice.actions.updateOne({
+          id: middleItemId,
+          changes: {
+            id: nanoid(),
+            position: 0.98,
+          },
+        }),
+      )
+    })
+
+    expect(numSorts).toBeLessThan(
+      INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER,
+    )
+
+    // The old code was around 120K, the new code is around 10K.
+    //expect(numSorts).toBeLessThan(25_000)
+  })
+
+  it('should not throw an Immer `current` error when `state.ids` is a plain array', () => {
+    const book1: BookModel = { id: 'a', title: 'First' }
+    const initialState = adapter.getInitialState()
+    const withItems = adapter.addMany(initialState, [book1])
+    const booksSlice = createSlice({
+      name: 'books',
+      initialState,
+      reducers: {
+        testCurrentBehavior(state, action: PayloadAction<BookModel>) {
+          // Will overwrite `state.ids` with a plain array
+          adapter.removeAll(state)
+
+          // will call `splitAddedUpdatedEntities` and call `current(state.ids)`
+          adapter.upsertMany(state, [book1])
+        },
+      },
+    })
+
+    booksSlice.reducer(
+      initialState,
+      booksSlice.actions.testCurrentBehavior(book1),
+    )
+  })
+
+  it('should not throw an Immer `current` error when the adapter is called twice', () => {
+    const book1: BookModel = { id: 'a', title: 'First' }
+    const book2: BookModel = { id: 'b', title: 'Second' }
+    const initialState = adapter.getInitialState()
+    const booksSlice = createSlice({
+      name: 'books',
+      initialState,
+      reducers: {
+        testCurrentBehavior(state, action: PayloadAction<BookModel>) {
+          // Will overwrite `state.ids` with a plain array
+          adapter.removeAll(state)
+
+          // will call `splitAddedUpdatedEntities` and call `current(state.ids)`
+          adapter.addOne(state, book1)
+          adapter.addOne(state, book2)
+        },
+      },
+    })
+
+    booksSlice.reducer(
+      initialState,
+      booksSlice.actions.testCurrentBehavior(book1),
+    )
+  })
+
+  describe('can be used mutably when wrapped in createNextState', () => {
+    test('removeAll', () => {
+      const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
+      const result = createNextState(withTwo, (draft) => {
+        adapter.removeAll(draft)
+      })
+      expect(result).toEqual({
+        entities: {},
+        ids: [],
+      })
+    })
+
+    test('addOne', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.addOne(draft, TheGreatGatsby)
+      })
+
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('addMany', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.addMany(draft, [TheGreatGatsby, AnimalFarm])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['af', 'tgg'],
+      })
+    })
+
+    test('setAll', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.setAll(draft, [TheGreatGatsby, AnimalFarm])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['af', 'tgg'],
+      })
+    })
+
+    test('updateOne', () => {
+      const withOne = adapter.addOne(state, TheGreatGatsby)
+      const changes = { title: 'A New Hope' }
+      const result = createNextState(withOne, (draft) => {
+        adapter.updateOne(draft, {
+          id: TheGreatGatsby.id,
+          changes,
+        })
+      })
+
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('updateMany', () => {
+      const firstChange = { title: 'First Change' }
+      const secondChange = { title: 'Second Change' }
+      const thirdChange = { title: 'Third Change' }
+      const fourthChange = { author: 'Fourth Change' }
+      const withMany = adapter.setAll(state, [
+        TheGreatGatsby,
+        AClockworkOrange,
+        TheHobbit,
+      ])
+
+      const result = createNextState(withMany, (draft) => {
+        adapter.updateMany(draft, [
+          { id: TheHobbit.id, changes: firstChange },
+          { id: TheGreatGatsby.id, changes: secondChange },
+          { id: AClockworkOrange.id, changes: thirdChange },
+          { id: TheHobbit.id, changes: fourthChange },
+        ])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          aco: {
+            id: 'aco',
+            title: 'Third Change',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'Second Change',
+          },
+          th: {
+            author: 'Fourth Change',
+            id: 'th',
+            title: 'First Change',
+          },
+        },
+        ids: ['th', 'tgg', 'aco'],
+      })
+    })
+
+    test('upsertOne (insert)', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.upsertOne(draft, TheGreatGatsby)
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('upsertOne (update)', () => {
+      const withOne = adapter.upsertOne(state, TheGreatGatsby)
+      const result = createNextState(withOne, (draft) => {
+        adapter.upsertOne(draft, {
+          id: TheGreatGatsby.id,
+          title: 'A New Hope',
+        })
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('upsertMany', () => {
+      const withOne = adapter.upsertOne(state, TheGreatGatsby)
+      const result = createNextState(withOne, (draft) => {
+        adapter.upsertMany(draft, [
+          {
+            id: TheGreatGatsby.id,
+            title: 'A New Hope',
+          },
+          AnimalFarm,
+        ])
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg', 'af'],
+      })
+    })
+
+    test('setOne (insert)', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.setOne(draft, TheGreatGatsby)
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('setOne (update)', () => {
+      const withOne = adapter.setOne(state, TheHobbit)
+      const result = createNextState(withOne, (draft) => {
+        adapter.setOne(draft, {
+          id: TheHobbit.id,
+          title: 'Silmarillion',
+        })
+      })
+      expect(result).toEqual({
+        entities: {
+          th: {
+            id: 'th',
+            title: 'Silmarillion',
+          },
+        },
+        ids: ['th'],
+      })
+    })
+
+    test('setMany', () => {
+      const withOne = adapter.setOne(state, TheHobbit)
+      const result = createNextState(withOne, (draft) => {
+        adapter.setMany(draft, [
+          {
+            id: TheHobbit.id,
+            title: 'Silmarillion',
+          },
+          AnimalFarm,
+        ])
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          th: {
+            id: 'th',
+            title: 'Silmarillion',
+          },
+        },
+        ids: ['af', 'th'],
+      })
+    })
+
+    test('removeOne', () => {
+      const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
+      const result = createNextState(withTwo, (draft) => {
+        adapter.removeOne(draft, TheGreatGatsby.id)
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+        },
+        ids: ['af'],
+      })
+    })
+
+    test('removeMany', () => {
+      const withThree = adapter.addMany(state, [
+        TheGreatGatsby,
+        AnimalFarm,
+        AClockworkOrange,
+      ])
+      const result = createNextState(withThree, (draft) => {
+        adapter.removeMany(draft, [TheGreatGatsby.id, AnimalFarm.id])
+      })
+      expect(result).toEqual({
+        entities: {
+          aco: {
+            id: 'aco',
+            title: 'A Clockwork Orange',
+          },
+        },
+        ids: ['aco'],
+      })
+    })
+  })
+})
Index: node_modules/@reduxjs/toolkit/src/entities/tests/state_adapter.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,61 @@
+import type { EntityAdapter } from '../index'
+import { createEntityAdapter } from '../index'
+import type { PayloadAction } from '../../createAction'
+import { configureStore } from '../../configureStore'
+import { createSlice } from '../../createSlice'
+import type { BookModel } from './fixtures/book'
+
+describe('createStateOperator', () => {
+  let adapter: EntityAdapter<BookModel, string>
+
+  beforeEach(() => {
+    adapter = createEntityAdapter({
+      selectId: (book: BookModel) => book.id,
+    })
+  })
+  it('Correctly mutates a draft state when inside `createNextState', () => {
+    const booksSlice = createSlice({
+      name: 'books',
+      initialState: adapter.getInitialState(),
+      reducers: {
+        // We should be able to call an adapter method as a mutating helper in a larger reducer
+        addOne(state, action: PayloadAction<BookModel>) {
+          // Originally, having nested `produce` calls don't mutate `state` here as I would have expected.
+          // (note that `state` here is actually an Immer Draft<S>, from `createReducer`)
+          // One woarkound was to return the new plain result value instead
+          // See https://github.com/immerjs/immer/issues/533
+          // However, after tweaking `createStateOperator` to check if the argument is a draft,
+          // we can just treat the operator as strictly mutating, without returning a result,
+          // and the result should be correct.
+          const result = adapter.addOne(state, action)
+          expect(result.ids.length).toBe(1)
+          //Deliberately _don't_ return result
+        },
+        // We should also be able to pass them individually as case reducers
+        addAnother: adapter.addOne,
+      },
+    })
+
+    const { addOne, addAnother } = booksSlice.actions
+
+    const store = configureStore({
+      reducer: {
+        books: booksSlice.reducer,
+      },
+    })
+
+    const book1: BookModel = { id: 'a', title: 'First' }
+    store.dispatch(addOne(book1))
+
+    const state1 = store.getState()
+    expect(state1.books.ids.length).toBe(1)
+    expect(state1.books.entities['a']).toBe(book1)
+
+    const book2: BookModel = { id: 'b', title: 'Second' }
+    store.dispatch(addAnother(book2))
+
+    const state2 = store.getState()
+    expect(state2.books.ids.length).toBe(2)
+    expect(state2.books.entities['b']).toBe(book2)
+  })
+})
Index: node_modules/@reduxjs/toolkit/src/entities/tests/state_selectors.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/state_selectors.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/state_selectors.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,154 @@
+import { createDraftSafeSelectorCreator } from '../../createDraftSafeSelector'
+import type { EntityAdapter, EntityState } from '../index'
+import { createEntityAdapter } from '../index'
+import type { EntitySelectors } from '../models'
+import type { BookModel } from './fixtures/book'
+import { AClockworkOrange, AnimalFarm, TheGreatGatsby } from './fixtures/book'
+import type { Selector } from 'reselect'
+import { createSelector, weakMapMemoize } from 'reselect'
+import { vi } from 'vitest'
+
+describe('Entity State Selectors', () => {
+  describe('Composed Selectors', () => {
+    interface State {
+      books: EntityState<BookModel, string>
+    }
+
+    let adapter: EntityAdapter<BookModel, string>
+    let selectors: EntitySelectors<BookModel, State, string>
+    let state: State
+
+    beforeEach(() => {
+      adapter = createEntityAdapter({
+        selectId: (book: BookModel) => book.id,
+      })
+
+      state = {
+        books: adapter.setAll(adapter.getInitialState(), [
+          AClockworkOrange,
+          AnimalFarm,
+          TheGreatGatsby,
+        ]),
+      }
+
+      selectors = adapter.getSelectors((state: State) => state.books)
+    })
+
+    it('should create a selector for selecting the ids', () => {
+      const ids = selectors.selectIds(state)
+
+      expect(ids).toEqual(state.books.ids)
+    })
+
+    it('should create a selector for selecting the entities', () => {
+      const entities = selectors.selectEntities(state)
+
+      expect(entities).toEqual(state.books.entities)
+    })
+
+    it('should create a selector for selecting the list of models', () => {
+      const models = selectors.selectAll(state)
+
+      expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby])
+    })
+
+    it('should create a selector for selecting the count of models', () => {
+      const total = selectors.selectTotal(state)
+
+      expect(total).toEqual(3)
+    })
+
+    it('should create a selector for selecting a single item by ID', () => {
+      const first = selectors.selectById(state, AClockworkOrange.id)
+      expect(first).toBe(AClockworkOrange)
+      const second = selectors.selectById(state, AnimalFarm.id)
+      expect(second).toBe(AnimalFarm)
+    })
+  })
+
+  describe('Uncomposed Selectors', () => {
+    type State = EntityState<BookModel, string>
+
+    let adapter: EntityAdapter<BookModel, string>
+    let selectors: EntitySelectors<
+      BookModel,
+      EntityState<BookModel, string>,
+      string
+    >
+    let state: State
+
+    beforeEach(() => {
+      adapter = createEntityAdapter({
+        selectId: (book: BookModel) => book.id,
+      })
+
+      state = adapter.setAll(adapter.getInitialState(), [
+        AClockworkOrange,
+        AnimalFarm,
+        TheGreatGatsby,
+      ])
+
+      selectors = adapter.getSelectors()
+    })
+
+    it('should create a selector for selecting the ids', () => {
+      const ids = selectors.selectIds(state)
+
+      expect(ids).toEqual(state.ids)
+    })
+
+    it('should create a selector for selecting the entities', () => {
+      const entities = selectors.selectEntities(state)
+
+      expect(entities).toEqual(state.entities)
+    })
+
+    it('should type single entity from Dictionary as entity type or undefined', () => {
+      expectType<
+        Selector<EntityState<BookModel, string>, BookModel | undefined>
+      >(createSelector(selectors.selectEntities, (entities) => entities[0]))
+    })
+
+    it('should create a selector for selecting the list of models', () => {
+      const models = selectors.selectAll(state)
+
+      expect(models).toEqual([AClockworkOrange, AnimalFarm, TheGreatGatsby])
+    })
+
+    it('should create a selector for selecting the count of models', () => {
+      const total = selectors.selectTotal(state)
+
+      expect(total).toEqual(3)
+    })
+
+    it('should create a selector for selecting a single item by ID', () => {
+      const first = selectors.selectById(state, AClockworkOrange.id)
+      expect(first).toBe(AClockworkOrange)
+      const second = selectors.selectById(state, AnimalFarm.id)
+      expect(second).toBe(AnimalFarm)
+    })
+  })
+  describe('custom createSelector instance', () => {
+    it('should use the custom createSelector function if provided', () => {
+      const memoizeSpy = vi.fn(
+        // test that we're allowed to pass memoizers with different options, as long as they're optional
+        <F extends (...args: any[]) => any>(fn: F, param?: boolean) => fn,
+      )
+      const createCustomSelector = createDraftSafeSelectorCreator(memoizeSpy)
+
+      const adapter = createEntityAdapter({
+        selectId: (book: BookModel) => book.id,
+      })
+
+      adapter.getSelectors(undefined, { createSelector: createCustomSelector })
+
+      expect(memoizeSpy).toHaveBeenCalled()
+
+      memoizeSpy.mockClear()
+    })
+  })
+})
+
+function expectType<T>(t: T) {
+  return t
+}
Index: node_modules/@reduxjs/toolkit/src/entities/tests/unsorted_state_adapter.test.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/unsorted_state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/unsorted_state_adapter.test.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,759 @@
+import type { EntityAdapter, EntityState } from '../models'
+import { createEntityAdapter } from '../create_adapter'
+import type { BookModel } from './fixtures/book'
+import {
+  TheGreatGatsby,
+  AClockworkOrange,
+  AnimalFarm,
+  TheHobbit,
+} from './fixtures/book'
+import { createNextState } from '../..'
+
+describe('Unsorted State Adapter', () => {
+  let adapter: EntityAdapter<BookModel, string>
+  let state: EntityState<BookModel, string>
+
+  beforeAll(() => {
+    //eslint-disable-next-line
+    Object.defineProperty(Array.prototype, 'unwantedField', {
+      enumerable: true,
+      configurable: true,
+      value: 'This should not appear anywhere',
+    })
+  })
+
+  afterAll(() => {
+    delete (Array.prototype as any).unwantedField
+  })
+
+  beforeEach(() => {
+    adapter = createEntityAdapter({
+      selectId: (book: BookModel) => book.id,
+    })
+
+    state = { ids: [], entities: {} }
+  })
+
+  it('should let you add one entity to the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    expect(withOneEntity).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should not change state if you attempt to re-add an entity', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const readded = adapter.addOne(withOneEntity, TheGreatGatsby)
+
+    expect(readded).toBe(withOneEntity)
+  })
+
+  it('should let you add many entities to the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withManyMore = adapter.addMany(withOneEntity, [
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    expect(withManyMore).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you add many entities to the state from a dictionary', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withManyMore = adapter.addMany(withOneEntity, {
+      [AClockworkOrange.id]: AClockworkOrange,
+      [AnimalFarm.id]: AnimalFarm,
+    })
+
+    expect(withManyMore).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you add the only first occurrence for duplicate ids', () => {
+    const firstEntry = {id: AClockworkOrange.id, author: TheHobbit.author }
+    const secondEntry = {id: AClockworkOrange.id, title: 'Zack' }
+    const withOne = adapter.setAll(state, [TheGreatGatsby])
+    const withMany = adapter.addMany(withOne, [
+      { ...AClockworkOrange, ...firstEntry }, {...AClockworkOrange, ...secondEntry}
+    ])
+
+    expect(withMany).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: {
+          ...AClockworkOrange,
+          ...firstEntry,
+        },
+      },
+    })
+  })
+
+  it('should remove existing and add new ones on setAll', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withAll = adapter.setAll(withOneEntity, [
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    expect(withAll).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should remove existing and add new ones on setAll when passing in a dictionary', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withAll = adapter.setAll(withOneEntity, {
+      [AClockworkOrange.id]: AClockworkOrange,
+      [AnimalFarm.id]: AnimalFarm,
+    })
+
+    expect(withAll).toEqual({
+      ids: [AClockworkOrange.id, AnimalFarm.id],
+      entities: {
+        [AClockworkOrange.id]: AClockworkOrange,
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you add remove an entity from the state', () => {
+    const withOneEntity = adapter.addOne(state, TheGreatGatsby)
+
+    const withoutOne = adapter.removeOne(withOneEntity, TheGreatGatsby.id)
+
+    expect(withoutOne).toEqual({
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you remove many entities by id from the state', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    const withoutMany = adapter.removeMany(withAll, [
+      TheGreatGatsby.id,
+      AClockworkOrange.id,
+    ])
+
+    expect(withoutMany).toEqual({
+      ids: [AnimalFarm.id],
+      entities: {
+        [AnimalFarm.id]: AnimalFarm,
+      },
+    })
+  })
+
+  it('should let you remove all entities from the state', () => {
+    const withAll = adapter.setAll(state, [
+      TheGreatGatsby,
+      AClockworkOrange,
+      AnimalFarm,
+    ])
+
+    const withoutAll = adapter.removeAll(withAll)
+
+    expect(withoutAll).toEqual({
+      ids: [],
+      entities: {},
+    })
+  })
+
+  it('should let you update an entity in the state', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should not change state if you attempt to update an entity that has not been added', () => {
+    const withUpdates = adapter.updateOne(state, {
+      id: TheGreatGatsby.id,
+      changes: { title: 'A New Title' },
+    })
+
+    expect(withUpdates).toBe(state)
+  })
+
+  it('should not change ids state if you attempt to update an entity that has already been added', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withOne.ids).toBe(withUpdates.ids)
+  })
+
+  it('should let you update the id of entity', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { id: 'A New Id' }
+
+    const withUpdates = adapter.updateOne(withOne, {
+      id: TheGreatGatsby.id,
+      changes,
+    })
+
+    expect(withUpdates).toEqual({
+      ids: [changes.id],
+      entities: {
+        [changes.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should let you update many entities by id in the state', () => {
+    const firstChange = { title: 'First Change' }
+    const secondChange = { title: 'Second Change' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby, AClockworkOrange])
+
+    const withUpdates = adapter.updateMany(withMany, [
+      { id: TheGreatGatsby.id, changes: firstChange },
+      { id: AClockworkOrange.id, changes: secondChange },
+    ])
+
+    expect(withUpdates).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: {
+          ...AClockworkOrange,
+          ...secondChange,
+        },
+      },
+    })
+  })
+
+  it("doesn't break when multiple renames of one item occur", () => {
+    const withA = adapter.addOne(state, { id: 'a', title: 'First' })
+
+    const withUpdates = adapter.updateMany(withA, [
+      { id: 'a', changes: { id: 'b' } },
+      { id: 'a', changes: { id: 'c' } },
+    ])
+
+    const { ids, entities } = withUpdates
+
+    /*
+      Original code failed with a mish-mash of values, like:
+      {
+        ids: [ 'c' ],
+        entities: { b: { id: 'b', title: 'First' }, c: { id: 'c' } }
+      }
+      We now expect that only 'c' will be left:
+      { 
+        ids: [ 'c' ], 
+        entities: { c: { id: 'c', title: 'First' } } 
+      }
+    */
+    expect(ids.length).toBe(1)
+    expect(ids).toEqual(['c'])
+    expect(entities.a).toBeFalsy()
+    expect(entities.b).toBeFalsy()
+    expect(entities.c).toBeTruthy()
+  })
+
+  it('should let you add one entity to the state with upsert()', () => {
+    const withOneEntity = adapter.upsertOne(state, TheGreatGatsby)
+    expect(withOneEntity).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you update an entity in the state with upsert()', () => {
+    const withOne = adapter.addOne(state, TheGreatGatsby)
+    const changes = { title: 'A New Hope' }
+
+    const withUpdates = adapter.upsertOne(withOne, {
+      ...TheGreatGatsby,
+      ...changes,
+    })
+    expect(withUpdates).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...changes,
+        },
+      },
+    })
+  })
+
+  it('should let you upsert many entities in the state', () => {
+    const firstChange = { title: 'First Change' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, [
+      { ...TheGreatGatsby, ...firstChange },
+      AClockworkOrange,
+    ])
+
+    expect(withUpserts).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should let you upsert many entities in the state when passing in a dictionary', () => {
+    const firstChange = { title: 'Zack' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, {
+      [TheGreatGatsby.id]: { ...TheGreatGatsby, ...firstChange },
+      [AClockworkOrange.id]: AClockworkOrange,
+    })
+
+    expect(withUpserts).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id],
+      entities: {
+        [TheGreatGatsby.id]: {
+          ...TheGreatGatsby,
+          ...firstChange,
+        },
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should let you add a new entity then apply changes to it', () => {
+    const firstChange = { author: TheHobbit.author }
+    const secondChange = { title: 'Zack' }
+    const withMany = adapter.setAll(state, [TheGreatGatsby])
+
+    const withUpserts = adapter.upsertMany(withMany, [
+      {...AClockworkOrange}, { ...AClockworkOrange, ...firstChange }, {...AClockworkOrange, ...secondChange}
+    ])
+
+    expect(withUpserts).toEqual({
+      ids: [TheGreatGatsby.id, AClockworkOrange.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+        [AClockworkOrange.id]: {
+          ...AClockworkOrange,
+          ...firstChange,
+          ...secondChange,
+        },
+      },
+    })
+  })
+
+  it('should let you add a new entity in the state with setOne()', () => {
+    const withOne = adapter.setOne(state, TheGreatGatsby)
+    expect(withOne).toEqual({
+      ids: [TheGreatGatsby.id],
+      entities: {
+        [TheGreatGatsby.id]: TheGreatGatsby,
+      },
+    })
+  })
+
+  it('should let you replace an entity in the state with setOne()', () => {
+    let withOne = adapter.setOne(state, TheHobbit)
+    const changeWithoutAuthor = { id: TheHobbit.id, title: 'Silmarillion' }
+    withOne = adapter.setOne(withOne, changeWithoutAuthor)
+
+    expect(withOne).toEqual({
+      ids: [TheHobbit.id],
+      entities: {
+        [TheHobbit.id]: changeWithoutAuthor,
+      },
+    })
+  })
+
+  it('should let you set many entities in the state', () => {
+    const changeWithoutAuthor = { id: TheHobbit.id, title: 'Silmarillion' }
+    const withMany = adapter.setAll(state, [TheHobbit])
+
+    const withSetMany = adapter.setMany(withMany, [
+      changeWithoutAuthor,
+      AClockworkOrange,
+    ])
+
+    expect(withSetMany).toEqual({
+      ids: [TheHobbit.id, AClockworkOrange.id],
+      entities: {
+        [TheHobbit.id]: changeWithoutAuthor,
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+
+  it('should let you set many entities in the state when passing in a dictionary', () => {
+    const changeWithoutAuthor = { id: TheHobbit.id, title: 'Silmarillion' }
+    const withMany = adapter.setAll(state, [TheHobbit])
+
+    const withSetMany = adapter.setMany(withMany, {
+      [TheHobbit.id]: changeWithoutAuthor,
+      [AClockworkOrange.id]: AClockworkOrange,
+    })
+
+    expect(withSetMany).toEqual({
+      ids: [TheHobbit.id, AClockworkOrange.id],
+      entities: {
+        [TheHobbit.id]: changeWithoutAuthor,
+        [AClockworkOrange.id]: AClockworkOrange,
+      },
+    })
+  })
+  it("only returns one entry for that id in the id's array", () => {
+    const book1: BookModel = { id: 'a', title: 'First' }
+    const book2: BookModel = { id: 'b', title: 'Second' }
+    const initialState = adapter.getInitialState()
+    const withItems = adapter.addMany(initialState, [book1, book2])
+
+    expect(withItems.ids).toEqual(['a', 'b'])
+    const withUpdate = adapter.updateOne(withItems, {
+      id: 'a',
+      changes: { id: 'b' },
+    })
+
+    expect(withUpdate.ids).toEqual(['b'])
+    expect(withUpdate.entities['b']!.title).toBe(book1.title)
+  })
+
+  describe('can be used mutably when wrapped in createNextState', () => {
+    test('removeAll', () => {
+      const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
+      const result = createNextState(withTwo, (draft) => {
+        adapter.removeAll(draft)
+      })
+      expect(result).toEqual({
+        entities: {},
+        ids: [],
+      })
+    })
+
+    test('addOne', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.addOne(draft, TheGreatGatsby)
+      })
+
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('addMany', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.addMany(draft, [TheGreatGatsby, AnimalFarm])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg', 'af'],
+      })
+    })
+
+    test('setAll', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.setAll(draft, [TheGreatGatsby, AnimalFarm])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg', 'af'],
+      })
+    })
+
+    test('updateOne', () => {
+      const withOne = adapter.addOne(state, TheGreatGatsby)
+      const changes = { title: 'A New Hope' }
+      const result = createNextState(withOne, (draft) => {
+        adapter.updateOne(draft, {
+          id: TheGreatGatsby.id,
+          changes,
+        })
+      })
+
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('updateMany', () => {
+      const firstChange = { title: 'First Change' }
+      const secondChange = { title: 'Second Change' }
+      const thirdChange = { title: 'Third Change' }
+      const fourthChange = { author: 'Fourth Change' }
+      const withMany = adapter.setAll(state, [
+        TheGreatGatsby,
+        AClockworkOrange,
+        TheHobbit,
+      ])
+
+      const result = createNextState(withMany, (draft) => {
+        adapter.updateMany(draft, [
+          { id: TheHobbit.id, changes: firstChange },
+          { id: TheGreatGatsby.id, changes: secondChange },
+          { id: AClockworkOrange.id, changes: thirdChange },
+          { id: TheHobbit.id, changes: fourthChange },
+        ])
+      })
+
+      expect(result).toEqual({
+        entities: {
+          aco: {
+            id: 'aco',
+            title: 'Third Change',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'Second Change',
+          },
+          th: {
+            author: 'Fourth Change',
+            id: 'th',
+            title: 'First Change',
+          },
+        },
+        ids: ['tgg', 'aco', 'th'],
+      })
+    })
+
+    test('upsertOne (insert)', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.upsertOne(draft, TheGreatGatsby)
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('upsertOne (update)', () => {
+      const withOne = adapter.upsertOne(state, TheGreatGatsby)
+      const result = createNextState(withOne, (draft) => {
+        adapter.upsertOne(draft, {
+          id: TheGreatGatsby.id,
+          title: 'A New Hope',
+        })
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('upsertMany', () => {
+      const withOne = adapter.upsertOne(state, TheGreatGatsby)
+      const result = createNextState(withOne, (draft) => {
+        adapter.upsertMany(draft, [
+          {
+            id: TheGreatGatsby.id,
+            title: 'A New Hope',
+          },
+          AnimalFarm,
+        ])
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          tgg: {
+            id: 'tgg',
+            title: 'A New Hope',
+          },
+        },
+        ids: ['tgg', 'af'],
+      })
+    })
+
+    test('setOne (insert)', () => {
+      const result = createNextState(state, (draft) => {
+        adapter.setOne(draft, TheGreatGatsby)
+      })
+      expect(result).toEqual({
+        entities: {
+          tgg: {
+            id: 'tgg',
+            title: 'The Great Gatsby',
+          },
+        },
+        ids: ['tgg'],
+      })
+    })
+
+    test('setOne (update)', () => {
+      const withOne = adapter.setOne(state, TheHobbit)
+      const result = createNextState(withOne, (draft) => {
+        adapter.setOne(draft, {
+          id: TheHobbit.id,
+          title: 'Silmarillion',
+        })
+      })
+      expect(result).toEqual({
+        entities: {
+          th: {
+            id: 'th',
+            title: 'Silmarillion',
+          },
+        },
+        ids: ['th'],
+      })
+    })
+
+    test('setMany', () => {
+      const withOne = adapter.setOne(state, TheHobbit)
+      const result = createNextState(withOne, (draft) => {
+        adapter.setMany(draft, [
+          {
+            id: TheHobbit.id,
+            title: 'Silmarillion',
+          },
+          AnimalFarm,
+        ])
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+          th: {
+            id: 'th',
+            title: 'Silmarillion',
+          },
+        },
+        ids: ['th', 'af'],
+      })
+    })
+
+    test('removeOne', () => {
+      const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
+      const result = createNextState(withTwo, (draft) => {
+        adapter.removeOne(draft, TheGreatGatsby.id)
+      })
+      expect(result).toEqual({
+        entities: {
+          af: {
+            id: 'af',
+            title: 'Animal Farm',
+          },
+        },
+        ids: ['af'],
+      })
+    })
+
+    test('removeMany', () => {
+      const withThree = adapter.addMany(state, [
+        TheGreatGatsby,
+        AnimalFarm,
+        AClockworkOrange,
+      ])
+      const result = createNextState(withThree, (draft) => {
+        adapter.removeMany(draft, [TheGreatGatsby.id, AnimalFarm.id])
+      })
+      expect(result).toEqual({
+        entities: {
+          aco: {
+            id: 'aco',
+            title: 'A Clockwork Orange',
+          },
+        },
+        ids: ['aco'],
+      })
+    })
+  })
+})
Index: node_modules/@reduxjs/toolkit/src/entities/tests/utils.spec.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/tests/utils.spec.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/tests/utils.spec.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,71 @@
+import { noop } from '@internal/listenerMiddleware/utils'
+import { AClockworkOrange } from './fixtures/book'
+
+describe('Entity utils', () => {
+  describe(`selectIdValue()`, () => {
+    const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(noop)
+
+    beforeEach(() => {
+      vi.resetModules() // this is important - it clears the cache
+      vi.stubEnv('NODE_ENV', 'development')
+    })
+
+    afterEach(() => {
+      vi.unstubAllEnvs()
+      vi.clearAllMocks()
+    })
+
+    afterAll(() => {
+      vi.restoreAllMocks()
+    })
+
+    it('should not warn when key does exist', async () => {
+      const { selectIdValue } = await import('../utils')
+
+      selectIdValue(AClockworkOrange, (book: any) => book.id)
+      expect(consoleWarnSpy).not.toHaveBeenCalled()
+    })
+
+    it('should warn when key does not exist in dev mode', async () => {
+      const { selectIdValue } = await import('../utils')
+
+      expect(process.env.NODE_ENV).toBe('development')
+
+      selectIdValue(AClockworkOrange, (book: any) => book.foo)
+
+      expect(consoleWarnSpy).toHaveBeenCalledOnce()
+    })
+
+    it('should warn when key is undefined in dev mode', async () => {
+      const { selectIdValue } = await import('../utils')
+
+      expect(process.env.NODE_ENV).toBe('development')
+
+      const undefinedAClockworkOrange = { ...AClockworkOrange, id: undefined }
+      selectIdValue(undefinedAClockworkOrange, (book: any) => book.id)
+
+      expect(consoleWarnSpy).toHaveBeenCalledOnce()
+    })
+
+    it('should not warn when key does not exist in prod mode', async () => {
+      vi.stubEnv('NODE_ENV', 'production')
+
+      const { selectIdValue } = await import('../utils')
+
+      selectIdValue(AClockworkOrange, (book: any) => book.foo)
+
+      expect(consoleWarnSpy).not.toHaveBeenCalled()
+    })
+
+    it('should not warn when key is undefined in prod mode', async () => {
+      vi.stubEnv('NODE_ENV', 'production')
+
+      const { selectIdValue } = await import('../utils')
+
+      const undefinedAClockworkOrange = { ...AClockworkOrange, id: undefined }
+      selectIdValue(undefinedAClockworkOrange, (book: any) => book.id)
+
+      expect(consoleWarnSpy).not.toHaveBeenCalled()
+    })
+  })
+})
Index: node_modules/@reduxjs/toolkit/src/entities/unsorted_state_adapter.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/unsorted_state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/unsorted_state_adapter.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,204 @@
+import type { Draft } from 'immer'
+import type {
+  EntityStateAdapter,
+  IdSelector,
+  Update,
+  EntityId,
+  DraftableEntityState,
+} from './models'
+import {
+  createStateOperator,
+  createSingleArgumentStateOperator,
+} from './state_adapter'
+import {
+  selectIdValue,
+  ensureEntitiesArray,
+  splitAddedUpdatedEntities,
+} from './utils'
+
+export function createUnsortedStateAdapter<T, Id extends EntityId>(
+  selectId: IdSelector<T, Id>,
+): EntityStateAdapter<T, Id> {
+  type R = DraftableEntityState<T, Id>
+
+  function addOneMutably(entity: T, state: R): void {
+    const key = selectIdValue(entity, selectId)
+
+    if (key in state.entities) {
+      return
+    }
+
+    state.ids.push(key as Id & Draft<Id>)
+    ;(state.entities as Record<Id, T>)[key] = entity
+  }
+
+  function addManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    newEntities = ensureEntitiesArray(newEntities)
+
+    for (const entity of newEntities) {
+      addOneMutably(entity, state)
+    }
+  }
+
+  function setOneMutably(entity: T, state: R): void {
+    const key = selectIdValue(entity, selectId)
+    if (!(key in state.entities)) {
+      state.ids.push(key as Id & Draft<Id>)
+    }
+    ;(state.entities as Record<Id, T>)[key] = entity
+  }
+
+  function setManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    newEntities = ensureEntitiesArray(newEntities)
+    for (const entity of newEntities) {
+      setOneMutably(entity, state)
+    }
+  }
+
+  function setAllMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    newEntities = ensureEntitiesArray(newEntities)
+
+    state.ids = []
+    state.entities = {} as Record<Id, T>
+
+    addManyMutably(newEntities, state)
+  }
+
+  function removeOneMutably(key: Id, state: R): void {
+    return removeManyMutably([key], state)
+  }
+
+  function removeManyMutably(keys: readonly Id[], state: R): void {
+    let didMutate = false
+
+    keys.forEach((key) => {
+      if (key in state.entities) {
+        delete (state.entities as Record<Id, T>)[key]
+        didMutate = true
+      }
+    })
+
+    if (didMutate) {
+      state.ids = (state.ids as Id[]).filter((id) => id in state.entities) as
+        | Id[]
+        | Draft<Id[]>
+    }
+  }
+
+  function removeAllMutably(state: R): void {
+    Object.assign(state, {
+      ids: [],
+      entities: {},
+    })
+  }
+
+  function takeNewKey(
+    keys: { [id: string]: Id },
+    update: Update<T, Id>,
+    state: R,
+  ): boolean {
+    const original: T | undefined = (state.entities as Record<Id, T>)[update.id]
+    if (original === undefined) {
+      return false
+    }
+    const updated: T = Object.assign({}, original, update.changes)
+    const newKey = selectIdValue(updated, selectId)
+    const hasNewKey = newKey !== update.id
+
+    if (hasNewKey) {
+      keys[update.id] = newKey
+      delete (state.entities as Record<Id, T>)[update.id]
+    }
+
+    ;(state.entities as Record<Id, T>)[newKey] = updated
+
+    return hasNewKey
+  }
+
+  function updateOneMutably(update: Update<T, Id>, state: R): void {
+    return updateManyMutably([update], state)
+  }
+
+  function updateManyMutably(
+    updates: ReadonlyArray<Update<T, Id>>,
+    state: R,
+  ): void {
+    const newKeys: { [id: string]: Id } = {}
+
+    const updatesPerEntity: { [id: string]: Update<T, Id> } = {}
+
+    updates.forEach((update) => {
+      // Only apply updates to entities that currently exist
+      if (update.id in state.entities) {
+        // If there are multiple updates to one entity, merge them together
+        updatesPerEntity[update.id] = {
+          id: update.id,
+          // Spreads ignore falsy values, so this works even if there isn't
+          // an existing update already at this key
+          changes: {
+            ...updatesPerEntity[update.id]?.changes,
+            ...update.changes,
+          },
+        }
+      }
+    })
+
+    updates = Object.values(updatesPerEntity)
+
+    const didMutateEntities = updates.length > 0
+
+    if (didMutateEntities) {
+      const didMutateIds =
+        updates.filter((update) => takeNewKey(newKeys, update, state)).length >
+        0
+
+      if (didMutateIds) {
+        state.ids = Object.values(state.entities).map((e) =>
+          selectIdValue(e as T, selectId),
+        )
+      }
+    }
+  }
+
+  function upsertOneMutably(entity: T, state: R): void {
+    return upsertManyMutably([entity], state)
+  }
+
+  function upsertManyMutably(
+    newEntities: readonly T[] | Record<Id, T>,
+    state: R,
+  ): void {
+    const [added, updated] = splitAddedUpdatedEntities<T, Id>(
+      newEntities,
+      selectId,
+      state,
+    )
+
+    addManyMutably(added, state)
+    updateManyMutably(updated, state)
+  }
+
+  return {
+    removeAll: createSingleArgumentStateOperator(removeAllMutably),
+    addOne: createStateOperator(addOneMutably),
+    addMany: createStateOperator(addManyMutably),
+    setOne: createStateOperator(setOneMutably),
+    setMany: createStateOperator(setManyMutably),
+    setAll: createStateOperator(setAllMutably),
+    updateOne: createStateOperator(updateOneMutably),
+    updateMany: createStateOperator(updateManyMutably),
+    upsertOne: createStateOperator(upsertOneMutably),
+    upsertMany: createStateOperator(upsertManyMutably),
+    removeOne: createStateOperator(removeOneMutably),
+    removeMany: createStateOperator(removeManyMutably),
+  }
+}
Index: node_modules/@reduxjs/toolkit/src/entities/utils.ts
===================================================================
--- node_modules/@reduxjs/toolkit/src/entities/utils.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/@reduxjs/toolkit/src/entities/utils.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,68 @@
+import type { Draft } from 'immer'
+import { current, isDraft } from '../immerImports'
+import type {
+  DraftableEntityState,
+  EntityId,
+  IdSelector,
+  Update,
+} from './models'
+
+export function selectIdValue<T, Id extends EntityId>(
+  entity: T,
+  selectId: IdSelector<T, Id>,
+) {
+  const key = selectId(entity)
+
+  if (process.env.NODE_ENV !== 'production' && key === undefined) {
+    console.warn(
+      'The entity passed to the `selectId` implementation returned undefined.',
+      'You should probably provide your own `selectId` implementation.',
+      'The entity that was passed:',
+      entity,
+      'The `selectId` implementation:',
+      selectId.toString(),
+    )
+  }
+
+  return key
+}
+
+export function ensureEntitiesArray<T, Id extends EntityId>(
+  entities: readonly T[] | Record<Id, T>,
+): readonly T[] {
+  if (!Array.isArray(entities)) {
+    entities = Object.values(entities)
+  }
+
+  return entities
+}
+
+export function getCurrent<T>(value: T | Draft<T>): T {
+  return (isDraft(value) ? current(value) : value) as T
+}
+
+export function splitAddedUpdatedEntities<T, Id extends EntityId>(
+  newEntities: readonly T[] | Record<Id, T>,
+  selectId: IdSelector<T, Id>,
+  state: DraftableEntityState<T, Id>,
+): [T[], Update<T, Id>[], Id[]] {
+  newEntities = ensureEntitiesArray(newEntities)
+
+  const existingIdsArray = getCurrent(state.ids)
+  const existingIds = new Set<Id>(existingIdsArray)
+
+  const added: T[] = []
+  const addedIds = new Set<Id>([])
+  const updated: Update<T, Id>[] = []
+
+  for (const entity of newEntities) {
+    const id = selectIdValue(entity, selectId)
+    if (existingIds.has(id) || addedIds.has(id)) {
+      updated.push({ id, changes: entity })
+    } else {
+      addedIds.add(id)
+      added.push(entity)
+    }
+  }
+  return [added, updated, existingIdsArray]
+}
