@fozy-labs/rx-toolkit 0.5.3 → 0.6.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 (302) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +22 -13
  3. package/dist/common/devtools/reduxDevtools.js +17 -2
  4. package/dist/common/react/index.d.ts +1 -0
  5. package/dist/common/react/index.js +1 -0
  6. package/dist/common/react/useIsomorphicLayoutEffect.d.ts +17 -0
  7. package/dist/common/react/useIsomorphicLayoutEffect.js +17 -0
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.js +1 -2
  10. package/dist/query/api/createApi.d.ts +4 -0
  11. package/dist/query/api/createApi.js +9 -0
  12. package/dist/query/api/index.d.ts +1 -0
  13. package/dist/query/api/index.js +1 -0
  14. package/dist/query/constants.d.ts +12 -0
  15. package/dist/query/constants.js +15 -0
  16. package/dist/query/core/api/Api.d.ts +20 -0
  17. package/dist/query/core/api/Api.js +129 -0
  18. package/dist/query/core/api/constants.d.ts +2 -0
  19. package/dist/query/core/api/constants.js +3 -0
  20. package/dist/query/core/api/index.d.ts +4 -0
  21. package/dist/query/core/api/index.js +4 -0
  22. package/dist/query/core/api/mergeHooks.d.ts +2 -0
  23. package/dist/query/core/api/mergeHooks.js +26 -0
  24. package/dist/query/core/api/normalizeLinks.d.ts +2 -0
  25. package/dist/query/core/api/normalizeLinks.js +11 -0
  26. package/dist/query/core/cache/CacheEntry.d.ts +21 -0
  27. package/dist/query/core/cache/CacheEntry.js +54 -0
  28. package/dist/query/core/cache/CacheMap.d.ts +19 -0
  29. package/dist/query/core/cache/CacheMap.js +32 -0
  30. package/dist/query/core/cache/QueryCacheEntry.d.ts +21 -0
  31. package/dist/query/core/cache/QueryCacheEntry.js +136 -0
  32. package/dist/query/core/cache/index.d.ts +3 -0
  33. package/dist/query/core/cache/index.js +3 -0
  34. package/dist/query/core/command/Command.d.ts +67 -0
  35. package/dist/query/core/command/Command.js +253 -0
  36. package/dist/query/core/command/CommandAgent.d.ts +17 -0
  37. package/dist/query/core/command/CommandAgent.js +67 -0
  38. package/dist/query/core/command/LinkManager.d.ts +24 -0
  39. package/dist/query/core/command/LinkManager.js +71 -0
  40. package/dist/query/core/command/index.d.ts +2 -0
  41. package/dist/query/core/command/index.js +2 -0
  42. package/dist/query/core/errors/CacheEntryRemovedError.d.ts +7 -0
  43. package/dist/query/core/errors/CacheEntryRemovedError.js +9 -0
  44. package/dist/query/core/errors/MachineStateError.d.ts +8 -0
  45. package/dist/query/core/errors/MachineStateError.js +10 -0
  46. package/dist/query/core/errors/MachineTransitionError.d.ts +7 -0
  47. package/dist/query/core/errors/MachineTransitionError.js +9 -0
  48. package/dist/query/core/errors/index.d.ts +3 -0
  49. package/dist/query/core/errors/index.js +3 -0
  50. package/dist/query/core/index.d.ts +8 -0
  51. package/dist/query/core/index.js +8 -0
  52. package/dist/query/core/machine/Machine.d.ts +21 -0
  53. package/dist/query/core/machine/Machine.js +42 -0
  54. package/dist/query/core/machine/MachineBase.d.ts +31 -0
  55. package/dist/query/core/machine/MachineBase.js +176 -0
  56. package/dist/query/core/machine/MachineError.d.ts +10 -0
  57. package/dist/query/core/machine/MachineError.js +19 -0
  58. package/dist/query/core/machine/MachinePending.d.ts +13 -0
  59. package/dist/query/core/machine/MachinePending.js +32 -0
  60. package/dist/query/core/machine/MachineRefreshError.d.ts +12 -0
  61. package/dist/query/core/machine/MachineRefreshError.js +23 -0
  62. package/dist/query/core/machine/MachineRefreshing.d.ts +15 -0
  63. package/dist/query/core/machine/MachineRefreshing.js +43 -0
  64. package/dist/query/core/machine/MachineSuccess.d.ts +12 -0
  65. package/dist/query/core/machine/MachineSuccess.js +23 -0
  66. package/dist/query/core/machine/MachineWithData.d.ts +25 -0
  67. package/dist/query/core/machine/MachineWithData.js +73 -0
  68. package/dist/query/core/machine/index.d.ts +9 -0
  69. package/dist/query/core/machine/index.js +9 -0
  70. package/dist/query/core/machine/machine-helpers.d.ts +9 -0
  71. package/dist/query/core/machine/machine-helpers.js +80 -0
  72. package/dist/query/core/patcher/Patcher.d.ts +30 -0
  73. package/dist/query/core/patcher/Patcher.js +122 -0
  74. package/dist/query/core/patcher/index.d.ts +1 -0
  75. package/dist/query/core/patcher/index.js +1 -0
  76. package/dist/query/core/resource/Resource.d.ts +105 -0
  77. package/dist/query/core/resource/Resource.js +340 -0
  78. package/dist/query/core/resource/ResourceAgent.d.ts +37 -0
  79. package/dist/query/core/resource/ResourceAgent.js +179 -0
  80. package/dist/query/core/resource/index.d.ts +2 -0
  81. package/dist/query/core/resource/index.js +2 -0
  82. package/dist/query/core/snapshoter/Snapshoter.d.ts +22 -0
  83. package/dist/query/core/snapshoter/Snapshoter.js +78 -0
  84. package/dist/query/core/snapshoter/index.d.ts +2 -0
  85. package/dist/query/core/snapshoter/index.js +1 -0
  86. package/dist/query/core/syncer/Syncer.d.ts +32 -0
  87. package/dist/query/core/syncer/Syncer.js +85 -0
  88. package/dist/query/core/syncer/index.d.ts +2 -0
  89. package/dist/query/core/syncer/index.js +1 -0
  90. package/dist/query/index.d.ts +5 -10
  91. package/dist/query/index.js +5 -13
  92. package/dist/query/lib/broadcastSyncDriver.d.ts +5 -0
  93. package/dist/query/lib/broadcastSyncDriver.js +46 -0
  94. package/dist/query/lib/index.d.ts +3 -0
  95. package/dist/query/lib/index.js +3 -0
  96. package/dist/{query-v2 → query}/lib/stableStringify.js +5 -3
  97. package/dist/query/lib/toKeyed.d.ts +11 -0
  98. package/dist/query/lib/toKeyed.js +18 -0
  99. package/dist/query/react/ReactHooksPlugin.d.ts +31 -0
  100. package/dist/query/react/ReactHooksPlugin.js +21 -0
  101. package/dist/query/react/index.d.ts +3 -0
  102. package/dist/query/react/index.js +3 -0
  103. package/dist/query/react/useCommand.d.ts +2 -0
  104. package/dist/query/react/useCommand.js +14 -0
  105. package/dist/query/react/useResource.d.ts +2 -0
  106. package/dist/query/react/useResource.js +16 -0
  107. package/dist/query/types/api.d.ts +39 -0
  108. package/dist/query/types/cache.d.ts +51 -0
  109. package/dist/query/types/command.d.ts +52 -0
  110. package/dist/query/types/common.d.ts +65 -0
  111. package/dist/query/types/index.d.ts +8 -4
  112. package/dist/query/types/index.js +8 -5
  113. package/dist/query/types/plugin-hkt.d.ts +64 -0
  114. package/dist/query/types/resource.d.ts +49 -0
  115. package/dist/query/types/snapshot.d.ts +27 -0
  116. package/dist/query/types/snapshot.js +2 -0
  117. package/dist/query/types/state.d.ts +24 -0
  118. package/dist/signals/base/ComputeCache.js +1 -1
  119. package/dist/signals/base/Devtools.js +2 -6
  120. package/dist/signals/signals/Computed.d.ts +1 -0
  121. package/dist/signals/signals/Computed.js +5 -1
  122. package/dist/signals/signals/Effect.d.ts +0 -4
  123. package/dist/signals/signals/Effect.js +0 -6
  124. package/dist/signals/signals/LocalState.d.ts +1 -10
  125. package/dist/signals/signals/LocalState.js +0 -12
  126. package/dist/signals/signals/Signal.d.ts +2 -8
  127. package/dist/signals/signals/Signal.js +1 -10
  128. package/dist/signals/signals/State.d.ts +2 -1
  129. package/dist/signals/signals/State.js +9 -0
  130. package/dist/signals/types/SignalOptions.d.ts +0 -2
  131. package/dist/signals/types/normalizeSignalOptions.js +0 -3
  132. package/dist/signals/types/signals.types.d.ts +3 -1
  133. package/docs/CHANGELOG.md +61 -31
  134. package/docs/migrations/0.6.0.md +224 -0
  135. package/docs/query/README.md +52 -562
  136. package/docs/query/api/README.md +59 -0
  137. package/docs/query/api/_CacheEntry.md +39 -0
  138. package/docs/query/api/_CacheMap.md +30 -0
  139. package/docs/query/api/_QueryCacheEntry.md +81 -0
  140. package/docs/query/api/command-agent.md +60 -0
  141. package/docs/query/api/command.md +76 -0
  142. package/docs/query/api/resource-agent.md +68 -0
  143. package/docs/query/api/resource.md +77 -0
  144. package/docs/query/concepts/agent.md +70 -0
  145. package/docs/query/concepts/architecture.md +139 -0
  146. package/docs/query/concepts/cache.md +81 -0
  147. package/docs/query/concepts/dataflows.md +473 -0
  148. package/docs/query/concepts/keyed.md +42 -0
  149. package/docs/query/concepts/machine.md +106 -0
  150. package/docs/query/concepts/patching.md +85 -0
  151. package/docs/query/usage/broadcast.md +188 -0
  152. package/docs/query/usage/command.md +203 -0
  153. package/docs/query/usage/lifecycle.md +114 -0
  154. package/docs/query/usage/links.md +125 -0
  155. package/docs/query/usage/plugins.md +96 -0
  156. package/docs/query/usage/resource.md +206 -0
  157. package/docs/query/usage/snapshot.md +80 -0
  158. package/docs/usage/react/README.md +45 -91
  159. package/package.json +6 -9
  160. package/dist/query/SKIP_TOKEN.d.ts +0 -1
  161. package/dist/query/SKIP_TOKEN.js +0 -1
  162. package/dist/query/api/createCommand.d.ts +0 -21
  163. package/dist/query/api/createCommand.js +0 -20
  164. package/dist/query/api/createOperation.d.ts +0 -5
  165. package/dist/query/api/createOperation.js +0 -6
  166. package/dist/query/api/createResource.d.ts +0 -3
  167. package/dist/query/api/createResource.js +0 -2
  168. package/dist/query/api/createResourceDuplicator.d.ts +0 -4
  169. package/dist/query/api/createResourceDuplicator.js +0 -2
  170. package/dist/query/api/resetAllQueriesCache.d.ts +0 -1
  171. package/dist/query/api/resetAllQueriesCache.js +0 -4
  172. package/dist/query/core/Command/Command.d.ts +0 -35
  173. package/dist/query/core/Command/Command.js +0 -210
  174. package/dist/query/core/Command/CommandAgent.d.ts +0 -19
  175. package/dist/query/core/Command/CommandAgent.js +0 -54
  176. package/dist/query/core/Command/index.d.ts +0 -2
  177. package/dist/query/core/Command/index.js +0 -2
  178. package/dist/query/core/Operation/Operation.d.ts +0 -8
  179. package/dist/query/core/Operation/Operation.js +0 -4
  180. package/dist/query/core/Operation/OperationAgent.d.ts +0 -4
  181. package/dist/query/core/Operation/OperationAgent.js +0 -4
  182. package/dist/query/core/QueriesCache.d.ts +0 -9
  183. package/dist/query/core/QueriesCache.js +0 -28
  184. package/dist/query/core/QueriesLifetimeHooks.d.ts +0 -22
  185. package/dist/query/core/QueriesLifetimeHooks.js +0 -86
  186. package/dist/query/core/ResetAllQueriesSignal.d.ts +0 -6
  187. package/dist/query/core/ResetAllQueriesSignal.js +0 -11
  188. package/dist/query/core/Resource/Resource.d.ts +0 -51
  189. package/dist/query/core/Resource/Resource.js +0 -232
  190. package/dist/query/core/Resource/ResourceAgent.d.ts +0 -35
  191. package/dist/query/core/Resource/ResourceAgent.js +0 -110
  192. package/dist/query/core/Resource/ResourceDuplicator.d.ts +0 -73
  193. package/dist/query/core/Resource/ResourceDuplicator.js +0 -227
  194. package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +0 -35
  195. package/dist/query/core/Resource/ResourceDuplicatorAgent.js +0 -110
  196. package/dist/query/core/Resource/ResourceRef.d.ts +0 -16
  197. package/dist/query/core/Resource/ResourceRef.js +0 -136
  198. package/dist/query/lib/IndirectMap.d.ts +0 -19
  199. package/dist/query/lib/IndirectMap.js +0 -88
  200. package/dist/query/lib/ReactiveCache.d.ts +0 -62
  201. package/dist/query/lib/ReactiveCache.js +0 -80
  202. package/dist/query/react/useCommandAgent.d.ts +0 -24
  203. package/dist/query/react/useCommandAgent.js +0 -39
  204. package/dist/query/react/useOperationAgent.d.ts +0 -6
  205. package/dist/query/react/useOperationAgent.js +0 -6
  206. package/dist/query/react/useResourceAgent.d.ts +0 -6
  207. package/dist/query/react/useResourceAgent.js +0 -31
  208. package/dist/query/react/useResourceRef.d.ts +0 -5
  209. package/dist/query/react/useResourceRef.js +0 -13
  210. package/dist/query/types/Command.types.d.ts +0 -154
  211. package/dist/query/types/Command.types.js +0 -1
  212. package/dist/query/types/Operation.types.d.ts +0 -13
  213. package/dist/query/types/Operation.types.js +0 -1
  214. package/dist/query/types/Resource.types.d.ts +0 -129
  215. package/dist/query/types/Resource.types.js +0 -1
  216. package/dist/query/types/shared.types.d.ts +0 -26
  217. package/dist/query/types/shared.types.js +0 -1
  218. package/dist/query-v2/api/createApi.d.ts +0 -10
  219. package/dist/query-v2/api/createApi.js +0 -83
  220. package/dist/query-v2/core/common/CacheEntry.d.ts +0 -29
  221. package/dist/query-v2/core/common/CacheEntry.js +0 -71
  222. package/dist/query-v2/core/common/CacheMap.d.ts +0 -38
  223. package/dist/query-v2/core/common/CacheMap.js +0 -127
  224. package/dist/query-v2/core/common/LifecycleHooks.d.ts +0 -22
  225. package/dist/query-v2/core/common/LifecycleHooks.js +0 -104
  226. package/dist/query-v2/core/common/index.d.ts +0 -3
  227. package/dist/query-v2/core/common/index.js +0 -3
  228. package/dist/query-v2/core/index.d.ts +0 -3
  229. package/dist/query-v2/core/index.js +0 -3
  230. package/dist/query-v2/core/machines/Machine.d.ts +0 -14
  231. package/dist/query-v2/core/machines/Machine.js +0 -33
  232. package/dist/query-v2/core/machines/MachineError.d.ts +0 -11
  233. package/dist/query-v2/core/machines/MachineError.js +0 -26
  234. package/dist/query-v2/core/machines/MachineIdle.d.ts +0 -8
  235. package/dist/query-v2/core/machines/MachineIdle.js +0 -19
  236. package/dist/query-v2/core/machines/MachinePending.d.ts +0 -12
  237. package/dist/query-v2/core/machines/MachinePending.js +0 -29
  238. package/dist/query-v2/core/machines/MachineRefreshing.d.ts +0 -14
  239. package/dist/query-v2/core/machines/MachineRefreshing.js +0 -46
  240. package/dist/query-v2/core/machines/MachineSuccess.d.ts +0 -16
  241. package/dist/query-v2/core/machines/MachineSuccess.js +0 -42
  242. package/dist/query-v2/core/machines/MachineWithData.d.ts +0 -18
  243. package/dist/query-v2/core/machines/MachineWithData.js +0 -40
  244. package/dist/query-v2/core/machines/Patcher.d.ts +0 -20
  245. package/dist/query-v2/core/machines/Patcher.js +0 -104
  246. package/dist/query-v2/core/machines/index.d.ts +0 -8
  247. package/dist/query-v2/core/machines/index.js +0 -8
  248. package/dist/query-v2/core/resource/ResourceV2.d.ts +0 -120
  249. package/dist/query-v2/core/resource/ResourceV2.js +0 -464
  250. package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +0 -26
  251. package/dist/query-v2/core/resource/ResourceV2Agent.js +0 -132
  252. package/dist/query-v2/core/resource/index.d.ts +0 -2
  253. package/dist/query-v2/core/resource/index.js +0 -2
  254. package/dist/query-v2/index.d.ts +0 -11
  255. package/dist/query-v2/index.js +0 -17
  256. package/dist/query-v2/lib/NO_VALUE.d.ts +0 -2
  257. package/dist/query-v2/lib/NO_VALUE.js +0 -1
  258. package/dist/query-v2/lib/SKIP_TOKEN.d.ts +0 -2
  259. package/dist/query-v2/lib/SKIP_TOKEN.js +0 -1
  260. package/dist/query-v2/lib/index.d.ts +0 -4
  261. package/dist/query-v2/lib/index.js +0 -3
  262. package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +0 -25
  263. package/dist/query-v2/plugins/ReactHooksPlugin.js +0 -19
  264. package/dist/query-v2/plugins/types.d.ts +0 -1
  265. package/dist/query-v2/react/__tests__/helpers.d.ts +0 -12
  266. package/dist/query-v2/react/__tests__/helpers.js +0 -33
  267. package/dist/query-v2/react/index.d.ts +0 -2
  268. package/dist/query-v2/react/index.js +0 -2
  269. package/dist/query-v2/react/useResourceV2Agent.d.ts +0 -12
  270. package/dist/query-v2/react/useResourceV2Agent.js +0 -36
  271. package/dist/query-v2/react/useResourceV2Ref.d.ts +0 -12
  272. package/dist/query-v2/react/useResourceV2Ref.js +0 -57
  273. package/dist/query-v2/snapshot/Snapshot.d.ts +0 -13
  274. package/dist/query-v2/snapshot/Snapshot.js +0 -76
  275. package/dist/query-v2/types/agent.types.d.ts +0 -54
  276. package/dist/query-v2/types/api.types.d.ts +0 -22
  277. package/dist/query-v2/types/cache.types.d.ts +0 -37
  278. package/dist/query-v2/types/index.d.ts +0 -9
  279. package/dist/query-v2/types/index.js +0 -9
  280. package/dist/query-v2/types/lifecycle.types.d.ts +0 -25
  281. package/dist/query-v2/types/machine.types.d.ts +0 -67
  282. package/dist/query-v2/types/plugin.types.d.ts +0 -38
  283. package/dist/query-v2/types/resource.types.d.ts +0 -35
  284. package/dist/query-v2/types/resource.types.js +0 -1
  285. package/dist/query-v2/types/shared.types.d.ts +0 -20
  286. package/dist/query-v2/types/shared.types.js +0 -1
  287. package/dist/query-v2/types/snapshot.types.d.ts +0 -21
  288. package/dist/query-v2/types/snapshot.types.js +0 -1
  289. package/docs/contributing/query-v2/README.md +0 -379
  290. package/docs/migrations/query-v2.md +0 -171
  291. package/docs/query-v2/README.md +0 -280
  292. package/docs/query-v2/api-reference.md +0 -235
  293. package/docs/query-v2/optimistic-updates.md +0 -148
  294. package/docs/query-v2/ssr.md +0 -130
  295. /package/dist/{query-v2 → query}/lib/stableStringify.d.ts +0 -0
  296. /package/dist/{query-v2/plugins/types.js → query/types/api.js} +0 -0
  297. /package/dist/{query-v2/types/agent.types.js → query/types/cache.js} +0 -0
  298. /package/dist/{query-v2/types/api.types.js → query/types/command.js} +0 -0
  299. /package/dist/{query-v2/types/cache.types.js → query/types/common.js} +0 -0
  300. /package/dist/{query-v2/types/lifecycle.types.js → query/types/plugin-hkt.js} +0 -0
  301. /package/dist/{query-v2/types/machine.types.js → query/types/resource.js} +0 -0
  302. /package/dist/{query-v2/types/plugin.types.js → query/types/state.js} +0 -0
