mobx-keystone 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/mobx-keystone.esm.js +3737 -2722
  3. package/dist/mobx-keystone.esm.mjs +3737 -2722
  4. package/dist/mobx-keystone.umd.js +3750 -2721
  5. package/dist/types/action/CallKind.d.ts +29 -0
  6. package/dist/types/action/applyAction.d.ts +8 -2
  7. package/dist/types/action/applyMethodCall.d.ts +1 -1
  8. package/dist/types/action/index.d.ts +13 -12
  9. package/dist/types/action/isModelAction.d.ts +1 -1
  10. package/dist/types/action/middleware.d.ts +1 -1
  11. package/dist/types/action/resolveCallName.d.ts +1 -0
  12. package/dist/types/actionMiddlewares/actionSerialization/actionSerialization.d.ts +17 -3
  13. package/dist/types/actionMiddlewares/actionSerialization/applySerializedAction.d.ts +8 -2
  14. package/dist/types/actionMiddlewares/actionSerialization/arraySerializer.d.ts +2 -2
  15. package/dist/types/actionMiddlewares/actionSerialization/core.d.ts +7 -0
  16. package/dist/types/actionMiddlewares/actionSerialization/dateSerializer.d.ts +1 -1
  17. package/dist/types/actionMiddlewares/actionSerialization/index.d.ts +3 -3
  18. package/dist/types/actionMiddlewares/actionSerialization/mapSerializer.d.ts +2 -2
  19. package/dist/types/actionMiddlewares/actionSerialization/objectPathSerializer.d.ts +2 -2
  20. package/dist/types/actionMiddlewares/actionSerialization/objectSnapshotSerializer.d.ts +1 -1
  21. package/dist/types/actionMiddlewares/actionSerialization/plainObjectSerializer.d.ts +1 -1
  22. package/dist/types/actionMiddlewares/actionSerialization/primitiveSerializer.d.ts +1 -1
  23. package/dist/types/actionMiddlewares/actionSerialization/setSerializer.d.ts +2 -2
  24. package/dist/types/actionMiddlewares/actionTrackingMiddleware.d.ts +3 -3
  25. package/dist/types/actionMiddlewares/index.d.ts +6 -6
  26. package/dist/types/actionMiddlewares/onActionMiddleware.d.ts +3 -3
  27. package/dist/types/actionMiddlewares/readonlyMiddleware.d.ts +1 -1
  28. package/dist/types/actionMiddlewares/transactionMiddleware.d.ts +2 -2
  29. package/dist/types/actionMiddlewares/undoMiddleware.d.ts +8 -8
  30. package/dist/types/computedTree/index.d.ts +1 -1
  31. package/dist/types/context/index.d.ts +1 -1
  32. package/dist/types/dataModel/BaseDataModel.d.ts +3 -3
  33. package/dist/types/dataModel/DataModel.d.ts +3 -3
  34. package/dist/types/dataModel/getDataModelMetadata.d.ts +3 -3
  35. package/dist/types/dataModel/index.d.ts +4 -4
  36. package/dist/types/dataModel/utils.d.ts +1 -1
  37. package/dist/types/deepChange/index.d.ts +1 -1
  38. package/dist/types/deepChange/onDeepChange.d.ts +1 -1
  39. package/dist/types/frozen/Frozen.d.ts +1 -1
  40. package/dist/types/frozen/index.d.ts +1 -1
  41. package/dist/types/globalConfig/index.d.ts +1 -1
  42. package/dist/types/index.d.ts +25 -24
  43. package/dist/types/model/BaseModel.d.ts +5 -5
  44. package/dist/types/model/Model.d.ts +3 -3
  45. package/dist/types/model/getModelMetadata.d.ts +3 -3
  46. package/dist/types/model/index.d.ts +6 -6
  47. package/dist/types/model/mixins.d.ts +4 -4
  48. package/dist/types/model/utils.d.ts +4 -4
  49. package/dist/types/modelShared/BaseModelShared.d.ts +5 -5
  50. package/dist/types/modelShared/index.d.ts +4 -4
  51. package/dist/types/modelShared/modelDecorator.d.ts +3 -3
  52. package/dist/types/modelShared/modelInfo.d.ts +3 -3
  53. package/dist/types/modelShared/newModel.d.ts +3 -3
  54. package/dist/types/modelShared/prop.d.ts +3 -3
  55. package/dist/types/modelShared/sharedInternalModel.d.ts +4 -4
  56. package/dist/types/parent/findParent.d.ts +1 -1
  57. package/dist/types/parent/index.d.ts +9 -9
  58. package/dist/types/parent/path.d.ts +1 -1
  59. package/dist/types/patch/Patch.d.ts +1 -1
  60. package/dist/types/patch/applyPatches.d.ts +1 -1
  61. package/dist/types/patch/emitPatch.d.ts +7 -1
  62. package/dist/types/patch/index.d.ts +5 -5
  63. package/dist/types/patch/jsonPatch.d.ts +2 -2
  64. package/dist/types/patch/patchRecorder.d.ts +2 -2
  65. package/dist/types/redux/index.d.ts +2 -2
  66. package/dist/types/redux/redux.d.ts +3 -3
  67. package/dist/types/ref/Ref.d.ts +3 -3
  68. package/dist/types/ref/core.d.ts +2 -2
  69. package/dist/types/ref/customRef.d.ts +2 -2
  70. package/dist/types/ref/index.d.ts +4 -4
  71. package/dist/types/ref/rootRef.d.ts +2 -2
  72. package/dist/types/rootStore/index.d.ts +1 -1
  73. package/dist/types/serialization/Call.d.ts +55 -0
  74. package/dist/types/serialization/CallError.d.ts +96 -0
  75. package/dist/types/serialization/JsonValue.d.ts +6 -0
  76. package/dist/types/serialization/Serializer.d.ts +84 -0
  77. package/dist/types/serialization/ValueSerializer.d.ts +88 -0
  78. package/dist/types/serialization/applyCall.d.ts +54 -0
  79. package/dist/types/serialization/builtinSerializers.d.ts +49 -0
  80. package/dist/types/serialization/codec.d.ts +1 -0
  81. package/dist/types/serialization/index.d.ts +8 -0
  82. package/dist/types/serialization/references.d.ts +74 -0
  83. package/dist/types/serialization/resolvedCall.d.ts +1 -0
  84. package/dist/types/snapshot/SnapshotOf.d.ts +5 -5
  85. package/dist/types/snapshot/SnapshotProcessingError.d.ts +2 -2
  86. package/dist/types/snapshot/applySnapshot.d.ts +1 -1
  87. package/dist/types/snapshot/cloneTreeValue.d.ts +1 -1
  88. package/dist/types/snapshot/fromSnapshot.d.ts +2 -2
  89. package/dist/types/snapshot/getSnapshot.d.ts +2 -2
  90. package/dist/types/snapshot/index.d.ts +8 -8
  91. package/dist/types/snapshot/onSnapshot.d.ts +1 -1
  92. package/dist/types/standardActions/index.d.ts +3 -3
  93. package/dist/types/standardActions/objectActions.d.ts +1 -1
  94. package/dist/types/transforms/asMap.d.ts +1 -1
  95. package/dist/types/transforms/asSet.d.ts +2 -2
  96. package/dist/types/transforms/bigint.d.ts +1 -1
  97. package/dist/types/transforms/date.d.ts +1 -1
  98. package/dist/types/transforms/index.d.ts +4 -4
  99. package/dist/types/treeUtils/draft.d.ts +1 -1
  100. package/dist/types/treeUtils/index.d.ts +3 -3
  101. package/dist/types/tweaker/index.d.ts +2 -2
  102. package/dist/types/tweaker/tweak.d.ts +1 -1
  103. package/dist/types/types/SnapshotTypeMismatchError.d.ts +2 -2
  104. package/dist/types/types/TypeCheckError.d.ts +2 -2
  105. package/dist/types/types/TypeChecker.d.ts +3 -3
  106. package/dist/types/types/arrayBased/typesArray.d.ts +2 -2
  107. package/dist/types/types/arrayBased/typesTuple.d.ts +2 -2
  108. package/dist/types/types/getTypeInfo.d.ts +2 -2
  109. package/dist/types/types/index.d.ts +7 -7
  110. package/dist/types/types/objectBased/typesArraySet.d.ts +3 -3
  111. package/dist/types/types/objectBased/typesDataModelData.d.ts +4 -4
  112. package/dist/types/types/objectBased/typesModel.d.ts +4 -4
  113. package/dist/types/types/objectBased/typesObject.d.ts +3 -3
  114. package/dist/types/types/objectBased/typesObjectMap.d.ts +3 -3
  115. package/dist/types/types/objectBased/typesRecord.d.ts +2 -2
  116. package/dist/types/types/objectBased/typesRef.d.ts +3 -3
  117. package/dist/types/types/primitiveBased/typesEnum.d.ts +1 -1
  118. package/dist/types/types/primitiveBased/typesPrimitive.d.ts +3 -3
  119. package/dist/types/types/primitiveBased/typesRefinedPrimitive.d.ts +2 -2
  120. package/dist/types/types/schemas.d.ts +5 -5
  121. package/dist/types/types/tProp.d.ts +4 -4
  122. package/dist/types/types/typeCheck.d.ts +2 -2
  123. package/dist/types/types/types.d.ts +39 -39
  124. package/dist/types/types/utility/typeToStoredData.d.ts +2 -2
  125. package/dist/types/types/utility/typesBigInt.d.ts +1 -1
  126. package/dist/types/types/utility/typesCodec.d.ts +6 -6
  127. package/dist/types/types/utility/typesCodecCore.d.ts +4 -4
  128. package/dist/types/types/utility/typesCodecSupport.d.ts +4 -4
  129. package/dist/types/types/utility/typesDate.d.ts +2 -2
  130. package/dist/types/types/utility/typesMap.d.ts +2 -2
  131. package/dist/types/types/utility/typesMaybe.d.ts +1 -1
  132. package/dist/types/types/utility/typesOr.d.ts +2 -2
  133. package/dist/types/types/utility/typesRefinement.d.ts +3 -3
  134. package/dist/types/types/utility/typesSet.d.ts +3 -3
  135. package/dist/types/types/utility/typesSkipCheck.d.ts +2 -2
  136. package/dist/types/types/utility/typesTag.d.ts +2 -2
  137. package/dist/types/types/utility/typesUnchecked.d.ts +2 -2
  138. package/dist/types/utils/ModelPool.d.ts +1 -1
  139. package/dist/types/wrappers/ArraySet.d.ts +1 -1
  140. package/dist/types/wrappers/ObjectMap.d.ts +1 -1
  141. package/dist/types/wrappers/asMap.d.ts +1 -1
  142. package/dist/types/wrappers/asSet.d.ts +1 -1
  143. package/dist/types/wrappers/index.d.ts +4 -4
  144. package/package.json +5 -18
  145. package/src/action/CallKind.ts +29 -0
  146. package/src/action/applyAction.ts +22 -49
  147. package/src/action/applySet.ts +21 -1
  148. package/src/action/index.ts +1 -0
  149. package/src/action/modelAction.ts +1 -1
  150. package/src/action/modelFlow.ts +1 -1
  151. package/src/action/resolveCallName.ts +207 -0
  152. package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +14 -0
  153. package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +6 -0
  154. package/src/actionMiddlewares/actionSerialization/core.ts +7 -0
  155. package/src/actionMiddlewares/actionSerialization/index.ts +2 -0
  156. package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +3 -2
  157. package/src/dataModel/BaseDataModel.ts +5 -5
  158. package/src/index.ts +1 -0
  159. package/src/model/BaseModel.ts +7 -6
  160. package/src/model/mixins.ts +1 -1
  161. package/src/model/newModel.ts +1 -1
  162. package/src/modelShared/modelDecorator.ts +4 -6
  163. package/src/modelShared/modelInfo.ts +2 -1
  164. package/src/modelShared/sharedInternalModel.ts +1 -1
  165. package/src/parent/path.ts +45 -12
  166. package/src/patch/emitPatch.ts +6 -0
  167. package/src/ref/Ref.ts +1 -1
  168. package/src/serialization/Call.ts +58 -0
  169. package/src/serialization/CallError.ts +153 -0
  170. package/src/serialization/JsonValue.ts +12 -0
  171. package/src/serialization/Serializer.ts +321 -0
  172. package/src/serialization/ValueSerializer.ts +98 -0
  173. package/src/serialization/applyCall.ts +190 -0
  174. package/src/serialization/builtinSerializers.ts +261 -0
  175. package/src/serialization/codec.ts +338 -0
  176. package/src/serialization/index.ts +15 -0
  177. package/src/serialization/references.ts +225 -0
  178. package/src/serialization/resolvedCall.ts +169 -0
  179. package/src/snapshot/SnapshotterAndReconcilerPriority.ts +2 -1
  180. package/src/snapshot/fromModelSnapshot.ts +1 -1
  181. package/src/snapshot/fromSnapshot.ts +1 -1
  182. package/src/standardActions/actions.ts +11 -3
  183. package/src/transforms/ImmutableDate.ts +19 -19
  184. package/src/tweaker/tweakArray.ts +1 -1
  185. package/src/tweaker/tweakFrozen.ts +1 -1
  186. package/src/tweaker/tweakModel.ts +1 -1
  187. package/src/tweaker/tweakPlainObject.ts +1 -1
  188. package/src/types/arrayBased/typesArray.ts +1 -1
  189. package/src/types/arrayBased/typesTuple.ts +1 -1
  190. package/src/types/objectBased/typesArraySet.ts +1 -1
  191. package/src/types/objectBased/typesModel.ts +2 -2
  192. package/src/types/objectBased/typesObject.ts +1 -1
  193. package/src/types/objectBased/typesObjectMap.ts +1 -1
  194. package/src/types/objectBased/typesRecord.ts +1 -1
  195. package/src/types/objectBased/typesRef.ts +2 -2
  196. package/src/types/primitiveBased/typesPrimitive.ts +1 -1
  197. package/src/types/schemas.ts +1 -1
  198. package/src/types/utility/typesCodecCore.ts +1 -1
  199. package/src/types/utility/typesCodecSupport.ts +2 -0
  200. package/src/types/utility/typesOr.ts +2 -2
  201. package/src/types/utility/typesRefinement.ts +1 -1
  202. package/src/utils/errorDiagnostics.ts +9 -4
  203. package/src/utils/index.ts +20 -13
  204. package/src/wrappers/ArraySet.ts +3 -5
  205. package/src/wrappers/ObjectMap.ts +3 -5
