@depup/reduxjs__toolkit 2.12.0-depup.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/changes.json +18 -0
  4. package/dist/cjs/index.js +6 -0
  5. package/dist/cjs/redux-toolkit.development.cjs +2406 -0
  6. package/dist/cjs/redux-toolkit.development.cjs.map +1 -0
  7. package/dist/cjs/redux-toolkit.production.min.cjs +3 -0
  8. package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -0
  9. package/dist/index.d.mts +2665 -0
  10. package/dist/index.d.ts +2665 -0
  11. package/dist/query/cjs/index.js +6 -0
  12. package/dist/query/cjs/rtk-query.development.cjs +3092 -0
  13. package/dist/query/cjs/rtk-query.development.cjs.map +1 -0
  14. package/dist/query/cjs/rtk-query.production.min.cjs +2 -0
  15. package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -0
  16. package/dist/query/index.d.mts +3066 -0
  17. package/dist/query/index.d.ts +3066 -0
  18. package/dist/query/react/cjs/index.js +6 -0
  19. package/dist/query/react/cjs/rtk-query-react.development.cjs +748 -0
  20. package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -0
  21. package/dist/query/react/cjs/rtk-query-react.production.min.cjs +2 -0
  22. package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -0
  23. package/dist/query/react/index.d.mts +1009 -0
  24. package/dist/query/react/index.d.ts +1009 -0
  25. package/dist/query/react/rtk-query-react.browser.mjs +2 -0
  26. package/dist/query/react/rtk-query-react.browser.mjs.map +1 -0
  27. package/dist/query/react/rtk-query-react.legacy-esm.js +740 -0
  28. package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -0
  29. package/dist/query/react/rtk-query-react.modern.mjs +705 -0
  30. package/dist/query/react/rtk-query-react.modern.mjs.map +1 -0
  31. package/dist/query/rtk-query.browser.mjs +2 -0
  32. package/dist/query/rtk-query.browser.mjs.map +1 -0
  33. package/dist/query/rtk-query.legacy-esm.js +3117 -0
  34. package/dist/query/rtk-query.legacy-esm.js.map +1 -0
  35. package/dist/query/rtk-query.modern.mjs +3052 -0
  36. package/dist/query/rtk-query.modern.mjs.map +1 -0
  37. package/dist/react/cjs/index.js +6 -0
  38. package/dist/react/cjs/redux-toolkit-react.development.cjs +55 -0
  39. package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -0
  40. package/dist/react/cjs/redux-toolkit-react.production.min.cjs +2 -0
  41. package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -0
  42. package/dist/react/index.d.mts +22 -0
  43. package/dist/react/index.d.ts +22 -0
  44. package/dist/react/redux-toolkit-react.browser.mjs +2 -0
  45. package/dist/react/redux-toolkit-react.browser.mjs.map +1 -0
  46. package/dist/react/redux-toolkit-react.legacy-esm.js +47 -0
  47. package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -0
  48. package/dist/react/redux-toolkit-react.modern.mjs +28 -0
  49. package/dist/react/redux-toolkit-react.modern.mjs.map +1 -0
  50. package/dist/redux-toolkit.browser.mjs +3 -0
  51. package/dist/redux-toolkit.browser.mjs.map +1 -0
  52. package/dist/redux-toolkit.legacy-esm.js +2351 -0
  53. package/dist/redux-toolkit.legacy-esm.js.map +1 -0
  54. package/dist/redux-toolkit.modern.mjs +2330 -0
  55. package/dist/redux-toolkit.modern.mjs.map +1 -0
  56. package/dist/uncheckedindexed.ts +16 -0
  57. package/package.json +310 -0
  58. package/query/package.json +13 -0
  59. package/query/react/package.json +13 -0
  60. package/react/package.json +13 -0
  61. package/skills/build-modern-redux-apps/modern-redux/SKILL.md +304 -0
  62. package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +53 -0
  63. package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +264 -0
  64. package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +269 -0
  65. package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +226 -0
  66. package/skills/manage-server-data/adopt-rtk-query/SKILL.md +385 -0
  67. package/skills/manage-server-data/adopt-rtk-query/references/endpoint-lifecycle.md +36 -0
  68. package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +364 -0
  69. package/skills/model-redux-state/build-slices-and-selectors/references/slice-patterns.md +59 -0
  70. package/skills/model-redux-state/design-state-ownership/SKILL.md +322 -0
  71. package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +28 -0
  72. package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +271 -0
  73. package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +34 -0
  74. package/src/actionCreatorInvariantMiddleware.ts +34 -0
  75. package/src/autoBatchEnhancer.ts +146 -0
  76. package/src/combineSlices.ts +487 -0
  77. package/src/configureStore.ts +248 -0
  78. package/src/createAction.ts +324 -0
  79. package/src/createAsyncThunk.ts +791 -0
  80. package/src/createDraftSafeSelector.ts +30 -0
  81. package/src/createReducer.ts +217 -0
  82. package/src/createSlice.ts +1079 -0
  83. package/src/devtoolsExtension.ts +241 -0
  84. package/src/dynamicMiddleware/index.ts +93 -0
  85. package/src/dynamicMiddleware/react/index.ts +101 -0
  86. package/src/dynamicMiddleware/types.ts +82 -0
  87. package/src/entities/create_adapter.ts +47 -0
  88. package/src/entities/entity_state.ts +38 -0
  89. package/src/entities/index.ts +8 -0
  90. package/src/entities/models.ts +198 -0
  91. package/src/entities/sorted_state_adapter.ts +266 -0
  92. package/src/entities/state_adapter.ts +58 -0
  93. package/src/entities/state_selectors.ts +73 -0
  94. package/src/entities/unsorted_state_adapter.ts +204 -0
  95. package/src/entities/utils.ts +68 -0
  96. package/src/formatProdErrorMessage.ts +13 -0
  97. package/src/getDefaultEnhancers.ts +31 -0
  98. package/src/getDefaultMiddleware.ts +113 -0
  99. package/src/immerImports.ts +7 -0
  100. package/src/immutableStateInvariantMiddleware.ts +274 -0
  101. package/src/index.ts +213 -0
  102. package/src/listenerMiddleware/exceptions.ts +20 -0
  103. package/src/listenerMiddleware/index.ts +562 -0
  104. package/src/listenerMiddleware/task.ts +100 -0
  105. package/src/listenerMiddleware/types.ts +886 -0
  106. package/src/listenerMiddleware/utils.ts +30 -0
  107. package/src/mapBuilders.ts +298 -0
  108. package/src/matchers.ts +365 -0
  109. package/src/nanoid.ts +20 -0
  110. package/src/query/HandledError.ts +6 -0
  111. package/src/query/apiTypes.ts +120 -0
  112. package/src/query/baseQueryTypes.ts +101 -0
  113. package/src/query/core/apiState.ts +377 -0
  114. package/src/query/core/buildInitiate.ts +596 -0
  115. package/src/query/core/buildMiddleware/batchActions.ts +207 -0
  116. package/src/query/core/buildMiddleware/cacheCollection.ts +204 -0
  117. package/src/query/core/buildMiddleware/cacheLifecycle.ts +379 -0
  118. package/src/query/core/buildMiddleware/devMiddleware.ts +34 -0
  119. package/src/query/core/buildMiddleware/index.ts +162 -0
  120. package/src/query/core/buildMiddleware/invalidationByTags.ts +139 -0
  121. package/src/query/core/buildMiddleware/polling.ts +187 -0
  122. package/src/query/core/buildMiddleware/queryLifecycle.ts +508 -0
  123. package/src/query/core/buildMiddleware/types.ts +173 -0
  124. package/src/query/core/buildMiddleware/windowEventHandling.ts +64 -0
  125. package/src/query/core/buildSelectors.ts +413 -0
  126. package/src/query/core/buildSlice.ts +735 -0
  127. package/src/query/core/buildThunks.ts +1124 -0
  128. package/src/query/core/index.ts +58 -0
  129. package/src/query/core/module.ts +727 -0
  130. package/src/query/core/rtkImports.ts +24 -0
  131. package/src/query/core/setupListeners.ts +118 -0
  132. package/src/query/createApi.ts +506 -0
  133. package/src/query/defaultSerializeQueryArgs.ts +52 -0
  134. package/src/query/endpointDefinitions.ts +1717 -0
  135. package/src/query/fakeBaseQuery.ts +21 -0
  136. package/src/query/fetchBaseQuery.ts +385 -0
  137. package/src/query/index.ts +105 -0
  138. package/src/query/react/ApiProvider.tsx +69 -0
  139. package/src/query/react/buildHooks.ts +2297 -0
  140. package/src/query/react/constants.ts +2 -0
  141. package/src/query/react/index.ts +45 -0
  142. package/src/query/react/module.ts +275 -0
  143. package/src/query/react/namedHooks.ts +59 -0
  144. package/src/query/react/reactImports.ts +10 -0
  145. package/src/query/react/reactReduxImports.ts +1 -0
  146. package/src/query/react/rtkqImports.ts +8 -0
  147. package/src/query/react/useSerializedStableValue.ts +17 -0
  148. package/src/query/react/useShallowStableValue.ts +13 -0
  149. package/src/query/retry.ts +233 -0
  150. package/src/query/standardSchema.ts +35 -0
  151. package/src/query/tsHelpers.ts +48 -0
  152. package/src/query/utils/capitalize.ts +3 -0
  153. package/src/query/utils/copyWithStructuralSharing.ts +27 -0
  154. package/src/query/utils/countObjectKeys.ts +14 -0
  155. package/src/query/utils/filterMap.ts +27 -0
  156. package/src/query/utils/getCurrent.ts +6 -0
  157. package/src/query/utils/getOrInsert.ts +41 -0
  158. package/src/query/utils/immerImports.ts +9 -0
  159. package/src/query/utils/index.ts +11 -0
  160. package/src/query/utils/isAbsoluteUrl.ts +9 -0
  161. package/src/query/utils/isDocumentVisible.ts +12 -0
  162. package/src/query/utils/isNotNullish.ts +7 -0
  163. package/src/query/utils/isOnline.ts +12 -0
  164. package/src/query/utils/isValidUrl.ts +9 -0
  165. package/src/query/utils/joinUrls.ts +26 -0
  166. package/src/query/utils/signals.ts +33 -0
  167. package/src/react/index.ts +7 -0
  168. package/src/reduxImports.ts +8 -0
  169. package/src/reselectImports.ts +1 -0
  170. package/src/serializableStateInvariantMiddleware.ts +285 -0
  171. package/src/tsHelpers.ts +214 -0
  172. package/src/uncheckedindexed.ts +16 -0
  173. package/src/utils.ts +125 -0
