palistor 0.0.24

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 (431) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +947 -0
  3. package/dist/index.d.ts +54 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +58 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/react/createTrackingProxy.d.ts +55 -0
  8. package/dist/react/createTrackingProxy.d.ts.map +1 -0
  9. package/dist/react/createTrackingProxy.js +149 -0
  10. package/dist/react/createTrackingProxy.js.map +1 -0
  11. package/dist/react/useForm.d.ts +108 -0
  12. package/dist/react/useForm.d.ts.map +1 -0
  13. package/dist/react/useForm.js +180 -0
  14. package/dist/react/useForm.js.map +1 -0
  15. package/dist/react/useNotifier.d.ts +35 -0
  16. package/dist/react/useNotifier.d.ts.map +1 -0
  17. package/dist/react/useNotifier.js +41 -0
  18. package/dist/react/useNotifier.js.map +1 -0
  19. package/dist/react/usePersist.d.ts +45 -0
  20. package/dist/react/usePersist.d.ts.map +1 -0
  21. package/dist/react/usePersist.js +60 -0
  22. package/dist/react/usePersist.js.map +1 -0
  23. package/dist/react/useStoreContext.d.ts +42 -0
  24. package/dist/react/useStoreContext.d.ts.map +1 -0
  25. package/dist/react/useStoreContext.js +46 -0
  26. package/dist/react/useStoreContext.js.map +1 -0
  27. package/dist/react/useTranslator.d.ts +37 -0
  28. package/dist/react/useTranslator.d.ts.map +1 -0
  29. package/dist/react/useTranslator.js +43 -0
  30. package/dist/react/useTranslator.js.map +1 -0
  31. package/dist/store/applyPatch/applyPatch.d.ts +17 -0
  32. package/dist/store/applyPatch/applyPatch.d.ts.map +1 -0
  33. package/dist/store/applyPatch/applyPatch.js +44 -0
  34. package/dist/store/applyPatch/applyPatch.js.map +1 -0
  35. package/dist/store/buildProxy/buildEntityProjectionProxy.d.ts +52 -0
  36. package/dist/store/buildProxy/buildEntityProjectionProxy.d.ts.map +1 -0
  37. package/dist/store/buildProxy/buildEntityProjectionProxy.js +321 -0
  38. package/dist/store/buildProxy/buildEntityProjectionProxy.js.map +1 -0
  39. package/dist/store/buildProxy/buildListProxy.d.ts +33 -0
  40. package/dist/store/buildProxy/buildListProxy.d.ts.map +1 -0
  41. package/dist/store/buildProxy/buildListProxy.js +306 -0
  42. package/dist/store/buildProxy/buildListProxy.js.map +1 -0
  43. package/dist/store/buildProxy/buildProxy.d.ts +41 -0
  44. package/dist/store/buildProxy/buildProxy.d.ts.map +1 -0
  45. package/dist/store/buildProxy/buildProxy.js +380 -0
  46. package/dist/store/buildProxy/buildProxy.js.map +1 -0
  47. package/dist/store/buildProxy/computeProxyKeys.d.ts +15 -0
  48. package/dist/store/buildProxy/computeProxyKeys.d.ts.map +1 -0
  49. package/dist/store/buildProxy/computeProxyKeys.js +28 -0
  50. package/dist/store/buildProxy/computeProxyKeys.js.map +1 -0
  51. package/dist/store/buildProxy/handleLazyResolve.d.ts +10 -0
  52. package/dist/store/buildProxy/handleLazyResolve.d.ts.map +1 -0
  53. package/dist/store/buildProxy/handleLazyResolve.js +26 -0
  54. package/dist/store/buildProxy/handleLazyResolve.js.map +1 -0
  55. package/dist/store/buildProxy/initProxyCaches.d.ts +16 -0
  56. package/dist/store/buildProxy/initProxyCaches.d.ts.map +1 -0
  57. package/dist/store/buildProxy/initProxyCaches.js +17 -0
  58. package/dist/store/buildProxy/initProxyCaches.js.map +1 -0
  59. package/dist/store/compute/computeFieldState.d.ts +10 -0
  60. package/dist/store/compute/computeFieldState.d.ts.map +1 -0
  61. package/dist/store/compute/computeFieldState.js +53 -0
  62. package/dist/store/compute/computeFieldState.js.map +1 -0
  63. package/dist/store/compute/fieldStateChanged.d.ts +6 -0
  64. package/dist/store/compute/fieldStateChanged.d.ts.map +1 -0
  65. package/dist/store/compute/fieldStateChanged.js +20 -0
  66. package/dist/store/compute/fieldStateChanged.js.map +1 -0
  67. package/dist/store/compute/index.d.ts +7 -0
  68. package/dist/store/compute/index.d.ts.map +1 -0
  69. package/dist/store/compute/index.js +6 -0
  70. package/dist/store/compute/index.js.map +1 -0
  71. package/dist/store/compute/isEmpty.d.ts +6 -0
  72. package/dist/store/compute/isEmpty.d.ts.map +1 -0
  73. package/dist/store/compute/isEmpty.js +14 -0
  74. package/dist/store/compute/isEmpty.js.map +1 -0
  75. package/dist/store/compute/recompute/collectGroupComputeNodes.d.ts +11 -0
  76. package/dist/store/compute/recompute/collectGroupComputeNodes.d.ts.map +1 -0
  77. package/dist/store/compute/recompute/collectGroupComputeNodes.js +26 -0
  78. package/dist/store/compute/recompute/collectGroupComputeNodes.js.map +1 -0
  79. package/dist/store/compute/recompute/collectGroupLeafNodes.d.ts +11 -0
  80. package/dist/store/compute/recompute/collectGroupLeafNodes.d.ts.map +1 -0
  81. package/dist/store/compute/recompute/collectGroupLeafNodes.js +26 -0
  82. package/dist/store/compute/recompute/collectGroupLeafNodes.js.map +1 -0
  83. package/dist/store/compute/recompute/index.d.ts +7 -0
  84. package/dist/store/compute/recompute/index.d.ts.map +1 -0
  85. package/dist/store/compute/recompute/index.js +6 -0
  86. package/dist/store/compute/recompute/index.js.map +1 -0
  87. package/dist/store/compute/recompute/recomputeAndNotify.d.ts +8 -0
  88. package/dist/store/compute/recompute/recomputeAndNotify.d.ts.map +1 -0
  89. package/dist/store/compute/recompute/recomputeAndNotify.js +13 -0
  90. package/dist/store/compute/recompute/recomputeAndNotify.js.map +1 -0
  91. package/dist/store/compute/recompute/recomputeLeaves.d.ts +23 -0
  92. package/dist/store/compute/recompute/recomputeLeaves.d.ts.map +1 -0
  93. package/dist/store/compute/recompute/recomputeLeaves.js +77 -0
  94. package/dist/store/compute/recompute/recomputeLeaves.js.map +1 -0
  95. package/dist/store/compute/recompute/recomputeTargeted.d.ts +14 -0
  96. package/dist/store/compute/recompute/recomputeTargeted.d.ts.map +1 -0
  97. package/dist/store/compute/recompute/recomputeTargeted.js +50 -0
  98. package/dist/store/compute/recompute/recomputeTargeted.js.map +1 -0
  99. package/dist/store/compute/recompute/topologicalSortComputed.d.ts +16 -0
  100. package/dist/store/compute/recompute/topologicalSortComputed.d.ts.map +1 -0
  101. package/dist/store/compute/recompute/topologicalSortComputed.js +60 -0
  102. package/dist/store/compute/recompute/topologicalSortComputed.js.map +1 -0
  103. package/dist/store/compute/recompute/types.d.ts +24 -0
  104. package/dist/store/compute/recompute/types.d.ts.map +1 -0
  105. package/dist/store/compute/recompute/types.js +2 -0
  106. package/dist/store/compute/recompute/types.js.map +1 -0
  107. package/dist/store/compute/resolveFlag.d.ts +7 -0
  108. package/dist/store/compute/resolveFlag.d.ts.map +1 -0
  109. package/dist/store/compute/resolveFlag.js +12 -0
  110. package/dist/store/compute/resolveFlag.js.map +1 -0
  111. package/dist/store/compute/resolveString.d.ts +11 -0
  112. package/dist/store/compute/resolveString.d.ts.map +1 -0
  113. package/dist/store/compute/resolveString.js +18 -0
  114. package/dist/store/compute/resolveString.js.map +1 -0
  115. package/dist/store/compute/types.d.ts +37 -0
  116. package/dist/store/compute/types.d.ts.map +1 -0
  117. package/dist/store/compute/types.js +2 -0
  118. package/dist/store/compute/types.js.map +1 -0
  119. package/dist/store/constants.d.ts +83 -0
  120. package/dist/store/constants.d.ts.map +1 -0
  121. package/dist/store/constants.js +145 -0
  122. package/dist/store/constants.js.map +1 -0
  123. package/dist/store/defineFieldMapping.d.ts +41 -0
  124. package/dist/store/defineFieldMapping.d.ts.map +1 -0
  125. package/dist/store/defineFieldMapping.js +42 -0
  126. package/dist/store/defineFieldMapping.js.map +1 -0
  127. package/dist/store/defineList.d.ts +14 -0
  128. package/dist/store/defineList.d.ts.map +1 -0
  129. package/dist/store/defineList.js +7 -0
  130. package/dist/store/defineList.js.map +1 -0
  131. package/dist/store/dirtyTracking/captureInitialValues.d.ts +8 -0
  132. package/dist/store/dirtyTracking/captureInitialValues.d.ts.map +1 -0
  133. package/dist/store/dirtyTracking/captureInitialValues.js +16 -0
  134. package/dist/store/dirtyTracking/captureInitialValues.js.map +1 -0
  135. package/dist/store/dirtyTracking/collectInitialSnapshot.d.ts +10 -0
  136. package/dist/store/dirtyTracking/collectInitialSnapshot.d.ts.map +1 -0
  137. package/dist/store/dirtyTracking/collectInitialSnapshot.js +35 -0
  138. package/dist/store/dirtyTracking/collectInitialSnapshot.js.map +1 -0
  139. package/dist/store/dirtyTracking/index.d.ts +7 -0
  140. package/dist/store/dirtyTracking/index.d.ts.map +1 -0
  141. package/dist/store/dirtyTracking/index.js +6 -0
  142. package/dist/store/dirtyTracking/index.js.map +1 -0
  143. package/dist/store/dirtyTracking/isDirtyValue.d.ts +7 -0
  144. package/dist/store/dirtyTracking/isDirtyValue.d.ts.map +1 -0
  145. package/dist/store/dirtyTracking/isDirtyValue.js +25 -0
  146. package/dist/store/dirtyTracking/isDirtyValue.js.map +1 -0
  147. package/dist/store/dirtyTracking/mergeInitialValues.d.ts +11 -0
  148. package/dist/store/dirtyTracking/mergeInitialValues.d.ts.map +1 -0
  149. package/dist/store/dirtyTracking/mergeInitialValues.js +29 -0
  150. package/dist/store/dirtyTracking/mergeInitialValues.js.map +1 -0
  151. package/dist/store/dirtyTracking/recomputeDirtyTargeted.d.ts +17 -0
  152. package/dist/store/dirtyTracking/recomputeDirtyTargeted.d.ts.map +1 -0
  153. package/dist/store/dirtyTracking/recomputeDirtyTargeted.js +90 -0
  154. package/dist/store/dirtyTracking/recomputeDirtyTargeted.js.map +1 -0
  155. package/dist/store/dirtyTracking/setGroupRevalidate.d.ts +13 -0
  156. package/dist/store/dirtyTracking/setGroupRevalidate.d.ts.map +1 -0
  157. package/dist/store/dirtyTracking/setGroupRevalidate.js +32 -0
  158. package/dist/store/dirtyTracking/setGroupRevalidate.js.map +1 -0
  159. package/dist/store/entityRegistry/entityRegistry.d.ts +166 -0
  160. package/dist/store/entityRegistry/entityRegistry.d.ts.map +1 -0
  161. package/dist/store/entityRegistry/entityRegistry.js +402 -0
  162. package/dist/store/entityRegistry/entityRegistry.js.map +1 -0
  163. package/dist/store/entityRegistry/generateId.d.ts +7 -0
  164. package/dist/store/entityRegistry/generateId.d.ts.map +1 -0
  165. package/dist/store/entityRegistry/generateId.js +18 -0
  166. package/dist/store/entityRegistry/generateId.js.map +1 -0
  167. package/dist/store/entityRegistry/index.d.ts +4 -0
  168. package/dist/store/entityRegistry/index.d.ts.map +1 -0
  169. package/dist/store/entityRegistry/index.js +3 -0
  170. package/dist/store/entityRegistry/index.js.map +1 -0
  171. package/dist/store/entityRegistry/types.d.ts +50 -0
  172. package/dist/store/entityRegistry/types.d.ts.map +1 -0
  173. package/dist/store/entityRegistry/types.js +2 -0
  174. package/dist/store/entityRegistry/types.js.map +1 -0
  175. package/dist/store/fieldMapping.typecheck.d.ts +2 -0
  176. package/dist/store/fieldMapping.typecheck.d.ts.map +1 -0
  177. package/dist/store/fieldMapping.typecheck.js +71 -0
  178. package/dist/store/fieldMapping.typecheck.js.map +1 -0
  179. package/dist/store/groupDeps/createGroupDeps.d.ts +9 -0
  180. package/dist/store/groupDeps/createGroupDeps.d.ts.map +1 -0
  181. package/dist/store/groupDeps/createGroupDeps.js +29 -0
  182. package/dist/store/groupDeps/createGroupDeps.js.map +1 -0
  183. package/dist/store/groupDeps/createTrackingValues.d.ts +15 -0
  184. package/dist/store/groupDeps/createTrackingValues.d.ts.map +1 -0
  185. package/dist/store/groupDeps/createTrackingValues.js +39 -0
  186. package/dist/store/groupDeps/createTrackingValues.js.map +1 -0
  187. package/dist/store/groupDeps/getNodeGroupPath.d.ts +9 -0
  188. package/dist/store/groupDeps/getNodeGroupPath.d.ts.map +1 -0
  189. package/dist/store/groupDeps/getNodeGroupPath.js +20 -0
  190. package/dist/store/groupDeps/getNodeGroupPath.js.map +1 -0
  191. package/dist/store/groupDeps/getRecipientGroups.d.ts +5 -0
  192. package/dist/store/groupDeps/getRecipientGroups.d.ts.map +1 -0
  193. package/dist/store/groupDeps/getRecipientGroups.js +15 -0
  194. package/dist/store/groupDeps/getRecipientGroups.js.map +1 -0
  195. package/dist/store/groupDeps/groupDeps.d.ts +19 -0
  196. package/dist/store/groupDeps/groupDeps.d.ts.map +1 -0
  197. package/dist/store/groupDeps/groupDeps.js +19 -0
  198. package/dist/store/groupDeps/groupDeps.js.map +1 -0
  199. package/dist/store/groupDeps/index.d.ts +7 -0
  200. package/dist/store/groupDeps/index.d.ts.map +1 -0
  201. package/dist/store/groupDeps/index.js +7 -0
  202. package/dist/store/groupDeps/index.js.map +1 -0
  203. package/dist/store/groupDeps/pairKey.d.ts +7 -0
  204. package/dist/store/groupDeps/pairKey.d.ts.map +1 -0
  205. package/dist/store/groupDeps/pairKey.js +12 -0
  206. package/dist/store/groupDeps/pairKey.js.map +1 -0
  207. package/dist/store/groupDeps/resolveGroupByPath.d.ts +8 -0
  208. package/dist/store/groupDeps/resolveGroupByPath.d.ts.map +1 -0
  209. package/dist/store/groupDeps/resolveGroupByPath.js +19 -0
  210. package/dist/store/groupDeps/resolveGroupByPath.js.map +1 -0
  211. package/dist/store/init/createNotificationHub.d.ts +81 -0
  212. package/dist/store/init/createNotificationHub.d.ts.map +1 -0
  213. package/dist/store/init/createNotificationHub.js +149 -0
  214. package/dist/store/init/createNotificationHub.js.map +1 -0
  215. package/dist/store/init/createResolveManager.d.ts +166 -0
  216. package/dist/store/init/createResolveManager.d.ts.map +1 -0
  217. package/dist/store/init/createResolveManager.js +502 -0
  218. package/dist/store/init/createResolveManager.js.map +1 -0
  219. package/dist/store/init/initGroupSubmitting.d.ts +8 -0
  220. package/dist/store/init/initGroupSubmitting.d.ts.map +1 -0
  221. package/dist/store/init/initGroupSubmitting.js +39 -0
  222. package/dist/store/init/initGroupSubmitting.js.map +1 -0
  223. package/dist/store/normalizeConfig.d.ts +28 -0
  224. package/dist/store/normalizeConfig.d.ts.map +1 -0
  225. package/dist/store/normalizeConfig.js +76 -0
  226. package/dist/store/normalizeConfig.js.map +1 -0
  227. package/dist/store/onChangePipeline/computeFieldKey.d.ts +11 -0
  228. package/dist/store/onChangePipeline/computeFieldKey.d.ts.map +1 -0
  229. package/dist/store/onChangePipeline/computeFieldKey.js +18 -0
  230. package/dist/store/onChangePipeline/computeFieldKey.js.map +1 -0
  231. package/dist/store/onChangePipeline/findOnChangeAncestors.d.ts +8 -0
  232. package/dist/store/onChangePipeline/findOnChangeAncestors.d.ts.map +1 -0
  233. package/dist/store/onChangePipeline/findOnChangeAncestors.js +22 -0
  234. package/dist/store/onChangePipeline/findOnChangeAncestors.js.map +1 -0
  235. package/dist/store/onChangePipeline/onChangePipeline.d.ts +29 -0
  236. package/dist/store/onChangePipeline/onChangePipeline.d.ts.map +1 -0
  237. package/dist/store/onChangePipeline/onChangePipeline.js +99 -0
  238. package/dist/store/onChangePipeline/onChangePipeline.js.map +1 -0
  239. package/dist/store/persist/drivers.d.ts +34 -0
  240. package/dist/store/persist/drivers.d.ts.map +1 -0
  241. package/dist/store/persist/drivers.js +89 -0
  242. package/dist/store/persist/drivers.js.map +1 -0
  243. package/dist/store/persist/index.d.ts +7 -0
  244. package/dist/store/persist/index.d.ts.map +1 -0
  245. package/dist/store/persist/index.js +3 -0
  246. package/dist/store/persist/index.js.map +1 -0
  247. package/dist/store/persist/persistManager.d.ts +67 -0
  248. package/dist/store/persist/persistManager.d.ts.map +1 -0
  249. package/dist/store/persist/persistManager.js +198 -0
  250. package/dist/store/persist/persistManager.js.map +1 -0
  251. package/dist/store/persist/types.d.ts +66 -0
  252. package/dist/store/persist/types.d.ts.map +1 -0
  253. package/dist/store/persist/types.js +9 -0
  254. package/dist/store/persist/types.js.map +1 -0
  255. package/dist/store/resetPipeline/buildResetPatch.d.ts +11 -0
  256. package/dist/store/resetPipeline/buildResetPatch.d.ts.map +1 -0
  257. package/dist/store/resetPipeline/buildResetPatch.js +22 -0
  258. package/dist/store/resetPipeline/buildResetPatch.js.map +1 -0
  259. package/dist/store/resetPipeline/collectDefaults.d.ts +12 -0
  260. package/dist/store/resetPipeline/collectDefaults.d.ts.map +1 -0
  261. package/dist/store/resetPipeline/collectDefaults.js +31 -0
  262. package/dist/store/resetPipeline/collectDefaults.js.map +1 -0
  263. package/dist/store/resetPipeline/resetPipeline.d.ts +19 -0
  264. package/dist/store/resetPipeline/resetPipeline.d.ts.map +1 -0
  265. package/dist/store/resetPipeline/resetPipeline.js +49 -0
  266. package/dist/store/resetPipeline/resetPipeline.js.map +1 -0
  267. package/dist/store/resolvePipeline/applyPendingWrites.d.ts +26 -0
  268. package/dist/store/resolvePipeline/applyPendingWrites.d.ts.map +1 -0
  269. package/dist/store/resolvePipeline/applyPendingWrites.js +68 -0
  270. package/dist/store/resolvePipeline/applyPendingWrites.js.map +1 -0
  271. package/dist/store/resolvePipeline/createContextTrackingProxy.d.ts +16 -0
  272. package/dist/store/resolvePipeline/createContextTrackingProxy.d.ts.map +1 -0
  273. package/dist/store/resolvePipeline/createContextTrackingProxy.js +29 -0
  274. package/dist/store/resolvePipeline/createContextTrackingProxy.js.map +1 -0
  275. package/dist/store/resolvePipeline/createValuesTrackingProxy.d.ts +75 -0
  276. package/dist/store/resolvePipeline/createValuesTrackingProxy.d.ts.map +1 -0
  277. package/dist/store/resolvePipeline/createValuesTrackingProxy.js +128 -0
  278. package/dist/store/resolvePipeline/createValuesTrackingProxy.js.map +1 -0
  279. package/dist/store/resolvePipeline/executeEntityFieldResolve.d.ts +29 -0
  280. package/dist/store/resolvePipeline/executeEntityFieldResolve.d.ts.map +1 -0
  281. package/dist/store/resolvePipeline/executeEntityFieldResolve.js +218 -0
  282. package/dist/store/resolvePipeline/executeEntityFieldResolve.js.map +1 -0
  283. package/dist/store/resolvePipeline/executeListResolve.d.ts +32 -0
  284. package/dist/store/resolvePipeline/executeListResolve.d.ts.map +1 -0
  285. package/dist/store/resolvePipeline/executeListResolve.js +157 -0
  286. package/dist/store/resolvePipeline/executeListResolve.js.map +1 -0
  287. package/dist/store/resolvePipeline/executeResolve.d.ts +26 -0
  288. package/dist/store/resolvePipeline/executeResolve.d.ts.map +1 -0
  289. package/dist/store/resolvePipeline/executeResolve.js +201 -0
  290. package/dist/store/resolvePipeline/executeResolve.js.map +1 -0
  291. package/dist/store/resolvePipeline/findResolvesToRetrigger.d.ts +10 -0
  292. package/dist/store/resolvePipeline/findResolvesToRetrigger.d.ts.map +1 -0
  293. package/dist/store/resolvePipeline/findResolvesToRetrigger.js +29 -0
  294. package/dist/store/resolvePipeline/findResolvesToRetrigger.js.map +1 -0
  295. package/dist/store/resolvePipeline/index.d.ts +22 -0
  296. package/dist/store/resolvePipeline/index.d.ts.map +1 -0
  297. package/dist/store/resolvePipeline/index.js +18 -0
  298. package/dist/store/resolvePipeline/index.js.map +1 -0
  299. package/dist/store/resolvePipeline/initResolveStates.d.ts +41 -0
  300. package/dist/store/resolvePipeline/initResolveStates.d.ts.map +1 -0
  301. package/dist/store/resolvePipeline/initResolveStates.js +95 -0
  302. package/dist/store/resolvePipeline/initResolveStates.js.map +1 -0
  303. package/dist/store/resolvePipeline/resetResolveState.d.ts +8 -0
  304. package/dist/store/resolvePipeline/resetResolveState.d.ts.map +1 -0
  305. package/dist/store/resolvePipeline/resetResolveState.js +18 -0
  306. package/dist/store/resolvePipeline/resetResolveState.js.map +1 -0
  307. package/dist/store/resolvePipeline/types.d.ts +134 -0
  308. package/dist/store/resolvePipeline/types.d.ts.map +1 -0
  309. package/dist/store/resolvePipeline/types.js +54 -0
  310. package/dist/store/resolvePipeline/types.js.map +1 -0
  311. package/dist/store/store/NodeRegistry/index.d.ts +3 -0
  312. package/dist/store/store/NodeRegistry/index.d.ts.map +1 -0
  313. package/dist/store/store/NodeRegistry/index.js +2 -0
  314. package/dist/store/store/NodeRegistry/index.js.map +1 -0
  315. package/dist/store/store/NodeRegistry/nodeRegistry.d.ts +139 -0
  316. package/dist/store/store/NodeRegistry/nodeRegistry.d.ts.map +1 -0
  317. package/dist/store/store/NodeRegistry/nodeRegistry.js +255 -0
  318. package/dist/store/store/NodeRegistry/nodeRegistry.js.map +1 -0
  319. package/dist/store/store/NodeRegistry/nodeUtils.d.ts +17 -0
  320. package/dist/store/store/NodeRegistry/nodeUtils.d.ts.map +1 -0
  321. package/dist/store/store/NodeRegistry/nodeUtils.js +21 -0
  322. package/dist/store/store/NodeRegistry/nodeUtils.js.map +1 -0
  323. package/dist/store/store/NodeRegistry/nodeView.d.ts +28 -0
  324. package/dist/store/store/NodeRegistry/nodeView.d.ts.map +1 -0
  325. package/dist/store/store/NodeRegistry/nodeView.js +16 -0
  326. package/dist/store/store/NodeRegistry/nodeView.js.map +1 -0
  327. package/dist/store/store/dirtyTracker.d.ts +27 -0
  328. package/dist/store/store/dirtyTracker.d.ts.map +1 -0
  329. package/dist/store/store/dirtyTracker.js +38 -0
  330. package/dist/store/store/dirtyTracker.js.map +1 -0
  331. package/dist/store/store/groupDepsMap.d.ts +52 -0
  332. package/dist/store/store/groupDepsMap.d.ts.map +1 -0
  333. package/dist/store/store/groupDepsMap.js +84 -0
  334. package/dist/store/store/groupDepsMap.js.map +1 -0
  335. package/dist/store/store/hasComputedProps.d.ts +7 -0
  336. package/dist/store/store/hasComputedProps.d.ts.map +1 -0
  337. package/dist/store/store/hasComputedProps.js +15 -0
  338. package/dist/store/store/hasComputedProps.js.map +1 -0
  339. package/dist/store/store/index.d.ts +6 -0
  340. package/dist/store/store/index.d.ts.map +1 -0
  341. package/dist/store/store/index.js +3 -0
  342. package/dist/store/store/index.js.map +1 -0
  343. package/dist/store/store/nodeMap.d.ts +12 -0
  344. package/dist/store/store/nodeMap.d.ts.map +1 -0
  345. package/dist/store/store/nodeMap.js +30 -0
  346. package/dist/store/store/nodeMap.js.map +1 -0
  347. package/dist/store/store/palistor.d.ts +256 -0
  348. package/dist/store/store/palistor.d.ts.map +1 -0
  349. package/dist/store/store/palistor.js +772 -0
  350. package/dist/store/store/palistor.js.map +1 -0
  351. package/dist/store/store/registerNodes.d.ts +33 -0
  352. package/dist/store/store/registerNodes.d.ts.map +1 -0
  353. package/dist/store/store/registerNodes.js +88 -0
  354. package/dist/store/store/registerNodes.js.map +1 -0
  355. package/dist/store/store/serviceRegistry.d.ts +24 -0
  356. package/dist/store/store/serviceRegistry.d.ts.map +1 -0
  357. package/dist/store/store/serviceRegistry.js +32 -0
  358. package/dist/store/store/serviceRegistry.js.map +1 -0
  359. package/dist/store/store/types.d.ts +622 -0
  360. package/dist/store/store/types.d.ts.map +1 -0
  361. package/dist/store/store/types.js +2 -0
  362. package/dist/store/store/types.js.map +1 -0
  363. package/dist/store/submitPipeline/applyLeafBeforeSubmit.d.ts +7 -0
  364. package/dist/store/submitPipeline/applyLeafBeforeSubmit.d.ts.map +1 -0
  365. package/dist/store/submitPipeline/applyLeafBeforeSubmit.js +26 -0
  366. package/dist/store/submitPipeline/applyLeafBeforeSubmit.js.map +1 -0
  367. package/dist/store/submitPipeline/collectLeafStates.d.ts +11 -0
  368. package/dist/store/submitPipeline/collectLeafStates.d.ts.map +1 -0
  369. package/dist/store/submitPipeline/collectLeafStates.js +17 -0
  370. package/dist/store/submitPipeline/collectLeafStates.js.map +1 -0
  371. package/dist/store/submitPipeline/getSubValues.d.ts +9 -0
  372. package/dist/store/submitPipeline/getSubValues.d.ts.map +1 -0
  373. package/dist/store/submitPipeline/getSubValues.js +26 -0
  374. package/dist/store/submitPipeline/getSubValues.js.map +1 -0
  375. package/dist/store/submitPipeline/submitPipeline.d.ts +32 -0
  376. package/dist/store/submitPipeline/submitPipeline.d.ts.map +1 -0
  377. package/dist/store/submitPipeline/submitPipeline.js +119 -0
  378. package/dist/store/submitPipeline/submitPipeline.js.map +1 -0
  379. package/dist/store/submitPipeline/types.d.ts +12 -0
  380. package/dist/store/submitPipeline/types.d.ts.map +1 -0
  381. package/dist/store/submitPipeline/types.js +2 -0
  382. package/dist/store/submitPipeline/types.js.map +1 -0
  383. package/dist/store/traversal/index.d.ts +4 -0
  384. package/dist/store/traversal/index.d.ts.map +1 -0
  385. package/dist/store/traversal/index.js +3 -0
  386. package/dist/store/traversal/index.js.map +1 -0
  387. package/dist/store/traversal/nodeClassifier.d.ts +23 -0
  388. package/dist/store/traversal/nodeClassifier.d.ts.map +1 -0
  389. package/dist/store/traversal/nodeClassifier.js +46 -0
  390. package/dist/store/traversal/nodeClassifier.js.map +1 -0
  391. package/dist/store/traversal/walkFull.d.ts +33 -0
  392. package/dist/store/traversal/walkFull.d.ts.map +1 -0
  393. package/dist/store/traversal/walkFull.js +28 -0
  394. package/dist/store/traversal/walkFull.js.map +1 -0
  395. package/dist/store/valuesCache/valuesCache.d.ts +27 -0
  396. package/dist/store/valuesCache/valuesCache.d.ts.map +1 -0
  397. package/dist/store/valuesCache/valuesCache.js +58 -0
  398. package/dist/store/valuesCache/valuesCache.js.map +1 -0
  399. package/dist/store/writePipeline/formatPatch.d.ts +14 -0
  400. package/dist/store/writePipeline/formatPatch.d.ts.map +1 -0
  401. package/dist/store/writePipeline/formatPatch.js +35 -0
  402. package/dist/store/writePipeline/formatPatch.js.map +1 -0
  403. package/dist/store/writePipeline/formatValue.d.ts +12 -0
  404. package/dist/store/writePipeline/formatValue.d.ts.map +1 -0
  405. package/dist/store/writePipeline/formatValue.js +15 -0
  406. package/dist/store/writePipeline/formatValue.js.map +1 -0
  407. package/dist/store/writePipeline/index.d.ts +8 -0
  408. package/dist/store/writePipeline/index.d.ts.map +1 -0
  409. package/dist/store/writePipeline/index.js +7 -0
  410. package/dist/store/writePipeline/index.js.map +1 -0
  411. package/dist/store/writePipeline/mergeChanged.d.ts +9 -0
  412. package/dist/store/writePipeline/mergeChanged.d.ts.map +1 -0
  413. package/dist/store/writePipeline/mergeChanged.js +15 -0
  414. package/dist/store/writePipeline/mergeChanged.js.map +1 -0
  415. package/dist/store/writePipeline/runSetter.d.ts +16 -0
  416. package/dist/store/writePipeline/runSetter.d.ts.map +1 -0
  417. package/dist/store/writePipeline/runSetter.js +35 -0
  418. package/dist/store/writePipeline/runSetter.js.map +1 -0
  419. package/dist/store/writePipeline/storeValue.d.ts +11 -0
  420. package/dist/store/writePipeline/storeValue.d.ts.map +1 -0
  421. package/dist/store/writePipeline/storeValue.js +17 -0
  422. package/dist/store/writePipeline/storeValue.js.map +1 -0
  423. package/dist/store/writePipeline/types.d.ts +10 -0
  424. package/dist/store/writePipeline/types.d.ts.map +1 -0
  425. package/dist/store/writePipeline/types.js +2 -0
  426. package/dist/store/writePipeline/types.js.map +1 -0
  427. package/dist/store/writePipeline/writePipeline.d.ts +31 -0
  428. package/dist/store/writePipeline/writePipeline.d.ts.map +1 -0
  429. package/dist/store/writePipeline/writePipeline.js +97 -0
  430. package/dist/store/writePipeline/writePipeline.js.map +1 -0
  431. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,947 @@