@@ -0,0 +1,207 @@
1
+ import { getDataModelAction } from "../dataModel/actions"
2
+ import { BaseDataModel } from "../dataModel/BaseDataModel"
3
+ import { isDataModelClass } from "../dataModel/utils"
4
+ import { BaseModel } from "../model/BaseModel"
5
+ import { isModel } from "../model/utils"
6
+ import type { ModelClass } from "../modelShared/BaseModelShared"
7
+ import { getModelInfoForName } from "../modelShared/modelInfo"
8
+ import { detach } from "../parent/detach"
9
+ import { applyPatches } from "../patch/applyPatches"
10
+ import { applySnapshot } from "../snapshot/applySnapshot"
11
+ import { getStandaloneAction } from "../standardActions/actions"
12
+ import { failure, namespace } from "../utils"
13
+ import type { AnyFunction } from "../utils/AnyFunction"
14
+ import { applyDelete } from "./applyDelete"
15
+ import { applyMethodCall } from "./applyMethodCall"
16
+ import { applySet } from "./applySet"
17
+ import { BuiltInAction, isBuiltInAction } from "./builtInActions"
18
+ import { CallKind } from "./CallKind"
19
+ import { isHookAction } from "./hookActions"
20
+ import { isModelAction } from "./isModelAction"
21
+ import { isModelFlow } from "./modelFlow"
22
+
23
+ const builtInActionToFunction = {
24
+ [BuiltInAction.ApplySnapshot]: applySnapshot,
25
+ [BuiltInAction.ApplyPatches]: applyPatches,
26
+ [BuiltInAction.Detach]: detach,
27
+ [BuiltInAction.ApplySet]: applySet,
28
+ [BuiltInAction.ApplyDelete]: applyDelete,
29
+ [BuiltInAction.ApplyMethodCall]: applyMethodCall,
30
+ }
31
+
32
+ const standardActionPrefixes = [`${namespace}/arrayActions::`, `${namespace}/objectActions::`]
33
+
34
+ const dataModelMemberPrefix = "fn::"
35
+
36
+ // members that are never callable, even when defined below the base classes
37
+ const nonCallableMemberNames: ReadonlySet<string> = new Set([
38
+ "constructor",
39
+ "onInit",
40
+ "onLazyInit",
41
+ "onAttachedToRootStore",
42
+ "onLazyAttachedToRootStore",
43
+ ])
44
+
45
+ /**
46
+ * @internal
47
+ *
48
+ * How a view is used: a getter is read (no `args`), a method is called (with `args`).
49
+ */
50
+ export type ViewForm = "getter" | "method"
51
+
52
+ /**
53
+ * @internal
54
+ *
55
+ * What a call's name resolved to on its target.
56
+ */
57
+ export interface CallResolution {
58
+ readonly kind: CallKind
59
+ readonly isFlow: boolean
60
+ /**
61
+ * Only for views.
62
+ */
63
+ readonly viewForm: ViewForm | undefined
64
+ /**
65
+ * Runs the call on the target it was resolved for (args are ignored when reading a getter).
66
+ */
67
+ run(args: readonly unknown[]): unknown
68
+ }
69
+
70
+ /**
71
+ * @internal
72
+ *
73
+ * Why a name couldn't be resolved: a hook (never callable) or nothing callable by that name.
74
+ */
75
+ export type CallResolutionFailure = "hook" | "unknown"
76
+
77
+ type FoundMember = { readonly get: AnyFunction } | { readonly fn: AnyFunction }
78
+
79
+ /**
80
+ * Finds a callable member without running any getter: a method, getter or function field of the
81
+ * object or of its prototype chain below `stopProto`.
82
+ */
83
+ function findMember(obj: object, name: string, stopProto: object): FoundMember | undefined {
84
+ if (nonCallableMemberNames.has(name)) {
85
+ return undefined
86
+ }
87
+
88
+ // own accessors too, e.g. computeds MobX defines on the instance with legacy decorators
89
+ for (
90
+ let current: object | null = obj;
91
+ current && current !== stopProto;
92
+ current = Object.getPrototypeOf(current)
93
+ ) {
94
+ const desc = Object.getOwnPropertyDescriptor(current, name)
95
+ if (desc) {
96
+ if (desc.get) {
97
+ return { get: desc.get }
98
+ }
99
+ return typeof desc.value === "function" ? { fn: desc.value } : undefined
100
+ }
101
+ }
102
+ return undefined
103
+ }
104
+
105
+ function resolveMember(member: FoundMember, self: object): CallResolution {
106
+ if ("get" in member) {
107
+ const get = member.get
108
+ return {
109
+ kind: CallKind.View,
110
+ isFlow: false,
111
+ viewForm: "getter",
112
+ run: () => get.call(self),
113
+ }
114
+ }
115
+
116
+ const fn = member.fn
117
+ const run = (args: readonly unknown[]) => fn.apply(self, args as unknown[])
118
+ if (isModelAction(fn) || isModelFlow(fn)) {
119
+ return { kind: CallKind.ModelAction, isFlow: isModelFlow(fn), viewForm: undefined, run }
120
+ }
121
+ return { kind: CallKind.View, isFlow: false, viewForm: "method", run }
122
+ }
123
+
124
+ function getDataModelClassAndMember(
125
+ name: string
126
+ ): { modelClass: ModelClass<any>; memberName: string } | undefined {
127
+ // data model actions are registered under their name
128
+ const registered = getDataModelAction(name)
129
+ if (registered) {
130
+ return { modelClass: registered.modelClass, memberName: registered.fnName }
131
+ }
132
+
133
+ // other members are named the same way: fn::<data model name>::<member>
134
+ if (!name.startsWith(dataModelMemberPrefix)) {
135
+ return undefined
136
+ }
137
+ const separatorIndex = name.lastIndexOf("::")
138
+ if (separatorIndex < dataModelMemberPrefix.length) {
139
+ return undefined
140
+ }
141
+ const modelInfo = getModelInfoForName(name.slice(dataModelMemberPrefix.length, separatorIndex))
142
+ if (!modelInfo || !isDataModelClass(modelInfo.class)) {
143
+ return undefined
144
+ }
145
+ return { modelClass: modelInfo.class, memberName: name.slice(separatorIndex + 2) }
146
+ }
147
+
148
+ /**
149
+ * @internal
150
+ *
151
+ * Resolves what a call's name refers to on its target, in this order: built-in actions, hooks
152
+ * (refused), data model members, standalone actions, the target's own model actions and flows,
153
+ * and finally the target's own methods, getters and function fields (views).
154
+ *
155
+ * Getters are never run while resolving.
156
+ */
157
+ export function resolveCallName(
158
+ target: object,
159
+ name: string
160
+ ): CallResolution | CallResolutionFailure {
161
+ if (isBuiltInAction(name)) {
162
+ const fn = builtInActionToFunction[name] as AnyFunction | undefined
163
+ if (!fn) {
164
+ throw failure(`assertion failed: unknown built-in action - ${name}`)
165
+ }
166
+ return {
167
+ kind: CallKind.BuiltInAction,
168
+ isFlow: false,
169
+ viewForm: undefined,
170
+ run: (args) => fn.apply(target, [target, ...args]),
171
+ }
172
+ }
173
+
174
+ if (isHookAction(name)) {
175
+ return "hook"
176
+ }
177
+
178
+ const dataModelMember = getDataModelClassAndMember(name)
179
+ if (dataModelMember) {
180
+ // the instance is created (or reused, since they are cached) first, so decorators that
181
+ // initialize on first use have run; it throws when the target isn't valid data for the class
182
+ const instance: object = new dataModelMember.modelClass(target)
183
+ const member = findMember(instance, dataModelMember.memberName, BaseDataModel.prototype)
184
+ return member ? resolveMember(member, instance) : "unknown"
185
+ }
186
+
187
+ const standaloneAction = getStandaloneAction(name)
188
+ if (standaloneAction) {
189
+ return {
190
+ kind: standardActionPrefixes.some((prefix) => name.startsWith(prefix))
191
+ ? CallKind.StandardAction
192
+ : CallKind.StandaloneAction,
193
+ isFlow: standaloneAction.isFlow,
194
+ viewForm: undefined,
195
+ run: (args) => standaloneAction.fn(target, ...args),
196
+ }
197
+ }
198
+
199
+ if (isModel(target)) {
200
+ const member = findMember(target, name, BaseModel.prototype)
201
+ if (member) {
202
+ return resolveMember(member, target)
203
+ }
204
+ }
205
+
206
+ return "unknown"
207
+ }
@@ -24,6 +24,8 @@ const serializersMap = new Map<string, ActionCallArgumentSerializer<any, any>>()
24
24
  *