@@ -0,0 +1,204 @@
1
+ import type { Draft } from 'immer'
2
+ import type {
3
+ EntityStateAdapter,
4
+ IdSelector,
5
+ Update,
6
+ EntityId,
7
+ DraftableEntityState,
8
+ } from './models'
9
+ import {
10
+ createStateOperator,
11
+ createSingleArgumentStateOperator,
12
+ } from './state_adapter'
13
+ import {
14
+ selectIdValue,
15
+ ensureEntitiesArray,
16
+ splitAddedUpdatedEntities,
17
+ } from './utils'
18
+
19
+ export function createUnsortedStateAdapter<T, Id extends EntityId>(
20
+ selectId: IdSelector<T, Id>,
21
+ ): EntityStateAdapter<T, Id> {
22
+ type R = DraftableEntityState<T, Id>
23
+
24
+ function addOneMutably(entity: T, state: R): void {
25
+ const key = selectIdValue(entity, selectId)
26
+
27
+ if (key in state.entities) {
28
+ return
29
+ }
30
+
31
+ state.ids.push(key as Id & Draft<Id>)
32
+ ;(state.entities as Record<Id, T>)[key] = entity
33
+ }
34
+
35
+ function addManyMutably(
36
+ newEntities: readonly T[] | Record<Id, T>,
37
+ state: R,
38
+ ): void {
39
+ newEntities = ensureEntitiesArray(newEntities)
40
+
41
+ for (const entity of newEntities) {
42
+ addOneMutably(entity, state)
43
+ }
44
+ }
45
+
46
+ function setOneMutably(entity: T, state: R): void {
47
+ const key = selectIdValue(entity, selectId)
48
+ if (!(key in state.entities)) {
49
+ state.ids.push(key as Id & Draft<Id>)
50
+ }
51
+ ;(state.entities as Record<Id, T>)[key] = entity
52
+ }
53
+
54
+ function setManyMutably(
55
+ newEntities: readonly T[] | Record<Id, T>,
56
+ state: R,
57
+ ): void {
58
+ newEntities = ensureEntitiesArray(newEntities)
59
+ for (const entity of newEntities) {
60
+ setOneMutably(entity, state)
61
+ }
62
+ }
63
+
64
+ function setAllMutably(
65
+ newEntities: readonly T[] | Record<Id, T>,
66
+ state: R,
67
+ ): void {
68
+ newEntities = ensureEntitiesArray(newEntities)
69
+
70
+ state.ids = []
71
+ state.entities = {} as Record<Id, T>
72
+
73
+ addManyMutably(newEntities, state)
74
+ }
75
+
76
+ function removeOneMutably(key: Id, state: R): void {
77
+ return removeManyMutably([key], state)
78
+ }
79
+
80
+ function removeManyMutably(keys: readonly Id[], state: R): void {
81
+ let didMutate = false
82
+
83
+ keys.forEach((key) => {
84
+ if (key in state.entities) {
85
+ delete (state.entities as Record<Id, T>)[key]
86
+ didMutate = true
87
+ }
88
+ })
89
+
90
+ if (didMutate) {
91
+ state.ids = (state.ids as Id[]).filter((id) => id in state.entities) as
92
+ | Id[]
93
+ | Draft<Id[]>
94
+ }
95
+ }
96
+
97
+ function removeAllMutably(state: R): void {
98
+ Object.assign(state, {
99
+ ids: [],
100
+ entities: {},
101
+ })
102
+ }
103
+
104
+ function takeNewKey(
105
+ keys: { [id: string]: Id },
106
+ update: Update<T, Id>,
107
+ state: R,
108
+ ): boolean {
109
+ const original: T | undefined = (state.entities as Record<Id, T>)[update.id]
110
+ if (original === undefined) {
111
+ return false
112
+ }
113
+ const updated: T = Object.assign({}, original, update.changes)
114
+ const newKey = selectIdValue(updated, selectId)
115
+ const hasNewKey = newKey !== update.id
116
+
117
+ if (hasNewKey) {
118
+ keys[update.id] = newKey
119
+ delete (state.entities as Record<Id, T>)[update.id]
120
+ }
121
+
122
+ ;(state.entities as Record<Id, T>)[newKey] = updated
123
+
124
+ return hasNewKey
125
+ }
126
+
127
+ function updateOneMutably(update: Update<T, Id>, state: R): void {
128
+ return updateManyMutably([update], state)
129
+ }
130
+
131
+ function updateManyMutably(
132
+ updates: ReadonlyArray<Update<T, Id>>,
133
+ state: R,
134
+ ): void {
135
+ const newKeys: { [id: string]: Id } = {}
136
+
137
+ const updatesPerEntity: { [id: string]: Update<T, Id> } = {}
138
+
139
+ updates.forEach((update) => {
140
+ // Only apply updates to entities that currently exist
141
+ if (update.id in state.entities) {
142
+ // If there are multiple updates to one entity, merge them together
143
+ updatesPerEntity[update.id] = {
144
+ id: update.id,
145
+ // Spreads ignore falsy values, so this works even if there isn't
146
+ // an existing update already at this key
147
+ changes: {
148
+ ...updatesPerEntity[update.id]?.changes,
149
+ ...update.changes,
150
+ },
151
+ }
152
+ }
153
+ })
154
+
155
+ updates = Object.values(updatesPerEntity)
156
+
157
+ const didMutateEntities = updates.length > 0
158
+
159
+ if (didMutateEntities) {
160
+ const didMutateIds =
161
+ updates.filter((update) => takeNewKey(newKeys, update, state)).length >
162
+ 0
163
+
164
+ if (didMutateIds) {
165
+ state.ids = Object.values(state.entities).map((e) =>
166
+ selectIdValue(e as T, selectId),
167
+ )
168
+ }
169
+ }
170
+ }
171
+
172
+ function upsertOneMutably(entity: T, state: R): void {
173
+ return upsertManyMutably([entity], state)
174
+ }
175
+
176
+ function upsertManyMutably(
177
+ newEntities: readonly T[] | Record<Id, T>,
178
+ state: R,
179
+ ): void {
180
+ const [added, updated] = splitAddedUpdatedEntities<T, Id>(
181
+ newEntities,
182
+ selectId,
183
+ state,
184
+ )
185
+
186
+ addManyMutably(added, state)
187
+ updateManyMutably(updated, state)
188
+ }
189
+
190
+ return {
191
+ removeAll: createSingleArgumentStateOperator(removeAllMutably),
192
+ addOne: createStateOperator(addOneMutably),
193
+ addMany: createStateOperator(addManyMutably),
194
+ setOne: createStateOperator(setOneMutably),
195
+ setMany: createStateOperator(setManyMutably),
196
+ setAll: createStateOperator(setAllMutably),
197
+ updateOne: createStateOperator(updateOneMutably),
198
+ updateMany: createStateOperator(updateManyMutably),
199
+ upsertOne: createStateOperator(upsertOneMutably),
200
+ upsertMany: createStateOperator(upsertManyMutably),
201
+ removeOne: createStateOperator(removeOneMutably),
202
+ removeMany: createStateOperator(removeManyMutably),
203
+ }
204
+ }
@@ -0,0 +1,68 @@
1
+ import type { Draft } from 'immer'
2
+ import { current, isDraft } from '../immerImports'
3
+ import type {
4
+ DraftableEntityState,
5
+ EntityId,
6
+ IdSelector,
7
+ Update,
8
+ } from './models'
9
+
10
+ export function selectIdValue<T, Id extends EntityId>(
11
+ entity: T,
12
+ selectId: IdSelector<T, Id>,
13
+ ) {
14
+ const key = selectId(entity)
15
+
16
+ if (process.env.NODE_ENV !== 'production' && key === undefined) {
17
+ console.warn(
18
+ 'The entity passed to the `selectId` implementation returned undefined.',
19
+ 'You should probably provide your own `selectId` implementation.',
20
+ 'The entity that was passed:',
21
+ entity,
22
+ 'The `selectId` implementation:',
23
+ selectId.toString(),
24
+ )
25
+ }
26
+
27
+ return key
28
+ }
29
+
30
+ export function ensureEntitiesArray<T, Id extends EntityId>(
31
+ entities: readonly T[] | Record<Id, T>,
32
+ ): readonly T[] {
33
+ if (!Array.isArray(entities)) {
34
+ entities = Object.values(entities)
35
+ }
36
+
37
+ return entities
38
+ }
39
+
40
+ export function getCurrent<T>(value: T | Draft<T>): T {
41
+ return (isDraft(value) ? current(value) : value) as T
42
+ }
43
+
44
+ export function splitAddedUpdatedEntities<T, Id extends EntityId>(
45
+ newEntities: readonly T[] | Record<Id, T>,
46
+ selectId: IdSelector<T, Id>,
47
+ state: DraftableEntityState<T, Id>,
48
+ ): [T[], Update<T, Id>[], Id[]] {
49
+ newEntities = ensureEntitiesArray(newEntities)
50
+
51
+ const existingIdsArray = getCurrent(state.ids)
52
+ const existingIds = new Set<Id>(existingIdsArray)
53
+
54
+ const added: T[] = []
55
+ const addedIds = new Set<Id>([])
56
+ const updated: Update<T, Id>[] = []
57
+
58
+ for (const entity of newEntities) {
59
+ const id = selectIdValue(entity, selectId)
60
+ if (existingIds.has(id) || addedIds.has(id)) {
61
+ updated.push({ id, changes: entity })
62
+ } else {
63
+ addedIds.add(id)
64
+ added.push(entity)
65
+ }
66
+ }
67
+ return [added, updated, existingIdsArray]
68
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
3
+ *
4
+ * Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
5
+ * during build.
6
+ * @param {number} code
7
+ */
8
+ export function formatProdErrorMessage(code: number) {
9
+ return (
10
+ `Minified Redux Toolkit error #${code}; visit https://redux-toolkit.js.org/Errors?code=${code} for the full message or ` +
11
+ 'use the non-minified dev environment for full errors. '
12
+ )
13
+ }
@@ -0,0 +1,31 @@
1
+ import type { StoreEnhancer } from 'redux'
2
+ import type { AutoBatchOptions } from './autoBatchEnhancer'
3
+ import { autoBatchEnhancer } from './autoBatchEnhancer'
4
+ import { Tuple } from './utils'
5
+ import type { Middlewares } from './configureStore'
6
+ import type { ExtractDispatchExtensions } from './tsHelpers'
7
+
8
+ type GetDefaultEnhancersOptions = {
9
+ autoBatch?: boolean | AutoBatchOptions
10
+ }
11
+
12
+ export type GetDefaultEnhancers<M extends Middlewares<any>> = (
13
+ options?: GetDefaultEnhancersOptions,
14
+ ) => Tuple<[StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>]>
15
+
16
+ export const buildGetDefaultEnhancers = <M extends Middlewares<any>>(
17
+ middlewareEnhancer: StoreEnhancer<{ dispatch: ExtractDispatchExtensions<M> }>,
18
+ ): GetDefaultEnhancers<M> =>
19
+ function getDefaultEnhancers(options) {
20
+ const { autoBatch = true } = options ?? {}
21
+
22
+ let enhancerArray = new Tuple<StoreEnhancer[]>(middlewareEnhancer)
23
+ if (autoBatch) {
24
+ enhancerArray.push(
25
+ autoBatchEnhancer(
26
+ typeof autoBatch === 'object' ? autoBatch : undefined,
27
+ ),
28
+ )
29
+ }
30
+ return enhancerArray as any
31
+ }
@@ -0,0 +1,113 @@
1
+ import type { Middleware, UnknownAction } from 'redux'
2
+ import type { ThunkMiddleware } from 'redux-thunk'
3
+ import { thunk as thunkMiddleware, withExtraArgument } from 'redux-thunk'
4
+ import type { ActionCreatorInvariantMiddlewareOptions } from './actionCreatorInvariantMiddleware'
5
+ import { createActionCreatorInvariantMiddleware } from './actionCreatorInvariantMiddleware'
6
+ import type { ImmutableStateInvariantMiddlewareOptions } from './immutableStateInvariantMiddleware'
7
+ /* PROD_START_REMOVE_UMD */
8
+ import { createImmutableStateInvariantMiddleware } from './immutableStateInvariantMiddleware'
9
+ /* PROD_STOP_REMOVE_UMD */
10
+
11
+ import type { SerializableStateInvariantMiddlewareOptions } from './serializableStateInvariantMiddleware'
12
+ import { createSerializableStateInvariantMiddleware } from './serializableStateInvariantMiddleware'
13
+ import type { ExcludeFromTuple } from './tsHelpers'
14
+ import { Tuple } from './utils'
15
+
16
+ function isBoolean(x: any): x is boolean {
17
+ return typeof x === 'boolean'
18
+ }
19
+
20
+ interface ThunkOptions<E = any> {
21
+ extraArgument: E
22
+ }
23
+
24
+ interface GetDefaultMiddlewareOptions {
25
+ thunk?: boolean | ThunkOptions
26
+ immutableCheck?: boolean | ImmutableStateInvariantMiddlewareOptions
27
+ serializableCheck?: boolean | SerializableStateInvariantMiddlewareOptions
28
+ actionCreatorCheck?: boolean | ActionCreatorInvariantMiddlewareOptions
29
+ }
30
+
31
+ export type ThunkMiddlewareFor<
32
+ S,
33
+ O extends GetDefaultMiddlewareOptions = {},
34
+ > = O extends {
35
+ thunk: false
36
+ }
37
+ ? never
38
+ : O extends { thunk: { extraArgument: infer E } }
39
+ ? ThunkMiddleware<S, UnknownAction, E>
40
+ : ThunkMiddleware<S, UnknownAction>
41
+
42
+ export type GetDefaultMiddleware<S = any> = <
43
+ O extends GetDefaultMiddlewareOptions = {
44
+ thunk: true
45
+ immutableCheck: true
46
+ serializableCheck: true
47
+ actionCreatorCheck: true
48
+ },
49
+ >(
50
+ options?: O,
51
+ ) => Tuple<ExcludeFromTuple<[ThunkMiddlewareFor<S, O>], never>>
52
+
53
+ export const buildGetDefaultMiddleware = <S = any>(): GetDefaultMiddleware<S> =>
54
+ function getDefaultMiddleware(options) {
55
+ const {
56
+ thunk = true,
57
+ immutableCheck = true,
58
+ serializableCheck = true,
59
+ actionCreatorCheck = true,
60
+ } = options ?? {}
61
+
62
+ let middlewareArray = new Tuple<Middleware[]>()
63
+
64
+ if (thunk) {
65
+ if (isBoolean(thunk)) {
66
+ middlewareArray.push(thunkMiddleware)
67
+ } else {
68
+ middlewareArray.push(withExtraArgument(thunk.extraArgument))
69
+ }
70
+ }
71
+
72
+ if (process.env.NODE_ENV !== 'production') {
73
+ if (immutableCheck) {
74
+ /* PROD_START_REMOVE_UMD */
75
+ let immutableOptions: ImmutableStateInvariantMiddlewareOptions = {}
76
+
77
+ if (!isBoolean(immutableCheck)) {
78
+ immutableOptions = immutableCheck
79
+ }
80
+
81
+ middlewareArray.unshift(
82
+ createImmutableStateInvariantMiddleware(immutableOptions),
83
+ )
84
+ /* PROD_STOP_REMOVE_UMD */
85
+ }
86
+
87
+ if (serializableCheck) {
88
+ let serializableOptions: SerializableStateInvariantMiddlewareOptions =
89
+ {}
90
+
91
+ if (!isBoolean(serializableCheck)) {
92
+ serializableOptions = serializableCheck
93
+ }
94
+
95
+ middlewareArray.push(
96
+ createSerializableStateInvariantMiddleware(serializableOptions),
97
+ )
98
+ }
99
+ if (actionCreatorCheck) {
100
+ let actionCreatorOptions: ActionCreatorInvariantMiddlewareOptions = {}
101
+
102
+ if (!isBoolean(actionCreatorCheck)) {
103
+ actionCreatorOptions = actionCreatorCheck
104
+ }
105
+
106
+ middlewareArray.unshift(
107
+ createActionCreatorInvariantMiddleware(actionCreatorOptions),
108
+ )
109
+ }
110
+ }
111
+
112
+ return middlewareArray as any
113
+ }
@@ -0,0 +1,7 @@
1
+ export {
2
+ current,
3
+ isDraft,
4
+ produce as createNextState,
5
+ isDraftable,
6
+ setUseStrictIteration,
7
+ } from 'immer'
@@ -0,0 +1,274 @@
1
+ import type { Middleware } from 'redux'
2
+ import type { IgnoredPaths } from './serializableStateInvariantMiddleware'
3
+ import { getTimeMeasureUtils } from './utils'
4
+
5
+ type EntryProcessor = (key: string, value: any) => any
6
+
7
+ /**
8
+ * The default `isImmutable` function.
9
+ *
10
+ * @public
11
+ */
12
+ export function isImmutableDefault(value: unknown): boolean {
13
+ return typeof value !== 'object' || value == null || Object.isFrozen(value)
14
+ }
15
+
16
+ export function trackForMutations(
17
+ isImmutable: IsImmutableFunc,
18
+ ignoredPaths: IgnoredPaths | undefined,
19
+ obj: any,
20
+ ) {
21
+ const trackedProperties = trackProperties(isImmutable, ignoredPaths, obj)
22
+ return {
23
+ detectMutations() {
24
+ return detectMutations(isImmutable, ignoredPaths, trackedProperties, obj)
25
+ },
26
+ }
27
+ }
28
+
29
+ interface TrackedProperty {
30
+ value: any
31
+ children: Record<string, any>
32
+ }
33
+
34
+ function trackProperties(
35
+ isImmutable: IsImmutableFunc,
36
+ ignoredPaths: IgnoredPaths = [],
37
+ obj: Record<string, any>,
38
+ path: string = '',
39
+ checkedObjects: Set<Record<string, any>> = new Set(),
40
+ ) {
41
+ const tracked: Partial<TrackedProperty> = { value: obj }
42
+
43
+ if (!isImmutable(obj) && !checkedObjects.has(obj)) {
44
+ checkedObjects.add(obj)
45
+ tracked.children = {}
46
+
47
+ const hasIgnoredPaths = ignoredPaths.length > 0
48
+
49
+ for (const key in obj) {
50
+ const nestedPath = path ? path + '.' + key : key
51
+
52
+ if (hasIgnoredPaths) {
53
+ const hasMatches = ignoredPaths.some((ignored) => {
54
+ if (ignored instanceof RegExp) {
55
+ return ignored.test(nestedPath)
56
+ }
57
+ return nestedPath === ignored
58
+ })
59
+ if (hasMatches) {
60
+ continue
61
+ }
62
+ }
63
+
64
+ tracked.children[key] = trackProperties(
65
+ isImmutable,
66
+ ignoredPaths,
67
+ obj[key],
68
+ nestedPath,
69
+ )
70
+ }
71
+ }
72
+ return tracked as TrackedProperty
73
+ }
74
+
75
+ function detectMutations(
76
+ isImmutable: IsImmutableFunc,
77
+ ignoredPaths: IgnoredPaths = [],
78
+ trackedProperty: TrackedProperty,
79
+ obj: any,
80
+ sameParentRef: boolean = false,
81
+ path: string = '',
82
+ ): { wasMutated: boolean; path?: string } {
83
+ const prevObj = trackedProperty ? trackedProperty.value : undefined
84
+
85
+ const sameRef = prevObj === obj
86
+
87
+ if (sameParentRef && !sameRef && !Number.isNaN(obj)) {
88
+ return { wasMutated: true, path }
89
+ }
90
+
91
+ if (isImmutable(prevObj) || isImmutable(obj)) {
92
+ return { wasMutated: false }
93
+ }
94
+
95
+ // Gather all keys from prev (tracked) and after objs
96
+ const keysToDetect: Record<string, boolean> = {}
97
+ for (let key in trackedProperty.children) {
98
+ keysToDetect[key] = true
99
+ }
100
+ for (let key in obj) {
101
+ keysToDetect[key] = true
102
+ }
103
+
104
+ const hasIgnoredPaths = ignoredPaths.length > 0
105
+
106
+ for (let key in keysToDetect) {
107
+ const nestedPath = path ? path + '.' + key : key
108
+
109
+ if (hasIgnoredPaths) {
110
+ const hasMatches = ignoredPaths.some((ignored) => {
111
+ if (ignored instanceof RegExp) {
112
+ return ignored.test(nestedPath)
113
+ }
114
+ return nestedPath === ignored
115
+ })
116
+ if (hasMatches) {
117
+ continue
118
+ }
119
+ }
120
+
121
+ const result = detectMutations(
122
+ isImmutable,
123
+ ignoredPaths,
124
+ trackedProperty.children[key],
125
+ obj[key],
126
+ sameRef,
127
+ nestedPath,
128
+ )
129
+
130
+ if (result.wasMutated) {
131
+ return result
132
+ }
133
+ }
134
+ return { wasMutated: false }
135
+ }
136
+
137
+ type IsImmutableFunc = (value: any) => boolean
138
+
139
+ /**
140
+ * Options for `createImmutableStateInvariantMiddleware()`.
141
+ *
142
+ * @public
143
+ */
144
+ export interface ImmutableStateInvariantMiddlewareOptions {
145
+ /**
146
+ Callback function to check if a value is considered to be immutable.
147
+ This function is applied recursively to every value contained in the state.
148
+ The default implementation will return true for primitive types
149
+ (like numbers, strings, booleans, null and undefined).
150
+ */
151
+ isImmutable?: IsImmutableFunc
152
+ /**
153
+ An array of dot-separated path strings that match named nodes from
154
+ the root state to ignore when checking for immutability.
155
+ Defaults to undefined
156
+ */
157
+ ignoredPaths?: IgnoredPaths
158
+ /** Print a warning if checks take longer than N ms. Default: 32ms */
159
+ warnAfter?: number
160
+ }
161
+
162
+ /**
163
+ * Creates a middleware that checks whether any state was mutated in between
164
+ * dispatches or during a dispatch. If any mutations are detected, an error is
165
+ * thrown.
166
+ *
167
+ * @param options Middleware options.
168
+ *
169
+ * @public
170
+ */
171
+ export function createImmutableStateInvariantMiddleware(
172
+ options: ImmutableStateInvariantMiddlewareOptions = {},
173
+ ): Middleware {
174
+ if (process.env.NODE_ENV === 'production') {
175
+ return () => (next) => (action) => next(action)
176
+ } else {
177
+ function stringify(
178
+ obj: any,
179
+ serializer?: EntryProcessor,
180
+ indent?: string | number,
181
+ decycler?: EntryProcessor,
182
+ ): string {
183
+ return JSON.stringify(obj, getSerialize(serializer, decycler), indent)
184
+ }
185
+
186
+ function getSerialize(
187
+ serializer?: EntryProcessor,
188
+ decycler?: EntryProcessor,
189
+ ): EntryProcessor {
190
+ let stack: any[] = [],
191
+ keys: any[] = []
192
+
193
+ if (!decycler)
194
+ decycler = function (_: string, value: any) {
195
+ if (stack[0] === value) return '[Circular ~]'
196
+ return (
197
+ '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']'
198
+ )
199
+ }
200
+
201
+ return function (this: any, key: string, value: any) {
202
+ if (stack.length > 0) {
203
+ var thisPos = stack.indexOf(this)
204
+ ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
205
+ ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
206
+ if (~stack.indexOf(value)) value = decycler!.call(this, key, value)
207
+ } else stack.push(value)
208
+
209
+ return serializer == null ? value : serializer.call(this, key, value)
210
+ }
211
+ }
212
+
213
+ let {
214
+ isImmutable = isImmutableDefault,
215
+ ignoredPaths,
216
+ warnAfter = 32,
217
+ } = options
218
+
219
+ const track = trackForMutations.bind(null, isImmutable, ignoredPaths)
220
+
221
+ return ({ getState }) => {
222
+ let state = getState()
223
+ let tracker = track(state)
224
+
225
+ let result
226
+ return (next) => (action) => {
227
+ const measureUtils = getTimeMeasureUtils(
228
+ warnAfter,
229
+ 'ImmutableStateInvariantMiddleware',
230
+ )
231
+
232
+ measureUtils.measureTime(() => {
233
+ state = getState()
234
+
235
+ result = tracker.detectMutations()
236
+ // Track before potentially not meeting the invariant
237
+ tracker = track(state)
238
+
239
+ if (result.wasMutated) {
240
+ throw new Error(
241
+ `A state mutation was detected between dispatches, in the path '${
242
+ result.path || ''
243
+ }'. This may cause incorrect behavior. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)`,
244
+ )
245
+ }
246
+ })
247
+
248
+ const dispatchedAction = next(action)
249
+
250
+ measureUtils.measureTime(() => {
251
+ state = getState()
252
+
253
+ result = tracker.detectMutations()
254
+ // Track before potentially not meeting the invariant
255
+ tracker = track(state)
256
+
257
+ if (result.wasMutated) {
258
+ throw new Error(
259
+ `A state mutation was detected inside a dispatch, in the path: ${
260
+ result.path || ''
261
+ }. Take a look at the reducer(s) handling the action ${stringify(
262
+ action,
263
+ )}. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)`,
264
+ )
265
+ }
266
+ })
267
+
268
+ measureUtils.warnIfExceeded()
269
+
270
+ return dispatchedAction
271
+ }
272
+ }
273
+ }
274
+ }