1
+ # Palistor
2
+
3
+ > Реактивный state manager для форм с гранулярным рендерингом
4
+
5
+ Palistor — библиотека управления состоянием форм для React. Построена на двухслойной proxy-архитектуре: framework-agnostic ядро и React-интеграция с точечным трекингом подписок. Компонент перерендеривается **только** при изменении тех полей, которые он реально читал.
6
+
7
+ ---
8
+
9
+ ## Установка
10
+
11
+ Пакет публикуется в **публичный npm-реестр** под именем `palistor`.
12
+
13
+ ```bash
14
+ npm install palistor
15
+ # или
16
+ yarn add palistor
17
+ # или
18
+ pnpm add palistor
19
+ ```
20
+
21
+ **Peer-зависимости:** `react ^19`
22
+
23
+ > **Альтернатива — GitHub Packages.** Тот же пакет доступен под scoped-именем
24
+ > `@projectint/palistor`. Для установки добавьте в `.npmrc`:
25
+ > ```
26
+ > @projectint:registry=https://npm.pkg.github.com
27
+ > ```
28
+ > и (для приватного доступа) токен:
29
+ > ```
30
+ > //npm.pkg.github.com/:_authToken=YOUR_GITHUB_PAT
31
+ > ```
32
+ > затем `npm install @projectint/palistor`. Каноническим считается имя `palistor`.
33
+
34
+ ### Импорт
35
+
36
+ Все публичные symbol'ы доступны из корневого модуля:
37
+
38
+ ```typescript
39
+ import {
40
+ Palistor,
41
+ useForm,
42
+ usePersist,
43
+ useTranslator,
44
+ useNotifier,
45
+ defineList,
46
+ localStorageDriver,
47
+ sessionStorageDriver,
48
+ } from "palistor";
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Содержание
54
+
55
+ - [Возможности](#возможности)
56
+ - [Быстрый старт](#быстрый-старт)
57
+ - [Концепции](#концепции)
58
+ - [API Reference](#api-reference)
59
+ - [Типизация](#типизация)
60
+ - [Рецепты](#рецепты)
61
+ - [Async Resolver](#async-resolver)
62
+ - [Списки и сущности](#списки-и-сущности)
63
+ - [Persist](#persist)
64
+ - [i18n](#i18n)
65
+ - [Уведомления](#уведомления)
66
+ - [Структура модуля](#структура-модуля)
67
+
68
+ ---
69
+
70
+ ## Возможности
71
+
72
+ | | |
73
+ |---|---|
74
+ | **Гранулярные ре-рендеры** | Компонент подписывается только на те поля, которые он читал — больше ничего не триггерит ре-рендер |
75
+ | **Computed Field State** | `isVisible`, `isRequired`, `error`, `dirty` пересчитываются автоматически по конфигу |
76
+ | **Proxy API** | Нативный синтаксис: `field.value = x` вместо `dispatch({ type: "SET", field: "...", value: x })` |
77
+ | **Submit pipeline** | `beforeSubmit → validate → onSubmit → afterSubmit` с revalidate-семантикой |
78
+ | **Dirty tracking** | Per-field и per-group флаг изменений; baseline обновляется после resolve и reset |
79
+ | **Async resolvers** | Загрузка данных с auto-deps, retry, optimistic updates и React Suspense |
80
+ | **Списки / Entities** | Нормализованный реестр сущностей, list proxy с `add / remove / setItems` |
81
+ | **Persist** | Автосохранение в `localStorage`, `sessionStorage` или любом кастомном драйвере |
82
+ | **i18n** | Одна строка в layout — `label`, `placeholder`, `description` переводятся везде |
83
+ | **Тестируемость** | Framework-agnostic ядро — тестируется без React |
84
+
85
+ ---
86
+
87
+ ## Быстрый старт
88
+
89
+ ### 1. Создайте store
90
+
91
+ ```typescript
92
+ import { createProxyStore } from "palistor";
93
+
94
+ export const paymentStore = createProxyStore({
95
+ config: {
96
+ paymentType: {
97
+ value: "card",
98
+ label: "Способ оплаты",
99
+ },
100
+ cardNumber: {
101
+ value: "",
102
+ label: "Номер карты",
103
+ placeholder: "0000 0000 0000 0000",
104
+ isVisible: (v) => v.paymentType === "card",
105
+ isRequired: (v) => v.paymentType === "card",
106
+ validate: (value, v) =>
107
+ v.paymentType === "card" && value.length < 16
108
+ ? "Введите 16 цифр"
109
+ : undefined,
110
+ },
111
+ passport: {
112
+ isVisible: (v) => v.paymentType === "bank",
113
+ number: { value: "", label: "Серия и номер", isRequired: true },
114
+ issueDate: { value: "", label: "Дата выдачи" },
115
+ },
116
+ amount: { value: 0, label: "Сумма", isRequired: true },
117
+ },
118
+ initialValues: { paymentType: "card" },
119
+ });
120
+ ```
121
+
122
+ ### 2. Используйте в компоненте
123
+
124
+ ```tsx
125
+ import { useForm } from "palistor";
126
+
127
+ function PaymentForm() {
128
+ const form = useForm(paymentStore);
129
+
130
+ return (
131
+ <form onSubmit={() => paymentStore.submit()}>
132
+ <Select
133
+ value={form.paymentType.value}
134
+ onChange={(e) => (form.paymentType.value = e.target.value)}
135
+ label={form.paymentType.label}
136
+ />
137
+
138
+ {form.cardNumber.isVisible && (
139
+ <Input
140
+ value={form.cardNumber.value}
141
+ onChange={(e) => (form.cardNumber.value = e.target.value)}
142
+ label={form.cardNumber.label}
143
+ isRequired={form.cardNumber.isRequired}
144
+ isInvalid={form.cardNumber.isInvalid}
145
+ errorMessage={form.cardNumber.errorMessage}
146
+ />
147
+ )}
148
+
149
+ {form.passport.isVisible && <PassportSection passport={form.passport} />}
150
+
151
+ <Button type="submit" isLoading={form.submitting}>
152
+ Оплатить
153
+ </Button>
154
+ </form>
155
+ );
156
+ }
157
+ ```
158
+
159
+ ### 3. Изолированный ре-рендер дочернего компонента
160
+
161
+ Если дочернему компоненту нужен **независимый** трекинг, передайте поддерево в `useForm`:
162
+
163
+ ```tsx
164
+ function PassportSection({ passport }) {
165
+ // Собственный tracking proxy — ре-рендер только при изменении полей passport
166
+ const p = useForm(passport);
167
+
168
+ return (
169
+ <>
170
+ <Input value={p.number.value} onChange={(e) => (p.number.value = e.target.value)} label={p.number.label} />
171
+ <Input value={p.issueDate.value} onChange={(e) => (p.issueDate.value = e.target.value)} label={p.issueDate.label} />
172
+ </>
173
+ );
174
+ }
175
+ ```
176
+
177
+ > **Без `useForm` в дочернем** — компонент рендерится каскадно вместе с родителем. Подходит для простых листовых компонентов.
178
+
179
+ ---
180
+
181
+ ## Концепции
182
+
183
+ ### Два узла: лист и группа
184
+
185
+ Тип узла определяется наличием свойства `value`:
186
+
187
+ ```
188
+ Есть "value" → листовой узел (поле формы)
189
+ Нет "value" → групповой узел (контейнер или секция)
190
+ ```
191
+
192
+ ```typescript
193
+ const config = {
194
+ // Листовой узел — управляет значением
195
+ email: { value: "", isRequired: true },
196
+
197
+ // Групповой узел — контейнер с вычисленными свойствами
198
+ address: {
199
+ isVisible: (v) => v.showAddress,
200
+ city: { value: "" },
201
+ country: { value: "RU" },
202
+ },
203
+ };
204
+ ```
205
+
206
+ ### Как работает трекинг
207
+
208
+ ```
209
+ Рендер: читаем form.email.value, form.phone.value
210
+ → accessed = { emailNode, phoneNode }
211
+
212
+ SET form.city.value → cityNode++ → snapshot не изменился → нет ре-рендера ✓
213
+ SET form.email.value → emailNode++ → snapshot изменился → ре-рендер ✓
214
+ ```
215
+
216
+ Родитель, который только навигирует (`form.passport`), но не читает поля — **не ре-рендерится** при изменении полей внутри `passport`.
217
+
218
+ ### Поток данных при SET
219
+
220
+ ```
221
+ form.email.value = "user@example.com"
222
+
223
+ ├─ 1. formatter(rawValue, allValues) → нормализованное значение
224
+ ├─ 2. storeValue() → nodeState обновлён, valuesCache O(1)
225
+ ├─ 3. setter(value, allValues)? → patch → applyPatch() смежных полей
226
+ ├─ 4. recompute(changedNodes) → таргетированный пересчёт FieldState
227
+ ├─ 5. recomputeDirtyTargeted() → dirty флаги вверх по дереву
228
+ ├─ 6. notifyChanged() → version++ → useSyncExternalStore → ре-рендер
229
+ └─ 7. onChangePipeline.fire() → onChange callback (fire-and-forget)
230
+ ```
231
+
232
+ ---
233
+
234
+ ## API Reference
235
+
236
+ ### `createProxyStore(options)`
237
+
238
+ ```typescript
239
+ import { createProxyStore } from "palistor";
240
+
241
+ const store = createProxyStore({
242
+ config: { /* дерево ConfigNode */ },
243
+ initialValues?: { /* перекрывают значения из конфига */ },
244
+ });
245
+ ```
246
+
247
+ **`ProxyStore<TConfig>` — возвращаемое значение:**
248
+
249
+ | Свойство / метод | Тип | Описание |
250
+ |---|---|---|
251
+ | `store.proxy` | `ConfigProxy<TConfig>` | Реактивный прокси — структура повторяет конфиг |
252
+ | `store.getValues()` | `DeepValues<TConfig>` | Все текущие значения вложенным объектом |
253
+ | `store.submit()` | `Promise<SubmitResult>` | Submit root-группы |
254
+ | `store.reset(values?)` | `void` | Сброс к defaults (или к переданным значениям) |
255
+ | `store.set(data)` | `string` | Upsert entity; возвращает `id` |
256
+ | `store.delete(id)` | `boolean` | Удалить entity из реестра |
257
+ | `store.rekey(oldId, newId)` | `void` | Переименовать entity во всех списках |
258
+ | `store.subscribe(node, fn)` | `() => void` | Подписка на изменения узла; возвращает unsubscribe |
259
+ | `store.subscribeGlobal(fn)` | `() => void` | Подписка на любые изменения |
260
+ | `store.getVersion()` | `number` | Глобальная версия (инкремент при каждом изменении) |
261
+ | `store.getNodeVersion(node)` | `number` | Версия конкретного узла |
262
+ | `store.setTranslator(fn \| null)` | `void` | Зарегистрировать i18n-функцию |
263
+ | `store.setNotifier(fn \| null)` | `void` | Зарегистрировать функцию уведомлений |
264
+ | `store.persist` | `PersistManager` | Менеджер персистенции |
265
+
266
+ ---
267
+
268
+ ### `useForm(source)`
269
+
270
+ ```typescript
271
+ import { useForm } from "palistor";
272
+
273
+ const form = useForm(store); // tracking поверх корневого proxy
274
+ const section = useForm(form.address); // свой tracking для поддерева
275
+ ```
276
+
277
+ Возвращает типизированный `ConfigProxy<TConfig>`. Ре-рендер только при изменении нод, к которым компонент обращался через `FIELD_STATE_PROPS`.
278
+
279
+ **Паттерны подписки:**
280
+
281
+ | Паттерн | Когда использовать |
282
+ |---|---|
283
+ | `useForm(store)` + пропсы вниз | Простые формы, листовые UI-компоненты |
284
+ | `useForm(subtree)` в дочернем | Крупные секции с независимым ре-рендером |
285
+ | Проп без `useForm` | Pure UI-компоненты, рендерятся каскадно за родителем |
286
+
287
+ ---
288
+
289
+ ### Листовой узел — доступные свойства
290
+
291
+ ```typescript
292
+ // Чтение (реактивно — добавляет ноду в tracking set)
293
+ form.email.value // → TValue
294
+ form.email.label // → string | undefined
295
+ form.email.placeholder // → string | undefined
296
+ form.email.description // → string | undefined
297
+ form.email.isRequired // → boolean
298
+ form.email.isReadOnly // → boolean
299
+ form.email.isDisabled // → boolean
300
+ form.email.isVisible // → boolean
301
+ form.email.isInvalid // → boolean | undefined
302
+ form.email.errorMessage // → string | undefined
303
+ form.email.dirty // → boolean
304
+
305
+ // Запись — триггерит formatter → setter → recompute → notify
306
+ form.email.value = "new@example.com";
307
+ form.email.onValueChange("new@example.com"); // эквивалентно
308
+ ```
309
+
310
+ ### Групповой узел — доступные свойства
311
+
312
+ ```typescript
313
+ form.passport.isVisible // → boolean
314
+ form.passport.isRequired // → boolean | undefined
315
+ form.passport.isReadOnly // → boolean | undefined
316
+ form.passport.isDisabled // → boolean | undefined
317
+ form.passport.isInvalid // → boolean | undefined
318
+ form.passport.errorMessage // → string | undefined
319
+ form.passport.submitting // → boolean
320
+ form.passport.loading // → boolean (async resolver)
321
+ form.passport.dirty // → boolean (хотя бы одно поле изменилось)
322
+ form.passport.revalidate // → boolean (true после первого неудачного submit)
323
+ form.passport.values // → Record<string, unknown> — live-снапшот значений группы
324
+
325
+ await form.passport.submit(); // → SubmitResult
326
+ form.passport.reset({ number: "" }); // сброс поддерева
327
+ ```
328
+
329
+ `values` — живая ссылка на вложенный объект `valuesCache`, отражающий текущие значения всех листовых полей группы (рекурсивно). Обновляется in-place при каждой записи — стабильная ссылка, безопасна для передачи в API:
330
+
331
+ ```typescript
332
+ const vals = form.passport.values;
333
+ // → { number: "AB1234", issueDate: "2020-01-01" }
334
+
335
+ await api.submit(vals); // стабильная ссылка, всегда актуальна
336
+ ```
337
+
338
+ ---
339
+
340
+ ### `ConfigNode` — схема поля
341
+
342
+ ```typescript
343
+ // Листовой узел (есть "value")
344
+ interface LeafNode<TValue, TValues> {
345
+ value?: TValue | ((values: TValues) => TValue);
346
+ validate?: (value: TValue, values: TValues) => string | undefined | false;
347
+ formatter?: (value: unknown, values: TValues) => TValue;
348
+ setter?: (value: TValue, values: TValues) => DeepPartialValues<TValues>;
349
+ beforeSubmit?: (value: TValue, values: TValues) => TValue;
350
+ dependencies?: readonly string[]; // для топологической сортировки computed
351
+ componentProps?: Record<string, unknown>;
352
+
353
+ label?: string | ((values: TValues) => string);
354
+ placeholder?: string | ((values: TValues) => string);
355
+ description?: string | ((values: TValues) => string);
356
+ isVisible?: boolean | ((values: TValues) => boolean); // default: true
357
+ isRequired?: boolean | ((values: TValues) => boolean); // default: false
358
+ isDisabled?: boolean | ((values: TValues) => boolean); // default: false
359
+ isReadOnly?: boolean | ((values: TValues) => boolean); // default: false
360
+ }
361
+
362
+ // Групповой узел (нет "value")
363
+ interface GroupNode<TValues> {
364
+ beforeSubmit?: (values: TValues) => TValues;
365
+ onSubmit?: (values: TValues) => Promise<unknown> | unknown;
366
+ afterSubmit?: (result: unknown, actions: { reset: () => void }) => void | Promise<void>;
367
+ reset?: (defaults: TValues) => TValues;
368
+ onChange?: (info: OnChangeInfo<TValues>) => DeepPartialValues<TValues> | void | Promise<...>;
369
+ resolve?: ResolveConfig<TValues>;
370
+
371
+ isVisible?: boolean | ((values: TValues) => boolean);
372
+ isRequired?: boolean | ((values: TValues) => boolean);
373
+ isDisabled?: boolean | ((values: TValues) => boolean);
374
+ isReadOnly?: boolean | ((values: TValues) => boolean);
375
+
376
+ [key: string]: LeafNode | GroupNode | ListNode | any;
377
+ }
378
+
379
+ // Список (массив длиной 1 или 2)
380
+ type ListNode = [TemplateGroupNode] | [TemplateGroupNode, ListConfig];
381
+ ```
382
+
383
+ ---
384
+
385
+ ### `SubmitResult`
386
+
387
+ ```typescript
388
+ type SubmitResult =
389
+ | { success: true; result?: unknown }
390
+ | { success: false; errors: Array<{ path: string; message: string }> };
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Типизация
396
+
397
+ ### Вывод типа значений из конфига
398
+
399
+ `ExtractValues<typeof config>` извлекает плоский тип значений из конфига. Листовые узлы (`value`) — тип значения; групповые — вложенный объект; списки — массив:
400
+
401
+ ```typescript
402
+ const config = {
403
+ name: { value: "" },
404
+ age: { value: 0 },
405
+ address: {
406
+ city: { value: "" },
407
+ country: { value: "RU" },
408
+ },
409
+ };
410
+
411
+ type FormValues = ExtractValues<typeof config>;
412
+ // → { name: string; age: number; address: { city: string; country: string } }
413
+ ```
414
+
415
+ `DeepPartialValues<FormValues>` — глубокая optional-версия, используется для `initialValues`, `setter`, `setValues`:
416
+
417
+ ```typescript
418
+ const initial: DeepPartialValues<FormValues> = { address: { city: "Москва" } };
419
+ ```
420
+
421
+ ### Типизация пропсов без импорта конфига
422
+
423
+ `Palistor<T>` маппит интерфейс значений на прокси-дерево. Используйте его для типизации пропсов дочерних компонентов:
424
+
425
+ ```typescript
426
+ import type { Palistor } from "palistor";
427
+
428
+ interface UserData { name: string; email: string; address: { city: string } }
429
+
430
+ type Props = { user: Palistor<UserData> };
431
+
432
+ function UserForm({ user }: Props) {
433
+ const u = useForm(user);
434
+ return <input value={u.name.value} onChange={e => { u.name.value = e.target.value }} />;
435
+ }
436
+ // u.name → FieldProxyNode<string>
437
+ // u.address → Palistor<{ city: string }> (GroupProxyNode + поля)
438
+ ```
439
+
440
+ Массивы в `T` обрабатываются автоматически:
441
+
442
+ ```typescript
443
+ interface FormData { users: Array<{ name: string; email: string }> }
444
+ // form.users → ListProxyNode<Palistor<{ name: string; email: string }>>
445
+ ```
446
+
447
+ ### Типизированные entity-ссылки
448
+
449
+ При передаче entity-прокси через пропсы используйте `PalistorRef<TEntity>`:
450
+
451
+ ```typescript
452
+ import type { PalistorRef, InferEntity } from "palistor";
453
+
454
+ function UserRow({ user }: { user: PalistorRef<{ name: string; email: string }> }) {
455
+ const u = useForm(user, (s) => s.userTemplate);
456
+ return <span>{u.name.value}</span>;
457
+ }
458
+
459
+ // Получить тип entity обратно из ссылки:
460
+ type UserEntity = InferEntity<PalistorRef<{ name: string; email: string }>>;
461
+ // → { name: string; email: string }
462
+ ```
463
+
464
+ `PalistorList<TEntity>` — типизированный список: `ListProxyNode<PalistorRef<TEntity>>`.
465
+
466
+ ### defineList — типизированный список
467
+
468
+ Предпочитайте `defineList<TEntity>()` вместо сырого массива. Он проверяет, что ключи `template` соответствуют entity, а `resolver` возвращает `Promise<TEntity[]>`:
469
+
470
+ ```typescript
471
+ import { defineList } from "palistor";
472
+
473
+ interface User { id: string; name: string; email: string }
474
+
475
+ const users = defineList<User>({
476
+ template: {
477
+ id: { value: "" },
478
+ name: { value: "", isRequired: true },
479
+ email: { value: "" },
480
+ },
481
+ resolve: {
482
+ resolver: async (values) => api.getUsers(values.filter), // → Promise<User[]>
483
+ deps: ["filter"],
484
+ },
485
+ });
486
+
487
+ const config = { filter: { value: "" }, users };
488
+ // store.proxy.users → ListProxyNode<PalistorRef<User>>
489
+ ```
490
+
491
+ ### Справочник типов
492
+
493
+ | Тип | Назначение |
494
+ |-----|-----------|
495
+ | `ExtractValues<TConfig>` | Плоский тип значений из конфига |
496
+ | `ConfigProxy<TConfig>` | Полный прокси — тип, возвращаемый `useForm(store)` |
497
+ | `Palistor<T>` | Proxy на основе интерфейса значений — для пропсов дочерних компонентов |
498
+ | `PalistorRef<TEntity>` | Непрозрачная ссылка на entity — для пропсов одного элемента |
499
+ | `PalistorList<TEntity>` | Типизированный список: `ListProxyNode<PalistorRef<TEntity>>` |
500
+ | `InferEntity<T>` | Извлечь тип entity из `PalistorRef<TEntity>` |
501
+ | `MaybeComputed<TResult, TValues>` | `isVisible`, `isRequired`, `value` — константа или `(values) => T` |
502
+ | `MaybeTranslatable<TResult, TValues>` | `label`, `placeholder` — константа или `(t, values) => string` |
503
+ | `DeepPartialValues<T>` | Глубокая partial-версия: `initialValues`, патчи `setter`, `setValues` |
504
+ | `TranslateFn` | Совместим с next-intl `t`, i18next `t` и любым `(...args) => string` |
505
+ | `TemplateConfig<TEntity>` | Типизированный шаблон — каждый ключ entity → `ConfigNode<TEntity[K]>` |
506
+ | `ListResolver<TEntity>` | Типизированный resolver — `(values) => Promise<TEntity[]>` |
507
+
508
+ ### Полный паттерн типизации
509
+
510
+ ```typescript
511
+ import { Palistor, defineList } from "palistor";
512
+ import type { ExtractValues, PalistorRef, DeepPartialValues } from "palistor";
513
+
514
+ // 1. Вывести тип значений из конфига
515
+ const config = {
516
+ filter: { value: "" },
517
+ users: defineList<{ id: string; name: string }>({
518
+ template: { id: { value: "" }, name: { value: "" } },
519
+ }),
520
+ };
521
+
522
+ type Values = ExtractValues<typeof config>;
523
+ // → { filter: string; users: Array<{ id: string; name: string }> }
524
+
525
+ // 2. Создать store — TConfig выводится из конфига
526
+ const store = new Palistor({ config, initialValues: { filter: "active" } });
527
+
528
+ // 3. Типизировать пропсы через Palistor<Values>
529
+ type FormProps = { form: Palistor<Values> };
530
+
531
+ // 4. Типизировать entity-пропсы через PalistorRef
532
+ type UserRef = PalistorRef<{ id: string; name: string }>;
533
+ ```
534
+
535
+ ---
536
+
537
+ ## Рецепты
538
+
539
+ ### Computed value
540
+
541
+ ```typescript
542
+ createProxyStore({
543
+ config: {
544
+ price: { value: 100 },
545
+ quantity: { value: 2 },
546
+ total: { value: (v) => v.price * v.quantity, isReadOnly: true },
547
+ },
548
+ });
549
+ ```
550
+
551
+ ### Цепочка computed (топологическая сортировка)
552
+
553
+ ```typescript
554
+ config: {
555
+ price: { value: 100 },
556
+ tax: { value: (v) => v.price * 0.2, dependencies: ["price"] },
557
+ total: { value: (v) => v.price + v.tax, dependencies: ["price", "tax"] },
558
+ }
559
+ ```
560
+
561
+ ### formatter — нормализация при записи
562
+
563
+ ```typescript
564
+ email: {
565
+ value: "",
566
+ formatter: (v) => String(v).trim().toLowerCase(),
567
+ },
568
+ ```
569
+
570
+ ### setter — каскадное изменение нескольких полей
571
+
572
+ ```typescript
573
+ country: {
574
+ value: "RU",
575
+ setter: (value) => ({ city: "" }), // сбрасываем city при смене country
576
+ },
577
+ ```
578
+
579
+ ### onChange — реакция на изменение поля
580
+
581
+ ```typescript
582
+ passport: {
583
+ onChange: ({ fieldKey, newValue, allValues }) => {
584
+ if (fieldKey === "number") return { issueDate: "" };
585
+ },
586
+ number: { value: "" },
587
+ issueDate: { value: "" },
588
+ },
589
+ ```
590
+
591
+ ### beforeSubmit — трансформация перед отправкой
592
+
593
+ ```typescript
594
+ phone: {
595
+ value: "",
596
+ beforeSubmit: (value) => value.replace(/\D/g, ""), // не мутирует store
597
+ },
598
+ ```
599
+
600
+ ### Групповой submit с валидацией
601
+
602
+ ```typescript
603
+ const store = createProxyStore({
604
+ config: {
605
+ company: {
606
+ onSubmit: async (values) => api.saveCompany(values.company),
607
+ afterSubmit: (_result, { reset }) => {
608
+ showSuccessToast();
609
+ reset();
610
+ },
611
+ name: { value: "", isRequired: true },
612
+ taxId: { value: "" },
613
+ },
614
+ },
615
+ });
616
+
617
+ const result = await store.proxy.company.submit();
618
+ if (!result.success) {
619
+ console.log(result.errors);
620
+ // [{ path: "company.name", message: "Обязательное поле" }]
621
+ }
622
+ ```
623
+
624
+ ### Получение значений для отправки
625
+
626
+ ```typescript
627
+ const values = store.getValues();
628
+ // → { paymentType: "bank", passport: { number: "AB123", issueDate: "2020-01-01" } }
629
+ await api.submit(values);
630
+ ```
631
+
632
+ ---
633
+
634
+ ## Async Resolver
635
+
636
+ Конфигурируется на групповом узле. Загружает данные асинхронно — с авто-трекингом зависимостей, retry и поддержкой React Suspense.
637
+
638
+ ```typescript
639
+ const store = createProxyStore({
640
+ config: {
641
+ userId: { value: "" },
642
+
643
+ userInfo: {
644
+ resolve: {
645
+ // values — tracking proxy: GET-доступы автоматически становятся зависимостями.
646
+ // При изменении userId resolver перезапустится.
647
+ resolver: async (values) => {
648
+ const data = await api.getUser(values.userId);
649
+ return { name: data.name, email: data.email };
650
+ },
651
+
652
+ // Мгновенный placeholder до завершения resolver
653
+ optimisticResolver: (values) => ({ name: "Загрузка..." }),
654
+
655
+ onError: (error, ctx) => {
656
+ ctx.notify("Не удалось загрузить данные", "USER_LOAD_ERROR");
657
+ },
658
+
659
+ options: {
660
+ lazy: true, // ждать первого обращения к узлу (default: true)
661
+ suspense: false, // throw promise для React Suspense (default: false)
662
+ retry: { attempts: 3, delay: 1000 },
663
+ },
664
+ },
665
+
666
+ name: { value: "" },
667
+ email: { value: "" },
668
+ },
669
+ },
670
+ });
671
+ ```
672
+
673
+ ```tsx
674
+ const form = useForm(store);
675
+
676
+ // Без Suspense — ручная проверка loading
677
+ if (form.userInfo.loading) return <Spinner />;
678
+
679
+ // С Suspense — автоматически
680
+ <Suspense fallback={<Spinner />}>
681
+ <UserInfoSection />
682
+ </Suspense>
683
+ ```
684
+
685
+ **Поведение при изменении зависимости:**
686
+
687
+ ```
688
+ userId меняется
689
+ → notifyChanged → findResolvesToRetrigger
690
+ → resetResolveState(idle) → triggerResolve()
691
+ → optimisticResolver применяется мгновенно
692
+ → resolver запускается заново
693
+ ```
694
+
695
+ ---
696
+
697
+ ## Списки и сущности
698
+
699
+ Списки объявляются как массив длиной 1 или 2, где `[0]` — шаблон элемента:
700
+
701
+ ```typescript
702
+ const store = createProxyStore({
703
+ config: {
704
+ users: [
705
+ // Шаблон — описывает поля каждого элемента
706
+ {
707
+ id: { value: "" },
708
+ name: { value: "", isRequired: true },
709
+ email: { value: "" },
710
+ },
711
+ // Опциональный конфиг списка
712
+ {
713
+ resolve: {
714
+ resolver: async () => {
715
+ const data = await api.getUsers();
716
+ return data; // Array<{ id, name, email }>
717
+ },
718
+ },
719
+ },
720
+ ],
721
+ },
722
+ });
723
+ ```
724
+
725
+ ### List Proxy API
726
+
727
+ ```typescript
728
+ const form = useForm(store);
729
+
730
+ // Чтение
731
+ form.users.items // ReadonlyArray<EntityProjectionProxy>
732
+ form.users.length // number
733
+ form.users.loading // boolean
734
+ form.users.dirty // boolean — состав списка изменился vs. baseline
735
+
736
+ // Итерация
737
+ form.users.map((item, index, id) => <Row key={id} item={item} />)
738
+ for (const item of form.users) { ... }
739
+
740
+ // Мутации
741
+ form.users.add({ name: "Alice", email: "alice@example.com" }); // объект → upsert + добавить
742
+ form.users.add("existing-id"); // строка → добавить существующую
743
+ form.users.remove("user-id");
744
+ form.users.setItems(["id1", "id2", "id3"]); // bulk замена
745
+ form.users.getById("user-id"); // → EntityProjectionProxy | undefined
746
+ ```
747
+
748
+ ### EntityProjectionProxy — свойства элемента списка
749
+
750
+ Каждый элемент `form.users.items` — это `EntityProjectionProxy`. Доступные свойства:
751
+
752
+ ```typescript
753
+ const item = form.users.items[0];
754
+
755
+ item.id // string — идентификатор entity
756
+ item.name.value // значение поля через template (с formatter/validate/isRequired)
757
+ item.name.label // computed label из template
758
+ item.name.isRequired // computed isRequired из template
759
+ // ... все leaf props: value, label, placeholder, isRequired, isReadOnly, isDisabled,
760
+ // isVisible, isInvalid, errorMessage, dirty, onValueChange
761
+
762
+ item.loading // boolean — идёт ли resolve для этого entity
763
+ item.submitting // boolean — идёт ли submit для этого entity
764
+ item.values // Record<string, unknown> — plain объект значений entity
765
+ await item.submit(); // → SubmitResult — submit этого entity через template
766
+ ```
767
+
768
+ `item.values` — plain объект с текущими значениями полей entity, пригодный для передачи в API:
769
+
770
+ ```typescript
771
+ form.users.map((item) => {
772
+ console.log(item.values); // → { name: "Alice", email: "alice@example.com" }
773
+ });
774
+ ```
775
+
776
+ ### Работа с entity
777
+
778
+ ```typescript
779
+ // Создать / обновить entity — возвращает id
780
+ const id = store.set({ name: "Bob", email: "bob@example.com" });
781
+
782
+ // Если id не передан — генерируется временный (_tmp_...)
783
+ // После сохранения на сервере переименуйте:
784
+ store.rekey(tmpId, serverAssignedId);
785
+
786
+ // Удалить entity
787
+ store.delete(id);
788
+ ```
789
+
790
+ ---
791
+
792
+ ## Persist
793
+
794
+ Автосохранение состояния формы в любом хранилище.
795
+
796
+ ### React-хук (рекомендуется)
797
+
798
+ ```tsx
799
+ import { usePersist } from "palistor/react/usePersist";
800
+
801
+ function PaymentPage({ orderId }: { orderId: string }) {
802
+ usePersist(paymentStore, {
803
+ key: `payment-${orderId}`, // ключ может зависеть от пропсов
804
+ driver: localStorageDriver,
805
+ debounce: 500, // ms, default: 100
806
+ pick: ["cardNumber"], // персистировать только эти top-level поля
807
+ // omit: ["cvv"], // или исключить чувствительные поля
808
+ });
809
+
810
+ const form = useForm(paymentStore);
811
+ // ...
812
+ }
813
+ ```
814
+
815
+ ### Вне React
816
+
817
+ ```typescript
818
+ import { localStorageDriver, sessionStorageDriver } from "palistor/store/persist";
819
+
820
+ paymentStore.persist.enable({
821
+ key: "payment",
822
+ driver: localStorageDriver,
823
+ });
824
+
825
+ await paymentStore.persist.flush(); // принудительное сохранение
826
+ paymentStore.persist.disable();
827
+ ```
828
+
829
+ ### Кастомный драйвер
830
+
831
+ ```typescript
832
+ import type { PersistDriver } from "palistor/store/persist";
833
+
834
+ const myDriver: PersistDriver = {
835
+ getItem: (key) => myStorage.get(key),
836
+ setItem: (key, value) => myStorage.set(key, value),
837
+ removeItem: (key) => myStorage.delete(key),
838
+ };
839
+ ```
840
+
841
+ **`PersistOptions`:**
842
+
843
+ | Поле | Тип | По умолчанию | Описание |
844
+ |---|---|---|---|
845
+ | `key` | `string` | — | Ключ хранения |
846
+ | `driver` | `PersistDriver` | — | Реализация хранилища |
847
+ | `debounce` | `number` | `100` | Задержка записи, ms |
848
+ | `serialize` | `fn` | `JSON.stringify` | Кастомный сериализатор |
849
+ | `deserialize` | `fn` | `JSON.parse` | Кастомный десериализатор |
850
+ | `pick` | `string[]` | — | Персистировать только эти top-level ключи |
851
+ | `omit` | `string[]` | — | Исключить эти ключи (игнорируется если задан `pick`) |
852
+
853
+ ---
854
+
855
+ ## i18n
856
+
857
+ Регистрируйте функцию перевода один раз — в layout или провайдере. Все компоненты с `useForm` получат переведённые `label`, `placeholder`, `description` автоматически. При смене локали все компоненты перерендерятся.
858
+
859
+ ```tsx
860
+ import { useTranslations } from "next-intl";
861
+ import { useTranslator } from "palistor/react/useTranslator";
862
+
863
+ function RootLayout({ children }: { children: React.ReactNode }) {
864
+ const t = useTranslations();
865
+ useTranslator(paymentStore, t);
866
+ return <>{children}</>;
867
+ }
868
+ ```
869
+
870
+ В конфиге `label` / `placeholder` задаются как функции-переводчики:
871
+
872
+ ```typescript
873
+ cardNumber: {
874
+ value: "",
875
+ label: (t) => t("fields.cardNumber"),
876
+ placeholder: (t) => t("fields.cardNumber.placeholder"),
877
+ },
878
+ ```
879
+
880
+ > Без translator функции возвращают свой результат вызова как есть — удобно для тестов без i18n-окружения.
881
+
882
+ ---
883
+
884
+ ## Уведомления
885
+
886
+ Регистрирует функцию toast-уведомлений для использования внутри `resolve.onError`:
887
+
888
+ ```tsx
889
+ import { useNotifier } from "palistor/react/useNotifier";
890
+
891
+ function RootLayout({ children }: { children: React.ReactNode }) {
892
+ const notifyError = useCallback((error: unknown, code?: string) => {
893
+ addToast({ title: code ?? "Ошибка", color: "danger" });
894
+ }, []);
895
+
896
+ useNotifier(paymentStore, notifyError);
897
+ return <>{children}</>;
898
+ }
899
+ ```
900
+
901
+ ---
902
+
903
+ ## Структура модуля
904
+
905
+ ```
906
+ palistor/
907
+ ├── index.ts # Публичный API
908
+ ├── store/
909
+ │ ├── store/
910
+ │ │ ├── palistor.ts # Palistor — ядро системы (kernel + ProxyStore)
911
+ │ │ ├── registerNodes.ts # Инициализация leafNodes + nodeState
912
+ │ │ └── types.ts # ConfigNode, ProxyStore, ListState и др.
913
+ │ ├── buildProxy/
914
+ │ │ ├── buildProxy.ts # Proxy слой 1: GET/SET traps
915
+ │ │ ├── buildListProxy.ts # List proxy: items, add, remove, map…
916
+ │ │ └── buildEntityProjectionProxy.ts # Entity proxy через template
917
+ │ ├── compute/
918
+ │ │ └── recompute/ # recomputeLeaves, recomputeTargeted, topologicalSort
919
+ │ ├── writePipeline/ # formatter → storeValue → setter
920
+ │ ├── submitPipeline/ # beforeSubmit → validate → onSubmit → afterSubmit
921
+ │ ├── resetPipeline/ # Сброс к defaults
922
+ │ ├── onChangePipeline/ # onChange callback
923
+ │ ├── resolvePipeline/ # Async resolver: deps, retry, optimistic, suspense
924
+ │ ├── dirtyTracking/ # captureInitialValues, recomputeDirtyTargeted
925
+ │ ├── entityRegistry/ # Нормализованный реестр сущностей
926
+ │ ├── groupDeps/ # Карта зависимостей между группами
927
+ │ ├── traversal/ # isLeaf / isGroup / isListNode / walkFull
928
+ │ ├── valuesCache/ # buildValuesCache + O(1) updateValuesCacheEntry
929
+ │ ├── init/ # NotificationHub, ResolveManager, initGroupSubmitting
930
+ │ └── persist/
931
+ │ ├── persistManager.ts # enable / disable / flush
932
+ │ ├── drivers.ts # localStorageDriver, sessionStorageDriver
933
+ │ └── types.ts # PersistDriver, PersistOptions
934
+ └── react/
935
+ ├── useForm.ts # useSyncExternalStore + tracking proxy
936
+ ├── createTrackingProxy.ts # Proxy слой 2: запись accessed нод
937
+ ├── useTranslator.ts # Регистрация i18n-функции
938
+ ├── useNotifier.ts # Регистрация функции уведомлений
939
+ └── usePersist.ts # React-интеграция persist
940
+ ```
941
+
942
+ ---
943
+
944
+ ## Лицензия
945
+
946
+ MIT
947
+