25
25
  * @param serializer Serializer to register.
26
26
  * @returns A disposer to unregister the serializer.
27
+ *
28
+ * @deprecated Use a `ValueSerializer` in the list passed to `createSerializer` instead.
27
29
  */
28
30
  export function registerActionCallArgumentSerializer(
29
31
  serializer: ActionCallArgumentSerializer<any, any>
@@ -54,6 +56,8 @@ export function registerActionCallArgumentSerializer(
54
56
 
55
57
  /**
56
58
  * Serialized action call argument.
59
+ *
60
+ * @deprecated Replaced by the marked value `{ "$mobxKeystone": tag, "v": payload }` of `createSerializer`.
57
61
  */
58
62
  export interface SerializedActionCallArgument {
59
63
  /**
@@ -68,6 +72,8 @@ export interface SerializedActionCallArgument {
68
72
 
69
73
  /**
70
74
  * A serialized action call.
75
+ *
76
+ * @deprecated Use `EncodedCall` instead.
71
77
  */
72
78
  export interface SerializedActionCall extends Omit<ActionCall, "serialized"> {
73
79
  /**
@@ -99,6 +105,8 @@ export interface SerializedActionCall extends Omit<ActionCall, "serialized"> {
99
105
  * @param argValue Argument value to be transformed into its serializable form.
100
106
  * @param [targetRoot] Target root node of the model where this action is being performed.
101
107
  * @returns The serializable form of the passed value.
108
+ *
109
+ * @deprecated Use `serializer.encodeValue(root, value)` instead (e.g. with `defaultSerializer`).
102
110
  */
103
111
  export function serializeActionCallArgument(
104
112
  argValue: any,
@@ -137,6 +145,8 @@ export function serializeActionCallArgument(
137
145
  * @param actionCall Action call to convert.
138
146
  * @param [targetRoot] Target root node of the model where this action is being performed.
139
147
  * @returns The serializable action call.
148
+ *
149
+ * @deprecated Use `serializer.encodeCall(root, call)` instead (e.g. with `defaultSerializer`).
140
150
  */
141
151
  export function serializeActionCall(
142
152
  actionCall: ActionCall,
@@ -165,6 +175,8 @@ export function serializeActionCall(
165
175
  * @param argValue Argument value to be transformed into its deserialized form.
166
176
  * @param [targetRoot] Target root node of the model where this action is being performed.
167
177
  * @returns The deserialized form of the passed value.
178
+ *
179
+ * @deprecated Use `serializer.decodeValue(root, json)` instead (e.g. with `defaultSerializer`).
168
180
  */
169
181
  export function deserializeActionCallArgument(
170
182
  argValue: SerializedActionCallArgument | JSONPrimitiveValue,
@@ -200,6 +212,8 @@ export function deserializeActionCallArgument(
200
212
  * @param actionCall Action call to convert.
201
213
  * @param [targetRoot] Target root node of the model where this action is being performed.
202
214
  * @returns The deserialized action call.
215
+ *
216
+ * @deprecated Use `serializer.decodeCall(root, json)` instead (e.g. with `defaultSerializer`), then `applyCall`.
203
217
  */
204
218
  export function deserializeActionCall(
205
219
  actionCall: SerializedActionCall,
@@ -17,6 +17,8 @@ import { deserializeActionCall, type SerializedActionCall } from "./actionSerial
17
17
  * Serialized action call with model ID overrides.
18
18
  * Can be generated with `applySerializedActionAndTrackNewModelIds`.
19
19
  * To be applied with `applySerializedActionAndSyncNewModelIds`.
20
+ *
21
+ * @deprecated Use `EncodedCall` instead; model id overrides aren't needed when replicas apply the patches the server broadcasts.
20
22
  */
21
23
  export interface SerializedActionCallWithModelIdOverrides extends SerializedActionCall {
22
24
  /**
@@ -38,6 +40,8 @@ export interface SerializedActionCallWithModelIdOverrides extends SerializedActi
38
40
  * @param call The serialized action, usually as coming from the server/client.
39
41
  * @returns The return value of the action, if any, plus a new serialized action
40
42
  * with model overrides.
43
+ *
44
+ * @deprecated Use `applyCall` / `applyCallAsync` on the server instead, broadcasting the patches the call produces.
41
45
  */
42
46
  export function applySerializedActionAndTrackNewModelIds<TRet = any>(
43
47
  subtreeRoot: object,
@@ -156,6 +160,8 @@ function deepScanValueForModelIdChanges(
156
160
  * @param subtreeRoot Subtree root target object to run the action over.
157
161
  * @param call The serialized action, usually as coming from the server/client.
158
162
  * @returns The return value of the action, if any.
163
+ *
164
+ * @deprecated Use `applyPatches` on the patches the server broadcasts instead.
159
165
  */
160
166
  export function applySerializedActionAndSyncNewModelIds<TRet = any>(
161
167
  subtreeRoot: object,
@@ -1,7 +1,14 @@
1
+ /**
2
+ * Returned by an `ActionCallArgumentSerializer` that can't serialize a value.
3
+ *
4
+ * @deprecated Use `ValueSerializer.is` returning false instead.
5
+ */
1
6
  export const cannotSerialize = Symbol("cannotSerialize")
2
7
 
3
8
  /**
4
9
  * Serializer of action call arguments.
10
+ *
11
+ * @deprecated Use `ValueSerializer` instead.
5
12
  */
6
13
  export interface ActionCallArgumentSerializer<TOriginal, TSerialized> {
7
14
  /**
@@ -1,3 +1,5 @@
1
+ // Deprecated: replaced by `src/serialization`; kept unchanged until the next major.
2
+
1
3
  export * from "./actionSerialization"
2
4
  export * from "./applySerializedAction"
3
5
  export * from "./core"
@@ -1,6 +1,6 @@
1
1
  import { fastGetRootPath, resolvePathCheckingIds } from "../../parent/path"
2
2
  import type { Path } from "../../parent/pathTypes"
3
- import { isTweakedObject } from "../../tweaker/core"
3
+ import { isTreeNode, isTweakedObject } from "../../tweaker/core"
4
4
  import { failure, namespace } from "../../utils"
5
5
  import { rootPathToTargetPathIds } from "../utils"
6
6
  import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
@@ -36,7 +36,8 @@ export const objectPathSerializer: ActionCallArgumentSerializer<object, ObjectPa
36
36
  // try to resolve the node back
37
37
  if (targetRoot) {
38
38
  const result = resolvePathCheckingIds(targetRoot, ref.targetPath, ref.targetPathIds)
39
- if (result.resolved) {
39
+ // only tree nodes can be serialized as paths, so anything else is not a valid target
40
+ if (result.resolved && isTreeNode(result.value)) {
40
41
  return result.value
41
42
  }
42
43
  }
@@ -1,4 +1,4 @@
1
- import { propsTypeSymbol } from "../modelShared/BaseModelShared"
1
+ import { type propsTypeSymbol } from "../modelShared/BaseModelShared"
2
2
  import { modelInfoByClass } from "../modelShared/modelInfo"
3
3
  import { getInternalModelClassPropsInfo } from "../modelShared/modelPropsInfo"
4
4
  import {
@@ -13,8 +13,8 @@ import { getSnapshot } from "../snapshot/getSnapshot"
13
13
  import { isTreeNode } from "../tweaker/core"
14
14
  import { toTreeNode } from "../tweaker/tweak"
15
15
  import { typesDataModelData } from "../types/objectBased/typesDataModelData"
16
- import type { TypeCheckError } from "../types/TypeCheckError"
17
16
  import { typeCheck } from "../types/typeCheck"
17
+ import type { TypeCheckError } from "../types/TypeCheckError"
18
18
  import { clonePlainObject, failure, hasOwnProp, isObject, setProtoProp } from "../utils"
19
19
  import { getOrCreate } from "../utils/mapUtils"
20
20
  import type { DataModelConstructorOptions } from "./DataModelConstructorOptions"
@@ -73,7 +73,7 @@ export abstract class BaseDataModel<TProps extends ModelProps> {
73
73
  }
74
74
 
75
75
  const constructorOptions =
76
- // biome-ignore lint/complexity/noArguments: internal factory code passes hidden constructor options through super().
76
+ // oxlint-disable-next-line eslint/prefer-rest-params -- internal factory code passes hidden constructor options through super().
77
77
  arguments[1] as DataModelConstructorOptions
78
78
  const { modelClass: _modelClass } = constructorOptions
79
79
  const modelClass = _modelClass!
@@ -140,7 +140,7 @@ export abstract class BaseDataModel<TProps extends ModelProps> {
140
140
 
141
141
  const instance = instancesForModelClass.get(tweakedData)
142
142
  if (instance) {
143
- // biome-ignore lint/correctness/noConstructorReturn: no other way to return an instance
143
+ // oxlint-disable-next-line eslint/no-constructor-return -- no other way to return an instance
144
144
  return instance
145
145
  }
146
146
 
@@ -189,6 +189,6 @@ export interface AnyDataModel extends BaseDataModel<any> {}
189
189
  * A data model class declaration, made of a base model and the model interface.
190
190
  */
191
191
  export type DataModelClassDeclaration<BaseModelClass, ModelInterface> = BaseModelClass & {
192
- // biome-ignore lint/style/useShorthandFunctionType: make type recursive
192
+ // oxlint-disable-next-line typescript/prefer-function-type -- make type recursive
193
193
  (...args: any[]): ModelInterface
194
194
  }
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ export * from "./patch"
13
13
  export * from "./redux"
14
14
  export * from "./ref"
15
15
  export * from "./rootStore"
16
+ export * from "./serialization"
16
17
  export * from "./snapshot"
17
18
  export * from "./standardActions"
18
19
  export * from "./transforms"
@@ -1,9 +1,9 @@
1
1
  import { observable } from "mobx"
2
2
  import {
3
- fromSnapshotOverrideTypeSymbol,
3
+ type fromSnapshotOverrideTypeSymbol,
4
4
  type ModelClass,
5
- propsTypeSymbol,
6
- toSnapshotOverrideTypeSymbol,
5
+ type propsTypeSymbol,
6
+ type toSnapshotOverrideTypeSymbol,
7
7
  } from "../modelShared/BaseModelShared"
8
8
  import { modelInfoByClass } from "../modelShared/modelInfo"
9
9
  import type {
@@ -15,12 +15,12 @@ import { getSnapshot } from "../snapshot/getSnapshot"
15
15
  import { setModelInitialDataSnapshot } from "../snapshot/modelInitialData"
16
16
  import type { SnapshotInOfModel, SnapshotOutOfModel } from "../snapshot/SnapshotOf"
17
17
  import { typesModel } from "../types/objectBased/typesModel"
18
- import type { TypeCheckError } from "../types/TypeCheckError"
19
18
  import { typeCheck } from "../types/typeCheck"
19
+ import type { TypeCheckError } from "../types/TypeCheckError"
20
20
  import { assertIsObject, failure, nodeObservableOptions } from "../utils"
21
21
  import { getModelIdPropertyName } from "./getModelMetadata"
22
- import type { ModelConstructorOptions } from "./ModelConstructorOptions"
23
22
  import { modelIdKey, modelTypeKey } from "./metadata"
23
+ import type { ModelConstructorOptions } from "./ModelConstructorOptions"
24
24
  import { internalFromSnapshotModel, internalNewModel } from "./newModel"
25
25
  import { assertIsModelClass } from "./utils"
26
26
 
@@ -134,7 +134,7 @@ export abstract class BaseModel<
134
134
  constructor(data: ModelPropsToTransformedCreationData<TProps>) {
135
135
  const initialData = data as any
136
136
  const constructorOptions =
137
- // biome-ignore lint/complexity/noArguments: internal factory code passes hidden constructor options through super().
137
+ // oxlint-disable-next-line eslint/prefer-rest-params -- internal factory code passes hidden constructor options through super().
138
138
  arguments[1] as ModelConstructorOptions
139
139
  const { snapshotInitialData, modelClass, generateNewIds } = constructorOptions
140
140
 
@@ -205,6 +205,7 @@ export interface AnyModel extends BaseModel<any, any, any, any> {}
205
205
  * @param type Abstract model class.
206
206
  * @returns
207
207
  */
208
+ // oxlint-disable-next-line typescript/no-wrapper-object-types -- part of the public signature
208
209
  export function abstractModelClass<T>(type: T): T & Object {
209
210
  return type as any
210
211
  }
@@ -2,7 +2,7 @@ import {
2
2
  type AbstractModelClass,
3
3
  type ModelClass,
4
4
  modelClass,
5
- propsTypeSymbol,
5
+ type propsTypeSymbol,
6
6
  } from "../modelShared/BaseModelShared"
7
7
  import type { ModelProps, ModelPropsToTransformedData } from "../modelShared/prop"
8
8
  import type { AnyModel, BaseModelKeys } from "./BaseModel"
@@ -27,8 +27,8 @@ import { failure, hasOwnProp, inDevMode, makePropReadonly } from "../utils"
27
27
  import { setIfDifferent, setIfDifferentWithReturn } from "../utils/setIfDifferent"
28
28
  import type { AnyModel } from "./BaseModel"
29
29
  import { getModelIdPropertyName } from "./getModelMetadata"
30
- import type { ModelConstructorOptions } from "./ModelConstructorOptions"
31
30
  import { modelTypeKey } from "./metadata"
31
+ import type { ModelConstructorOptions } from "./ModelConstructorOptions"
32
32
  import { assertIsModelClass } from "./utils"
33
33
 
34
34
  /**
@@ -43,9 +43,7 @@ export const model =
43
43
  // the model instance type is checked through `prototype` rather than through a typed constructor
44
44
  // signature, since comparing constructor signatures would compute the (expensive) model creation data
45
45
  // type of every decorated class
46
- type ModelDecoratorTarget = (new (
47
- ...args: any
48
- ) => any) & {
46
+ type ModelDecoratorTarget = (new (...args: any) => any) & {
49
47
  prototype: AnyModel | AnyDataModel
50
48
  }
51
49
 
@@ -191,7 +189,7 @@ function tsDecorate(
191
189
  r = (Reflect as any).decorate(decorators, target, key, desc)
192
190
  } else {
193
191
  for (
194
- // biome-ignore lint/correctness/noInnerDeclarations: minified file
192
+ // oxlint-disable-next-line eslint/no-inner-declarations, eslint/no-var -- minified file
195
193
  var i = decorators.length - 1;
196
194
  i >= 0;
197
195
  i--
@@ -201,8 +199,8 @@ function tsDecorate(
201
199
  }
202
200
  }
203
201
  }
204
- // biome-ignore lint/complexity/noCommaOperator: minified file
205
- return c > 3 && r && Object.defineProperty(target, key, r), r
202
+ // oxlint-disable-next-line eslint/no-sequences -- minified file
203
+ return (c > 3 && r && Object.defineProperty(target, key, r), r)
206
204
  }
207
205
 
208
206
  /**
@@ -58,10 +58,11 @@ export function setModelInfo(modelInfo: ModelInfo, unwrappedClass: ModelClass<an
58
58
  // registration of a model
59
59
  const baseModelInfo = findModelInfoForPrototype(Object.getPrototypeOf(unwrappedClass.prototype))
60
60
  const ancestorDistances = new Map<string, number>()
61
- baseModelInfo &&
61
+ if (baseModelInfo) {
62
62
  ancestorDistancesByModelInfo.get(baseModelInfo)?.forEach((distance, name) => {
63
63
  ancestorDistances.set(name, distance + 1)
64
64
  })
65
+ }
65
66
  ancestorDistances.set(modelInfo.name, 0)
66
67
  ancestorDistancesByModelInfo.set(modelInfo, ancestorDistances)
67
68
  ancestorDistancesByModelName.set(modelInfo.name, ancestorDistances)
@@ -11,8 +11,8 @@ import type { DataModelMetadata } from "../dataModel/getDataModelMetadata"
11
11
  import { getGlobalConfig } from "../globalConfig/globalConfig"
12
12
  import { type AnyModel, BaseModel, baseModelPropNames } from "../model/BaseModel"
13
13
  import type { ModelMetadata } from "../model/getModelMetadata"
14
- import type { ModelConstructorOptions } from "../model/ModelConstructorOptions"
15
14
  import { modelTypeKey } from "../model/metadata"
15
+ import type { ModelConstructorOptions } from "../model/ModelConstructorOptions"
16
16
  import { typesObject } from "../types/objectBased/typesObject"
17
17
  import { typesString } from "../types/primitiveBased/typesPrimitive"
18
18
  import type { AnyType } from "../types/schemas"
@@ -256,19 +256,20 @@ export function resolvePath<T = any>(
256
256
 
257
257
  const p = path[i]
258
258
 
259
- // check just to avoid mobx warnings about trying to access out of bounds index
260
- if (isArray(current) && +p >= current.length) {
261
- return unresolved
262
- }
263
-
264
- if (isModel(current)) {
259
+ if (isArray(current)) {
260
+ if (!isArrayIndexOf(current, p)) {
261
+ return unresolved
262
+ }
263
+ } else if (isModel(current)) {
265
264
  const dataNode = modelToDataNode(current)
266
- if (p in dataNode) {
265
+ if (hasOwnProp(dataNode, p)) {
267
266
  current = dataNode
267
+ } else if (!hasOwnProp(current, p) && !isInheritedGetter(current, p)) {
268
+ // the model's own fields and getters (e.g. computed trees) resolve,
269
+ // but not its methods or anything inherited from Object.prototype
270
+ return unresolved
268
271
  }
269
- }
270
-
271
- if (!(p in current)) {
272
+ } else if (!hasOwnProp(current, p)) {
272
273
  return unresolved
273
274
  }
274
275
 
@@ -278,6 +279,39 @@ export function resolvePath<T = any>(
278
279
  return { resolved: true, value: current }
279
280
  }
280
281
 
282
+ /**
283
+ * @internal
284
+ *
285
+ * Whether a value can be a path element (a property name or an array index).
286
+ */
287
+ export function isPathElement(value: unknown): value is PathElement {
288
+ return typeof value === "string" || typeof value === "number"
289
+ }
290
+
291
+ /**
292
+ * Whether a path element is an index of the array, so non-index props such as 'length' never
293
+ * resolve. It also avoids mobx warnings about trying to access out of bounds indexes.
294
+ */
295
+ function isArrayIndexOf(array: readonly unknown[], p: PathElement): boolean {
296
+ const index = +p
297
+ return Number.isInteger(index) && index >= 0 && index < array.length && p in array
298
+ }
299
+
300
+ /**
301
+ * Whether a getter is defined for a prop by the prototype chain of an object, below `Object.prototype`.
302
+ */
303
+ function isInheritedGetter(obj: object, p: PathElement): boolean {
304
+ let proto = Object.getPrototypeOf(obj)
305
+ while (proto && proto !== Object.prototype) {
306
+ const descriptor = Object.getOwnPropertyDescriptor(proto, p)
307
+ if (descriptor) {
308
+ return descriptor.get !== undefined
309
+ }
310
+ proto = Object.getPrototypeOf(proto)
311
+ }
312
+ return false
313
+ }
314
+
281
315
  /**
282
316
  * @internal
283
317
  */
@@ -321,9 +355,8 @@ export function resolvePathCheckingIds<T = any>(
321
355
 
322
356
  const p = path[i]
323
357
 
324
- // check just to avoid mobx warnings about trying to access out of bounds index
325
358
  if (isArray(current)) {
326
- if (+p >= current.length || !(p in current)) {
359
+ if (!isArrayIndexOf(current, p)) {
327
360
  return { resolved: false }
328
361
  }
329
362
  } else if (!hasOwnProp(current, p)) {
@@ -148,6 +148,9 @@ export function hasPatchListenersFor(target: object): boolean {
148
148
  /**
149
149
  * Adds a listener that will be called every time a patch is generated for the tree of the given target object.
150
150
  *
151
+ * The listener runs inside the action that made the change, so `getCurrentActionContext()` returns
152
+ * that action's context: its `rootContext` is the top-level action (for a flow step, the flow).
153
+ *
151
154
  * @param subtreeRoot Subtree root object of the patch listener.
152
155
  * @param listener The listener function that will be called everytime a patch is generated for the object or its children.
153
156
  * @returns A disposer to stop listening to patches.
@@ -190,6 +193,9 @@ export function internalOnPatches(
190
193
  * Adds a listener that will be called every time a patch is generated anywhere.
191
194
  * Usually prefer using `onPatches`.
192
195
  *
196
+ * The listener runs inside the action that made the change, so `getCurrentActionContext()` returns
197
+ * that action's context: its `rootContext` is the top-level action (for a flow step, the flow).
198
+ *
193
199
  * @param listener The listener function that will be called everytime a patch is generated anywhere.
194
200
  * @returns A disposer to stop listening to patches.
195
201
  */
package/src/ref/Ref.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Model } from "../model/Model"
2
1
  import { modelTypeKey } from "../model/metadata"
2
+ import { Model } from "../model/Model"
3
3
  import type { ModelClass } from "../modelShared/BaseModelShared"
4
4
  import { typesString } from "../types/primitiveBased/typesPrimitive"
5
5
  import { tProp } from "../types/tProp"