@@ -0,0 +1,473 @@
1
+ # Потоки данных
2
+
3
+ Диаграммы описывают основные сценарии взаимодействия компонентов модуля Query.
4
+
5
+
6
+ ---
7
+
8
+ ## Потоки ресурса (Resource)
9
+
10
+ > Разделы ниже описывают потоки, специфичные для ресурсов. Команды используют упрощённый поток — см. «Мутация».
11
+
12
+ ### Cache miss
13
+
14
+
15
+ ```mermaid
16
+ sequenceDiagram
17
+ participant UI as React-компонент
18
+ participant Hook as useResource
19
+ participant Agent as Agent
20
+ participant Res as Resource
21
+ participant Cache as CacheMap
22
+ participant Entry as QueryCacheEntry
23
+ participant Query as queryFn
24
+ participant BQ as beforeQuery
25
+ participant Sync as SyncDriver
26
+
27
+ UI->>Hook: useResource(args)
28
+ Hook->>Agent: set(args)
29
+
30
+ Note over Agent: Создание Signal.computed
31
+
32
+ Agent->>Res: getEntry$(keyedArgs, doInitiate=false)
33
+
34
+ Res->>Cache: get(key)
35
+ Cache-->>Res: null (нет записи)
36
+ Res-->>Agent: null
37
+ Agent-->>Hook: pending
38
+ Hook-->>UI: { status: pending }
39
+
40
+ Note over Hook: useIsomorphicLayoutEffect срабатывает
41
+
42
+ opt синхронно
43
+ Hook->>Agent: start()
44
+ Agent->>Res: trigger(keyedArgs, doForce=false)
45
+ Res-->>Res: _getOrCreate(keyedArgs, doForce=false)
46
+ Res->>Cache: get(key)
47
+ Cache-->>Res: null
48
+ Res->>Entry: new Entry(options)
49
+
50
+ opt beforeQuery настроен (sync: true)
51
+ Res->>BQ: beforeQuery(key, keyedArgs)
52
+ BQ->>Sync: REQ { keys, reqId }
53
+ Note over Sync: BroadcastChannel.postMessage
54
+ Sync-->>BQ: RES { data } или таймаут
55
+
56
+ alt данные получены
57
+ BQ-->>Entry: hydrate(data)
58
+ Entry->>Entry: → success (без сетевого запроса)
59
+ Entry-->>Agent: machine$ → success
60
+ Agent-->>Hook: success
61
+ Hook-->>UI: { status: success, data }
62
+ else таймаут
63
+ BQ-->>Res: null
64
+ Note over Res: queryFn вызывается далее
65
+ end
66
+ end
67
+
68
+ Entry->>Query: queryFn(args, abortSignal)
69
+ Query-->>Entry: Promise (pending)
70
+ Entry-->>Res: Entry (pending)
71
+
72
+ Res->>Cache: set(key, entry)
73
+
74
+ Cache-->>Res: Entry (pending)
75
+
76
+ opt Отработка реактивной зависимости (null → Entry)
77
+ Res -->> Res: lastEntry.set(Entry)
78
+ Res-->>Agent: $: Entry (pending)
79
+ Agent-->>Agent: Подписка на machine$ (pending)
80
+ Note over Agent: return stable(prev, next)
81
+ end
82
+
83
+ Res -->> Agent: void
84
+ Agent-->>Hook: void
85
+ end
86
+
87
+ Note over Query: Ожидание
88
+
89
+ alt ответ OK
90
+ Query-->>Entry: data
91
+ Entry->>Entry: → success
92
+ Entry-->>Agent: machine$ → success
93
+ Agent-->>Hook: success
94
+ Hook-->>UI: { status: success, data }
95
+ else ошибка
96
+ Query-->>Entry: error
97
+ Entry->>Entry: → error
98
+ Entry-->>Agent: machine$ → error
99
+ Agent-->>Hook: error
100
+ Hook-->>UI: { status: error, error }
101
+ end
102
+ ```
103
+
104
+ ### Cache hit
105
+
106
+
107
+ ```mermaid
108
+ sequenceDiagram
109
+ participant UI as React-компонент
110
+ participant Hook as useResource
111
+ participant Agent as Agent
112
+ participant Res as Resource
113
+ participant Cache as CacheMap
114
+
115
+ UI->>Hook: useResource(args)
116
+ Hook->>Agent: set(args)
117
+ Note over Agent: Создание Signal.computed
118
+ Agent->>Res: getEntry$(keyedArgs, doInitiate=false)
119
+ Res->>Cache: get(key)
120
+ Cache-->>Res: Entry
121
+ Res-->>Agent: Entry
122
+ Agent-->>Agent: Подписка на machine$
123
+ Agent-->>Hook: state
124
+ Hook-->>UI: state
125
+ ```
126
+
127
+ ### Условный запрос (SKIP → реальные args)
128
+
129
+
130
+ ```mermaid
131
+ sequenceDiagram
132
+ participant UI as React-компонент
133
+ participant Hook as useResource
134
+ participant Agent as Agent
135
+ participant Res as Resource
136
+
137
+ UI->>Hook: useResource(SKIP)
138
+ Hook->>Agent: set(SKIP)
139
+ Note over Agent: → idle (запись не создаётся)
140
+ Agent-->>Hook: idle
141
+ Hook-->>UI: { status: idle }
142
+
143
+ Note over UI: зависимые данные готовы
144
+
145
+ UI->>Hook: useResource(args)
146
+ Hook->>Agent: set(args)
147
+ Agent->>Res: getEntry$(keyedArgs, doInitiate=false)
148
+
149
+ Res-->>Agent: Entry или null
150
+
151
+ Note over Agent: → поток «Cache miss» или «Cache hit»
152
+ ```
153
+
154
+ ### Refresh / фоновое обновление
155
+
156
+ ```mermaid
157
+ sequenceDiagram
158
+ participant UI as React-компонент
159
+ participant Hook as useResource
160
+ participant Agent as Agent
161
+ participant Entry as QueryCacheEntry
162
+ participant Query as queryFn
163
+
164
+ Note over Entry: machine: success (data v1)
165
+
166
+ UI->>Hook: refresh()
167
+ Hook->>Agent: refresh()
168
+ Agent->>Entry: refresh()
169
+ Entry->>Entry: success → refreshing
170
+ Entry-->>Agent: machine$ → refreshing
171
+ Agent-->>Hook: refreshing
172
+ Hook-->>UI: { status: refreshing, data: v1 }
173
+
174
+ Entry->>Query: queryFn(args, abortSignal)
175
+
176
+ alt ответ OK
177
+ Query-->>Entry: data v2
178
+ Entry->>Entry: refreshing → success (rebase)
179
+ Entry-->>Agent: machine$ → success
180
+ Agent-->>Hook: success
181
+ Hook-->>UI: { status: success, data: v2 }
182
+ else ошибка
183
+ Query-->>Entry: error
184
+ Entry->>Entry: refreshing → refresh-error (fail)
185
+ Entry-->>Agent: machine$ → refresh-error
186
+ Agent-->>Hook: refresh-error
187
+ Hook-->>UI: { status: refresh-error, data: v1, error }
188
+ end
189
+ ```
190
+
191
+ ### SWR-fallback при смене аргументов
192
+
193
+
194
+ ```mermaid
195
+ sequenceDiagram
196
+ participant UI as React-компонент
197
+ participant Hook as useResource
198
+ participant Agent as Agent
199
+ participant Res as Resource
200
+ participant Entry2 as QueryCacheEntry (user/2)
201
+
202
+ Note over Agent: current = Entry1 (success, data/1)
203
+
204
+ UI->>Hook: useResource({ id: 2 })
205
+ Hook->>Agent: set({ id: 2 })
206
+ Agent->>Agent: prev = Entry1, current = null
207
+
208
+ Agent->>Res: getEntry$(keyedArgs, doInitiate=false)
209
+ Res-->>Agent: null
210
+
211
+ Note over Agent,Entry2: → поток «Cache miss» для { id: 2 }
212
+
213
+ Note over Agent: Реактивная зависимость: Entry2 (pending)
214
+ Agent-->>Agent: Подписка на machine$ (pending)
215
+
216
+ Note over Agent: pending + prev → refreshing (SWR)
217
+ Agent-->>Hook: refreshing
218
+ Hook-->>UI: { status: refreshing, data: data/1 }
219
+
220
+ alt ответ OK
221
+ Entry2->>Entry2: → success
222
+ Entry2-->>Agent: machine$ → success
223
+ Agent->>Agent: prev = null
224
+ Agent-->>Hook: success
225
+ Hook-->>UI: { status: success, data: data/2 }
226
+ else ошибка
227
+ Entry2->>Entry2: → error
228
+ Entry2-->>Agent: machine$ → error
229
+ Note over Agent: error не маскируется, prev (Entry1) сохраняется
230
+ Agent-->>Hook: error
231
+ Hook-->>UI: { status: error, data: data/1, error }
232
+ end
233
+ ```
234
+
235
+ ### Дедупликация параллельных запросов
236
+
237
+
238
+ ```mermaid
239
+ sequenceDiagram
240
+ participant Agent as Потребитель B (например Agent)
241
+ participant Res as Resource
242
+ participant Cache as CacheMap
243
+
244
+ Note over Res: Потребитель A уже прошёл «Cache miss»<br/>(см. одноимённый раздел выше)
245
+
246
+ Agent->>Res: trigger(keyedArgs, doForce=false)
247
+ Res->>Cache: get(key)
248
+ Cache-->>Res: existing Entry (pending)
249
+ Res-->>Agent: void
250
+ ```
251
+
252
+ ## Потоки команды (Command)
253
+
254
+ ### Мутация — базовый поток
255
+
256
+
257
+ ```mermaid
258
+ sequenceDiagram
259
+ participant UI as React-компонент
260
+ participant Hook as useCommand
261
+ participant Agent as Agent
262
+ participant Cmd as Command
263
+ participant Cache as CacheMap
264
+ participant Entry as QueryCacheEntry
265
+ participant Query as queryFn
266
+
267
+ UI->>Hook: cmd.useCommand()
268
+
269
+ Hook-->>UI: { status: idle }
270
+
271
+ UI->>Hook: trigger(args)
272
+ Hook->>Agent: trigger(args)
273
+ Agent->>Cmd: trigger(keyedArgs)
274
+ Cmd->>Cache: get(key)
275
+ Cache-->>Cmd: null
276
+ Cmd->>Entry: new Entry(options)
277
+ Entry->>Query: queryFn(args)
278
+ Query-->>Entry: Promise (pending)
279
+ Entry-->>Cmd: Entry (pending)
280
+ Cmd->>Cache: set(key, entry)
281
+ Cache-->>Cmd: void
282
+ Cmd-->>Cmd: lastEntry.set(Entry)
283
+ Cmd-->>Agent: Entry (pending)
284
+ Agent-->>Hook: pending
285
+ Hook-->>UI: { status: pending }
286
+
287
+ alt ответ OK
288
+ Query-->>Entry: data
289
+ Entry->>Entry: pending → success
290
+ Entry-->>Agent: machine$ → success
291
+ Agent-->>Hook: success
292
+ Hook-->>UI: { status: success, data }
293
+ else ошибка
294
+ Query-->>Entry: error
295
+ Entry->>Entry: pending → error
296
+ Entry-->>Agent: machine$ → error
297
+ Agent-->>Hook: error
298
+ Hook-->>UI: { status: error, error }
299
+ end
300
+ ```
301
+
302
+ ## Связи (Links)
303
+
304
+ ### Инвалидация через link после мутации
305
+
306
+
307
+ ```mermaid
308
+ sequenceDiagram
309
+ participant Cmd as Command
310
+ participant Lnk as Link
311
+ participant Res as Resource
312
+ participant Cache as CacheMap
313
+ participant Entry as QueryCacheEntry
314
+ participant Query as queryFn
315
+
316
+ Note over Lnk: invalidate: true
317
+
318
+ Note over Entry: machine: success (data v1)
319
+
320
+ Note over Cmd: Мутация (UI → Hook → Cmd) — см. «Мутация — базовый поток»
321
+ Note over Cmd: queryFn(args) завершился успешно
322
+
323
+
324
+ Cmd->>Lnk: Вызов onQueryStarted ($queryFulfilled) хука
325
+ Lnk->>Lnk: forwardArgs(args) → args
326
+ Lnk->>Res: refresh(args)
327
+ Res->>Cache: get(key)
328
+ Cache-->>Res: Entry
329
+ Res->>Entry: refresh()
330
+ Entry->>Entry: success → refreshing
331
+
332
+ Note over Entry: подписчики записи ресурса получат refreshing
333
+
334
+ Entry->>Query: queryFn(args, abortSignal)
335
+
336
+ alt ответ OK
337
+ Query-->>Entry: fresh data
338
+ Entry->>Entry: refreshing → success (rebase)
339
+ Note over Entry: подписчики записи ресурса получат success
340
+ else ошибка
341
+ Query-->>Entry: error
342
+ Entry->>Entry: refreshing → refresh-error (fail)
343
+ Note over Entry: подписчики записи ресурса получат refresh-error
344
+ end
345
+
346
+ Entry-->>Res: void
347
+ Res-->>Lnk: void
348
+ Lnk-->>Cmd: void
349
+ ```
350
+
351
+ ### Оптимистичное обновление через link
352
+
353
+
354
+ ```mermaid
355
+ sequenceDiagram
356
+ participant Cmd as Command
357
+ participant Lnk as Link
358
+ participant Res as Resource
359
+ participant Entry as QueryCacheEntry
360
+
361
+ Note over Cmd: trigger(args) — полный поток<br/>см. «Мутация — базовый поток»
362
+
363
+ Note over Lnk: optimisticUpdate: fn
364
+
365
+ Cmd->>Lnk: Вызов onQueryStarted хука
366
+ Lnk->>Lnk: forwardArgs(args) → args
367
+ Lnk->>Res: getEntry(args)
368
+ Res-->>Lnk: Entry
369
+ Lnk->>Entry: createPatch(patchFn)
370
+ Entry->>Entry: Immer produce → patches + inversePatches
371
+ Entry-->>Entry: machine$ → success (patched data)
372
+
373
+ alt ответ OK
374
+ Cmd->>Lnk: $queryFulfilled.resolve(data)
375
+ Lnk->>Entry: handle.commit()
376
+ Entry-->>Lnk: void
377
+
378
+ else ошибка
379
+ Cmd->>Lnk: onError(args, error)
380
+ Lnk->>Entry: handle.abort()
381
+ Entry->>Entry: inversePatches → rollback
382
+ Entry-->>Entry: machine$ → success (original data)
383
+ Note over Entry: Возможен isConsistencyViolation →<br/>автоинвалидация (см. патчинг)
384
+ Entry-->>Lnk: void
385
+ end
386
+
387
+ Lnk-->>Cmd: void
388
+ ```
389
+
390
+ ---
391
+
392
+
393
+ ## Кросс-табовая синхронизация
394
+
395
+ > Синхронизация построена на PULL-модели: вкладка, которой нужны данные, запрашивает их у других вкладок через `beforeQuery` хук и `BroadcastChannel`. Вкладки **не** рассылают данные проактивно после успешного запроса.
396
+
397
+ ```mermaid
398
+ sequenceDiagram
399
+ participant UI as React-компонент
400
+ participant Hook as useResource
401
+ participant Agent as Agent
402
+ participant Res as Resource
403
+ participant Entry as QueryCacheEntry
404
+ participant BQ as beforeQuery
405
+ participant Sync as SyncDriver
406
+ participant Sync2 as SyncDriver (отвечающий)
407
+ participant Cache2 as CacheMap
408
+ participant Query as queryFn
409
+
410
+ Note over UI, Sync: Tab B — запрашивающая вкладка
411
+ Note over Sync2, Cache2: Tab A — вкладка с данными (success)
412
+
413
+ Note over Res: Cache miss — создание новой записи<br/>(подробнее см. «Cache miss»)
414
+ Res->>Entry: new Entry(options)
415
+
416
+ opt beforeQuery настроен (sync: true)
417
+ Res->>BQ: beforeQuery(key, keyedArgs)
418
+ BQ->>Sync: REQ { keys, reqId }
419
+ Note over Sync: BroadcastChannel.postMessage
420
+ Sync-->>Sync2: ISyncMessage { type: "REQ", reqId, keys }
421
+
422
+ alt данные получены
423
+ Sync2->>Cache2: get(key)
424
+ Cache2-->>Sync2: Entry (success, data)
425
+ Sync2-->>Sync: ISyncMessage { type: "RES", reqId, data }
426
+ Sync-->>BQ: RES { data }
427
+ BQ-->>Entry: hydrate(data)
428
+ Entry->>Entry: → success (queryFn не вызывается)
429
+ Note over Entry: Мгновенный кэш-хит —<br/>рендер без сетевого запроса
430
+ Entry-->>Agent: machine$ → success
431
+ Agent-->>Hook: success
432
+ Hook-->>UI: { status: success, data }
433
+ else таймаут
434
+ Note over Sync2: Нет данных / нет других вкладок → нет ответа
435
+ Note over BQ: Таймаут — RES не получен
436
+ BQ-->>Res: null
437
+ Note over Res: queryFn вызывается далее
438
+ end
439
+ end
440
+
441
+ Entry->>Query: queryFn(args, abortSignal)
442
+ Note over Query: Сетевой запрос
443
+
444
+ alt ответ OK
445
+ Query-->>Entry: data
446
+ Entry->>Entry: → success
447
+ Entry-->>Agent: machine$ → success
448
+ Agent-->>Hook: success
449
+ Hook-->>UI: { status: success, data }
450
+ else ошибка
451
+ Query-->>Entry: error
452
+ Entry->>Entry: → error
453
+ Entry-->>Agent: machine$ → error
454
+ Agent-->>Hook: error
455
+ Hook-->>UI: { status: error, error }
456
+ end
457
+ ```
458
+
459
+
460
+ ## См. также
461
+
462
+ - [Машина состояний запроса][machine] — статусы и переходы, на которых построены все потоки
463
+ - [Система кэширования][cache] — жизненный цикл записей и `retentionTime`
464
+ - [Оптимистичные обновления (links)][usage-links] — `optimisticUpdate` и `invalidate` в действии
465
+ - [Агент][agent] — SWR-наблюдатель, транслирующий состояние машины в UI
466
+ - [Кросс-табовая синхронизация][usage-broadcast] — настройка `syncDriver` и `broadcastSyncDriver`
467
+
468
+
469
+ [agent]: agent.md
470
+ [machine]: machine.md
471
+ [cache]: cache.md
472
+ [usage-links]: ../usage/links.md
473
+ [usage-broadcast]: ../usage/broadcast.md
@@ -0,0 +1,42 @@
1
+ # Типизация аргументов (Keyed)
2
+
3
+ Все методы ресурсов и команд, принимающие аргументы, работают с типом `Args<TArgs>` — объединением сырых аргументов и обёрнутых в `Keyed`.
4
+
5
+
6
+ ## Типы
7
+
8
+ ```ts
9
+ type Args<TArgs> = TArgs | Keyed<TArgs>;
10
+
11
+ type Keyed<T> = { value: T; key: string };
12
+ ```
13
+
14
+ - **`Keyed<T>`** — аргументы, обёрнутые с предвычисленным ключом кэша. Пара `{ value, key }`, где `key` — результат сериализации.
15
+ - **`Args<TArgs>`** — объединённый тип: сырые аргументы или `Keyed`. Все публичные методы (`trigger`, `refresh`, `getEntry`, `getEntry$`) принимают `Args<TArgs>`.
16
+
17
+
18
+ ## Пайплайн аргументов
19
+
20
+ ```
21
+ args (UI / хук) → keyedArgs (Keyed<TArgs>) → key (string)
22
+ ```
23
+
24
+ 1. **args** — сырые аргументы, переданные пользователем.
25
+ 2. **keyedArgs** — обёртка `{ value: args, key }`, где `key` вычислен через `serializeArgs`.
26
+ 3. **key** — строковый ключ кэша, используемый в `CacheMap`.
27
+
28
+ Метод `toKeyed(args)` на ресурсе выполняет шаг 1 → 2.
29
+ Передача `Keyed<TArgs>` напрямую позволяет избежать повторной сериализации.
30
+
31
+
32
+ ## См. также
33
+
34
+ - [Ресурс — API][api-res] — методы ресурса, принимающие `Args<TArgs>`
35
+ - [Команда — API][api-cmd] — методы команды
36
+ - [Архитектура][architecture] — общая диаграмма компонентов
37
+
38
+ ---
39
+
40
+ [api-res]: ../api/resource.md
41
+ [api-cmd]: ../api/command.md
42
+ [architecture]: architecture.md
@@ -0,0 +1,106 @@
1
+ # Машина состояний запроса
2
+
3
+ Каждый запрос представлен **иммутабельной машиной состояний**. Машина хранит статус, данные, ошибку и метаданные. Любой переход создаёт **новый** экземпляр — старый не мутируется.
4
+
5
+ ## Пять состояний
6
+
7
+ | Статус | Данные | Ошибка | `updatedAt` |
8
+ |---|---|---|---|
9
+ | `pending` | `null` | `null` | `null` |
10
+ | `success` | `TData` | `null` | `number` |
11
+ | `error` | `null` | `unknown` | `null` |
12
+ | `refreshing` | `TData` (устаревшие) | `null` | `number` |
13
+ | `refresh-error` | `TData` (устаревшие) | `unknown` | `number` |
14
+
15
+
16
+ ## Диаграмма переходов
17
+
18
+ ```mermaid
19
+ stateDiagram-v2
20
+ pending --> success : success(data)
21
+
22
+ [*] --> pending : Machine.pending(args)
23
+ [*] --> success : Machine.fromSnapshot(state)
24
+ [*] --> refreshing : Machine.fromSnapshot(state) | Запись устарела
25
+
26
+ state "refresh-error" as refresh_error
27
+
28
+ pending --> error : fail(error)
29
+
30
+ success --> refreshing : refresh()
31
+ success --> success : createPatch() / finishPatch() / finishAllPatches()
32
+
33
+ error --> pending : retry()
34
+
35
+ refreshing --> success : rebase(data)
36
+ refreshing --> refresh_error : fail(error)
37
+ refreshing --> refreshing : createPatch() / finishPatch() / finishAllPatches()
38
+
39
+ refresh_error --> refreshing : refresh()
40
+ refresh_error --> refresh_error : createPatch() / finishPatch() / finishAllPatches()
41
+ ```
42
+
43
+ ## Модель данных
44
+
45
+ ```ts
46
+ interface TPendingState<TArgs> {
47
+ status: 'pending';
48
+ args: TArgs;
49
+ data: null;
50
+ error: null;
51
+ updatedAt: null;
52
+ }
53
+
54
+ interface TSuccessState<TArgs, TData> {
55
+ status: 'success';
56
+ args: TArgs;
57
+ data: TData;
58
+ error: null;
59
+ updatedAt: number;
60
+ patchState: TPatchState<TData> | null;
61
+ }
62
+
63
+ interface TErrorState<TArgs> {
64
+ status: 'error';
65
+ args: TArgs;
66
+ data: null;
67
+ error: unknown;
68
+ updatedAt: null;
69
+ }
70
+
71
+ interface TRefreshingState<TArgs, TData> {
72
+ status: 'refreshing';
73
+ args: TArgs;
74
+ data: TData;
75
+ error: null;
76
+ updatedAt: number;
77
+ patchState: TPatchState<TData> | null;
78
+ }
79
+
80
+ interface TRefreshErrorState<TArgs, TData> {
81
+ status: 'refresh-error';
82
+ args: TArgs;
83
+ data: TData;
84
+ error: unknown;
85
+ updatedAt: number;
86
+ patchState: TPatchState<TData> | null;
87
+ }
88
+ ```
89
+
90
+ ## См. также
91
+
92
+ - [Кэш][cache] — хранит записи, каждая из которых содержит экземпляр машины.
93
+ - [Агент][agent] — наблюдает за записью кэша и транслирует состояние машины в UI.
94
+ - [Ресурс][usage-res] — использует машину для отслеживания состояния чтения данных.
95
+ - [Команда][usage-cmd] — использует машину для отслеживания состояния мутации.
96
+ - [Потоки данных][dataflows] — как машина участвует в потоках данных.
97
+ - [Патчинг][patching] — оптимистичные обновления через `createPatch` / `finishPatch`.
98
+
99
+ ---
100
+
101
+ [cache]: cache.md
102
+ [agent]: agent.md
103
+ [usage-res]: ../usage/resource.md
104
+ [usage-cmd]: ../usage/command.md
105
+ [dataflows]: dataflows.md
106
+ [patching]: patching.md