@fozy-labs/rx-toolkit 0.5.4 → 0.6.2

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 (303) 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 +3 -0
  21. package/dist/query/core/api/index.js +3 -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 +54 -2
  134. package/docs/contributing/release/README.md +2 -8
  135. package/docs/migrations/0.6.0.md +224 -0
  136. package/docs/query/README.md +52 -562
  137. package/docs/query/api/README.md +59 -0
  138. package/docs/query/api/_CacheEntry.md +39 -0
  139. package/docs/query/api/_CacheMap.md +30 -0
  140. package/docs/query/api/_QueryCacheEntry.md +81 -0
  141. package/docs/query/api/command-agent.md +60 -0
  142. package/docs/query/api/command.md +76 -0
  143. package/docs/query/api/resource-agent.md +68 -0
  144. package/docs/query/api/resource.md +77 -0
  145. package/docs/query/concepts/agent.md +70 -0
  146. package/docs/query/concepts/architecture.md +139 -0
  147. package/docs/query/concepts/cache.md +81 -0
  148. package/docs/query/concepts/dataflows.md +473 -0
  149. package/docs/query/concepts/keyed.md +42 -0
  150. package/docs/query/concepts/machine.md +106 -0
  151. package/docs/query/concepts/patching.md +85 -0
  152. package/docs/query/usage/broadcast.md +188 -0
  153. package/docs/query/usage/command.md +203 -0
  154. package/docs/query/usage/lifecycle.md +114 -0
  155. package/docs/query/usage/links.md +125 -0
  156. package/docs/query/usage/plugins.md +96 -0
  157. package/docs/query/usage/resource.md +206 -0
  158. package/docs/query/usage/snapshot.md +80 -0
  159. package/docs/usage/react/README.md +45 -91
  160. package/package.json +5 -7
  161. package/dist/query/SKIP_TOKEN.d.ts +0 -1
  162. package/dist/query/SKIP_TOKEN.js +0 -1
  163. package/dist/query/api/createCommand.d.ts +0 -21
  164. package/dist/query/api/createCommand.js +0 -20
  165. package/dist/query/api/createOperation.d.ts +0 -5
  166. package/dist/query/api/createOperation.js +0 -6
  167. package/dist/query/api/createResource.d.ts +0 -3
  168. package/dist/query/api/createResource.js +0 -2
  169. package/dist/query/api/createResourceDuplicator.d.ts +0 -4
  170. package/dist/query/api/createResourceDuplicator.js +0 -2
  171. package/dist/query/api/resetAllQueriesCache.d.ts +0 -1
  172. package/dist/query/api/resetAllQueriesCache.js +0 -4
  173. package/dist/query/core/Command/Command.d.ts +0 -35
  174. package/dist/query/core/Command/Command.js +0 -210
  175. package/dist/query/core/Command/CommandAgent.d.ts +0 -19
  176. package/dist/query/core/Command/CommandAgent.js +0 -54
  177. package/dist/query/core/Command/index.d.ts +0 -2
  178. package/dist/query/core/Command/index.js +0 -2
  179. package/dist/query/core/Operation/Operation.d.ts +0 -8
  180. package/dist/query/core/Operation/Operation.js +0 -4
  181. package/dist/query/core/Operation/OperationAgent.d.ts +0 -4
  182. package/dist/query/core/Operation/OperationAgent.js +0 -4
  183. package/dist/query/core/QueriesCache.d.ts +0 -9
  184. package/dist/query/core/QueriesCache.js +0 -28
  185. package/dist/query/core/QueriesLifetimeHooks.d.ts +0 -22
  186. package/dist/query/core/QueriesLifetimeHooks.js +0 -86
  187. package/dist/query/core/ResetAllQueriesSignal.d.ts +0 -6
  188. package/dist/query/core/ResetAllQueriesSignal.js +0 -11
  189. package/dist/query/core/Resource/Resource.d.ts +0 -51
  190. package/dist/query/core/Resource/Resource.js +0 -232
  191. package/dist/query/core/Resource/ResourceAgent.d.ts +0 -35
  192. package/dist/query/core/Resource/ResourceAgent.js +0 -110
  193. package/dist/query/core/Resource/ResourceDuplicator.d.ts +0 -73
  194. package/dist/query/core/Resource/ResourceDuplicator.js +0 -227
  195. package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +0 -35
  196. package/dist/query/core/Resource/ResourceDuplicatorAgent.js +0 -110
  197. package/dist/query/core/Resource/ResourceRef.d.ts +0 -16
  198. package/dist/query/core/Resource/ResourceRef.js +0 -136
  199. package/dist/query/lib/IndirectMap.d.ts +0 -19
  200. package/dist/query/lib/IndirectMap.js +0 -88
  201. package/dist/query/lib/ReactiveCache.d.ts +0 -62
  202. package/dist/query/lib/ReactiveCache.js +0 -80
  203. package/dist/query/react/useCommandAgent.d.ts +0 -24
  204. package/dist/query/react/useCommandAgent.js +0 -39
  205. package/dist/query/react/useOperationAgent.d.ts +0 -6
  206. package/dist/query/react/useOperationAgent.js +0 -6
  207. package/dist/query/react/useResourceAgent.d.ts +0 -6
  208. package/dist/query/react/useResourceAgent.js +0 -31
  209. package/dist/query/react/useResourceRef.d.ts +0 -5
  210. package/dist/query/react/useResourceRef.js +0 -13
  211. package/dist/query/types/Command.types.d.ts +0 -154
  212. package/dist/query/types/Command.types.js +0 -1
  213. package/dist/query/types/Operation.types.d.ts +0 -13
  214. package/dist/query/types/Operation.types.js +0 -1
  215. package/dist/query/types/Resource.types.d.ts +0 -129
  216. package/dist/query/types/Resource.types.js +0 -1
  217. package/dist/query/types/shared.types.d.ts +0 -26
  218. package/dist/query/types/shared.types.js +0 -1
  219. package/dist/query-v2/api/createApi.d.ts +0 -10
  220. package/dist/query-v2/api/createApi.js +0 -83
  221. package/dist/query-v2/core/common/CacheEntry.d.ts +0 -29
  222. package/dist/query-v2/core/common/CacheEntry.js +0 -71
  223. package/dist/query-v2/core/common/CacheMap.d.ts +0 -38
  224. package/dist/query-v2/core/common/CacheMap.js +0 -127
  225. package/dist/query-v2/core/common/LifecycleHooks.d.ts +0 -22
  226. package/dist/query-v2/core/common/LifecycleHooks.js +0 -104
  227. package/dist/query-v2/core/common/index.d.ts +0 -3
  228. package/dist/query-v2/core/common/index.js +0 -3
  229. package/dist/query-v2/core/index.d.ts +0 -3
  230. package/dist/query-v2/core/index.js +0 -3
  231. package/dist/query-v2/core/machines/Machine.d.ts +0 -14
  232. package/dist/query-v2/core/machines/Machine.js +0 -33
  233. package/dist/query-v2/core/machines/MachineError.d.ts +0 -11
  234. package/dist/query-v2/core/machines/MachineError.js +0 -26
  235. package/dist/query-v2/core/machines/MachineIdle.d.ts +0 -8
  236. package/dist/query-v2/core/machines/MachineIdle.js +0 -19
  237. package/dist/query-v2/core/machines/MachinePending.d.ts +0 -12
  238. package/dist/query-v2/core/machines/MachinePending.js +0 -29
  239. package/dist/query-v2/core/machines/MachineRefreshing.d.ts +0 -14
  240. package/dist/query-v2/core/machines/MachineRefreshing.js +0 -46
  241. package/dist/query-v2/core/machines/MachineSuccess.d.ts +0 -16
  242. package/dist/query-v2/core/machines/MachineSuccess.js +0 -42
  243. package/dist/query-v2/core/machines/MachineWithData.d.ts +0 -18
  244. package/dist/query-v2/core/machines/MachineWithData.js +0 -40
  245. package/dist/query-v2/core/machines/Patcher.d.ts +0 -20
  246. package/dist/query-v2/core/machines/Patcher.js +0 -104
  247. package/dist/query-v2/core/machines/index.d.ts +0 -8
  248. package/dist/query-v2/core/machines/index.js +0 -8
  249. package/dist/query-v2/core/resource/ResourceV2.d.ts +0 -120
  250. package/dist/query-v2/core/resource/ResourceV2.js +0 -464
  251. package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +0 -26
  252. package/dist/query-v2/core/resource/ResourceV2Agent.js +0 -132
  253. package/dist/query-v2/core/resource/index.d.ts +0 -2
  254. package/dist/query-v2/core/resource/index.js +0 -2
  255. package/dist/query-v2/index.d.ts +0 -11
  256. package/dist/query-v2/index.js +0 -17
  257. package/dist/query-v2/lib/NO_VALUE.d.ts +0 -2
  258. package/dist/query-v2/lib/NO_VALUE.js +0 -1
  259. package/dist/query-v2/lib/SKIP_TOKEN.d.ts +0 -2
  260. package/dist/query-v2/lib/SKIP_TOKEN.js +0 -1
  261. package/dist/query-v2/lib/index.d.ts +0 -4
  262. package/dist/query-v2/lib/index.js +0 -3
  263. package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +0 -25
  264. package/dist/query-v2/plugins/ReactHooksPlugin.js +0 -19
  265. package/dist/query-v2/plugins/types.d.ts +0 -1
  266. package/dist/query-v2/react/__tests__/helpers.d.ts +0 -12
  267. package/dist/query-v2/react/__tests__/helpers.js +0 -33
  268. package/dist/query-v2/react/index.d.ts +0 -2
  269. package/dist/query-v2/react/index.js +0 -2
  270. package/dist/query-v2/react/useResourceV2Agent.d.ts +0 -12
  271. package/dist/query-v2/react/useResourceV2Agent.js +0 -36
  272. package/dist/query-v2/react/useResourceV2Ref.d.ts +0 -12
  273. package/dist/query-v2/react/useResourceV2Ref.js +0 -57
  274. package/dist/query-v2/snapshot/Snapshot.d.ts +0 -13
  275. package/dist/query-v2/snapshot/Snapshot.js +0 -76
  276. package/dist/query-v2/types/agent.types.d.ts +0 -54
  277. package/dist/query-v2/types/api.types.d.ts +0 -22
  278. package/dist/query-v2/types/cache.types.d.ts +0 -37
  279. package/dist/query-v2/types/index.d.ts +0 -9
  280. package/dist/query-v2/types/index.js +0 -9
  281. package/dist/query-v2/types/lifecycle.types.d.ts +0 -25
  282. package/dist/query-v2/types/machine.types.d.ts +0 -67
  283. package/dist/query-v2/types/plugin.types.d.ts +0 -38
  284. package/dist/query-v2/types/resource.types.d.ts +0 -35
  285. package/dist/query-v2/types/resource.types.js +0 -1
  286. package/dist/query-v2/types/shared.types.d.ts +0 -20
  287. package/dist/query-v2/types/shared.types.js +0 -1
  288. package/dist/query-v2/types/snapshot.types.d.ts +0 -21
  289. package/dist/query-v2/types/snapshot.types.js +0 -1
  290. package/docs/contributing/query-v2/README.md +0 -379
  291. package/docs/migrations/query-v2.md +0 -171
  292. package/docs/query-v2/README.md +0 -280
  293. package/docs/query-v2/api-reference.md +0 -235
  294. package/docs/query-v2/optimistic-updates.md +0 -148
  295. package/docs/query-v2/ssr.md +0 -130
  296. /package/dist/{query-v2 → query}/lib/stableStringify.d.ts +0 -0
  297. /package/dist/{query-v2/plugins/types.js → query/types/api.js} +0 -0
  298. /package/dist/{query-v2/types/agent.types.js → query/types/cache.js} +0 -0
  299. /package/dist/{query-v2/types/api.types.js → query/types/command.js} +0 -0
  300. /package/dist/{query-v2/types/cache.types.js → query/types/common.js} +0 -0
  301. /package/dist/{query-v2/types/lifecycle.types.js → query/types/plugin-hkt.js} +0 -0
  302. /package/dist/{query-v2/types/machine.types.js → query/types/resource.js} +0 -0
  303. /package/dist/{query-v2/types/plugin.types.js → query/types/state.js} +0 -0
@@ -1,575 +1,65 @@
1
- # RxQuery
1
+ # Модуль Query
2
2
 
3
- > **Note:** Экспериментальная версия Query v2 доступнасм. [Query v2](../query-v2/README.md).
3
+ Модуль Query декларативное управление серверными данными: кеширование, инвалидация, оптимистичные обновления и SSR. Построен на RxJS и [сигналах][signals], не зависит от UI-фреймворка React-интеграция подключается плагином. Два базовых примитива: [ресурс][resource] (чтение данных с кешем по аргументам) и [команда][command] (мутация / побочное действие).
4
4
 
5
- RxQuery — система для управления асинхронными запросами и кэшированием данных в RxToolkit. Она состоит из двух основных компонентов: **Resources** и **Commands**.
6
5
 
7
- ## Основные концепции
8
-
9
- ### Resources (Ресурсы)
10
-
11
- Resources предназначены для реактивного кэширования повторяемых запросов. Они автоматически управляют состоянием загрузки, кэшируют результаты и обеспечивают эффективную инвалидацию данных.
12
-
13
- **Ключевые особенности:**
14
- - Автоматическое кэширование по аргументам запроса
15
- - Поддержка AbortController для отмены запросов
16
- - Реактивные обновления состояния
17
- - Оптимистичные обновления
18
- - Гибкое управление временем жизни кэша
19
-
20
- ### Commands (Команды)
21
-
22
- Commands представляют одноразовые команды или мутации. Они не кэшируются, но предоставляют состояние выполнения и могут связываться с ресурсами для их обновления.
23
-
24
- **Ключевые особенности:**
25
- - Отслеживание состояния выполнения
26
- - Связывание с ресурсами для их обновления
27
- - Поддержка оптимистичных обновлений
28
- - Возможность блокировки связанных ресурсов
29
- - Автоматический откат при ошибках
30
-
31
- ### Agents (Агенты)
32
-
33
- Agents представляют собой интеллектуальные обертки над ресурсами (или командами), которые обеспечивают более удобную работу с состояниями запросов для потребителей.
34
-
35
- **Основная проблема, которую решают агенты:**
36
-
37
- Кэш ресурсов содержит "сырые" состояния отдельных запросов, но потребителям нужна более высокоуровневая логика:
38
- - `isInitialLoading` должно быть true только при первой загрузке ресурса
39
- - При смене аргументов запроса нужно показывать данные предыдущего запроса, пока загружается новый
40
- - Состояние загрузки должно отражать контекст использования, а не просто состояние кэша
41
-
42
- ### ResourceRef (Ссылка на ресурс)
43
-
44
- Ref — это абстракция для взаимодействия с элементом кэша ресурса напрямую.
45
-
46
- **Особенности:**
47
- - Команды используют ref под капотом для управления связанным ресурсом
48
- - Ref может ссылаться на отсутствующий элемент кэша
49
- - Позволяет выполнять patch-транзакции для оптимистичных обновлений
50
-
51
- ---
52
-
53
- ## API
54
-
55
- ### createResource
56
-
57
- Создает новый ресурс для кэширования данных.
58
-
59
- ```typescript
60
- import { createResource } from '@fozy-labs/rx-toolkit';
61
-
62
- interface User {
63
- id: string;
64
- name: string;
65
- email: string;
66
- }
67
-
68
- const userResource = createResource<{ id: string }, User>({
69
- async queryFn(args, tools) {
70
- const response = await fetch(`/api/users/${args.id}`, {
71
- signal: tools.abortSignal // Поддержка отмены запроса
72
- });
73
- return response.json();
74
- },
75
-
76
- // Опционально: трансформация данных
77
- select: (data) => ({
78
- id: data.id,
79
- name: data.name,
80
- email: data.email
81
- }),
82
-
83
- // Опционально: время жизни кэша (по умолчанию 60 секунд)
84
- cacheLifetime: 30000, // 30 секунд
85
-
86
- // Опционально: имя для devtools
87
- devtoolsName: 'user-resource',
88
-
89
- // Опционально: кастомное сравнение аргументов
90
- compareArgsFn: (args1, args2) => args1.id === args2.id,
91
- });
92
- ```
93
-
94
- **Параметры createResource:**
95
-
96
- | Параметр | Тип | Описание |
97
- |----------|-----|----------|
98
- | `queryFn` | `(args, tools) => Promise<Result>` | Функция выполнения запроса |
99
- | `select` | `(data) => Selected` | Опциональная функция трансформации данных |
100
- | `cacheLifetime` | `number \| false` | Время жизни кэша в мс (default: 60000). `false` — кэш не удаляется |
101
- | `compareArgsFn` | `(args1, args2) => boolean` | Кастомная функция сравнения аргументов |
102
- | `onCacheEntryAdded` | `(args, tools) => void` | Хук при добавлении элемента в кэш |
103
- | `onQueryStarted` | `(args, tools) => void` | Хук при старте запроса |
104
- | `devtoolsName` | `string \| false` | Имя для devtools (`false` — отключить) |
105
-
106
- **Tools в queryFn:**
107
- - `abortSignal` — AbortSignal для отмены запроса
108
-
109
- ### createCommand
110
-
111
- Создает новую команду для выполнения мутаций.
112
-
113
- ```typescript
114
- import { createCommand } from '@fozy-labs/rx-toolkit';
115
-
116
- const updateUser = createCommand<
117
- { id: string; data: Partial<User> },
118
- User
119
- >({
120
- async queryFn(args) {
121
- const response = await fetch(`/api/users/${args.id}`, {
122
- method: 'PATCH',
123
- headers: { 'Content-Type': 'application/json' },
124
- body: JSON.stringify(args.data)
125
- });
126
- return response.json();
127
- },
128
-
129
- // Связывание с ресурсами
130
- link(add) {
131
- add({
132
- resource: userResource,
133
- forwardArgs: (args) => ({ id: args.id }),
134
- // Обновление кэша после успешного запроса
135
- update({ draft, args, data }) {
136
- Object.assign(draft, args.data);
137
- },
138
- });
139
- },
140
-
141
- devtoolsName: 'update-user',
142
- });
143
- ```
144
-
145
- **Параметры createCommand:**
146
-
147
- | Параметр | Тип | Описание |
148
- |---------------------|-----------------------------|-----------------------------------------------|
149
- | `queryFn` | `(args) => Promise<Result>` | Функция выполнения команды |
150
- | `select` | `(data) => Selected` | Опциональная функция трансформации результата |
151
- | `link` | `(add) => void` | Функция связывания с ресурсами |
152
- | `cacheLifetime` | `number \| false` | Время жизни кэша команды (default: 1000) |
153
- | `onCacheEntryAdded` | `(args, tools) => void` | Хук при добавлении в кэш |
154
- | `onQueryStarted` | `(args, tools) => void` | Хук при старте команды |
155
- | `devtoolsName` | `string \| false` | Имя для devtools |
156
-
157
- > **Note:** `createOperation` and `useOperationAgent` are deprecated aliases for `createCommand` and `useCommandAgent` respectively. They will be removed in v0.6.0.
158
-
159
- ---
160
-
161
- ## Свойства Link
162
-
163
- Link позволяет связывать команды с ресурсами для автоматического обновления кэша:
6
+ ## Быстрый старт
164
7
 
165
8
  ```typescript
166
- type LinkOptions<D, RD> = {
167
- /**
168
- * Целевой ресурс, с которым связывается команда
169
- * @required
170
- */
171
- resource: ResourceInstance<RD>;
172
-
173
- /**
174
- * Функция для получения аргументов ресурса из аргументов команды.
175
- * Используется для определения какой элемент в кэше нужно обновить
176
- * @required
177
- */
178
- forwardArgs: (args: D["Args"]) => RD["Args"];
179
-
180
- /**
181
- * Инвалидация кэша после выполнения команды.
182
- * При true — кэш будет очищен и ресурс перезагрузится
183
- * @default false
184
- */
185
- invalidate?: boolean;
9
+ import { createApi, reactHooksPlugin } from '@fozy-labs/rx-toolkit';
186
10
 
187
- /**
188
- * Блокировка ресурса во время выполнения команды.
189
- * При true — ресурс не сможет выполнять новые запросы
190
- * @default false
191
- */
192
- lock?: boolean;
11
+ const api = createApi({ plugins: [reactHooksPlugin()] });
193
12
 
194
- /**
195
- * Обновление кэша ПОСЛЕ успешного выполнения команды.
196
- * Использует Immer для иммутабельных обновлений
197
- */
198
- update?: (tools: {
199
- draft: RD["Data"]; // Immer draft для мутации
200
- args: D["Args"]; // Аргументы команды
201
- data: D["Data"]; // Результат команды
202
- }) => void | RD["Data"];
203
-
204
- /**
205
- * Оптимистичное обновление ДО выполнения команды.
206
- * Позволяет обновить UI немедленно
207
- */
208
- optimisticUpdate?: (tools: {
209
- draft: RD["Data"]; // Immer draft для мутации
210
- args: D["Args"]; // Аргументы команды
211
- }) => void | RD["Data"];
212
-
213
- /**
214
- * Создание нового элемента в кэше.
215
- * Используется когда команда создает новую сущность
216
- */
217
- create?: (tools: {
218
- args: D["Args"];
219
- data: D["Data"];
220
- }) => RD["Data"] | Promise<RD["Data"]>;
221
- };
222
- ```
223
-
224
- ### Пример: Оптимистичные обновления
225
-
226
- ```typescript
227
- const toggleCartItem = createCommand({
228
- queryFn: async (args: { id: string; enabled: boolean }) => {
229
- return fetch(`/api/cart/toggle`, {
230
- method: 'POST',
231
- body: JSON.stringify(args)
232
- }).then(r => r.json());
233
- },
234
- link(add) {
235
- add({
236
- resource: cartResource,
237
- forwardArgs: () => undefined, // Корзина без параметров
238
-
239
- // Оптимистичное обновление — UI обновится мгновенно
240
- optimisticUpdate: ({ draft, args }) => {
241
- const item = draft.items.find(i => i.id === args.id);
242
- if (item) {
243
- item.enabled = args.enabled;
244
- }
245
- }
246
- // При ошибке изменения автоматически откатятся
247
- });
248
- }
13
+ const usersResource = api.createResource({
14
+ queryFn: async (args: { page: number }, signal) => {
15
+ const res = await fetch(`/api/users?page=${args.page}`, { signal });
16
+ return res.json();
17
+ },
249
18
  });
250
- ```
251
-
252
- ---
253
19
 
254
- ## Состояния запросов
255
-
256
- ### ResourceQueryState
257
-
258
- Состояние запроса ресурса через агента:
259
-
260
- ```typescript
261
- type ResourceQueryState<D> = {
262
- /** Инициализирован ли хотя бы один запрос */
263
- isInitiated: boolean;
264
-
265
- /** Любая загрузка (первая или повторная) */
266
- isLoading: boolean;
267
-
268
- /** Первая загрузка (данных еще не было) */
269
- isInitialLoading: boolean;
270
-
271
- /** Перезагрузка (данные уже есть) */
272
- isReloading: boolean;
273
-
274
- /** Завершен ли запрос */
275
- isDone: boolean;
276
-
277
- /** Успешно ли завершен последний запрос */
278
- isSuccess: boolean;
279
-
280
- /** Произошла ли ошибка последнего запроса */
281
- isError: boolean;
282
-
283
- /** Заблокирован ли ресурс командой */
284
- isLocked: boolean;
285
-
286
- /** Оригинал ошибки, если есть */
287
- error: unknown | undefined;
288
-
289
- /** Данные (или select данных) */
290
- data: D["Data"] | undefined;
291
-
292
- /** Аргументы последнего запроса */
293
- args: D["Args"] | undefined;
294
- }
295
- ```
296
-
297
- ### CommandQueryState
298
-
299
- Состояние выполнения команды:
300
-
301
- ```typescript
302
- type CommandQueryState<D> = {
303
- isInitiated: boolean;
304
- isLoading: boolean;
305
- isDone: boolean;
306
- isSuccess: boolean;
307
- isError: boolean;
308
- error: unknown | undefined;
309
- data: D["Data"] | undefined;
20
+ // React-компонент
21
+ function UsersList({ page }: { page: number }) {
22
+ const { data, error, isLoading } = usersResource.useResource({ page });
23
+ if (isLoading) return <Spinner />;
24
+ return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
310
25
  }
311
26
  ```
312
27
 
313
- ---
314
-
315
- ## ResourceRef API
316
-
317
- ResourceRef предоставляет низкоуровневый доступ к элементу кэша:
318
-
319
- ```typescript
320
- type ResourceRefInstance<D> = {
321
- /** Проверка наличия элемента в кэше */
322
- get has(): boolean;
323
-
324
- /** Блокировка ресурса (возвращает функцию разблокировки) */
325
- lock(): { unlock: () => void };
326
-
327
- /** Снятие одной блокировки */
328
- unlockOne(): void;
329
-
330
- /** Patch-транзакция для изменения данных */
331
- patch(patchFn: (data: D['Data']) => void): ResourceTransaction | null;
332
-
333
- /** Инвалидация (очистка) кэша */
334
- invalidate(): void;
335
-
336
- /** Создание элемента в кэше с данными */
337
- create(data: D['Data']): void;
338
- }
339
- ```
340
-
341
- ### Patch-транзакции
342
-
343
- Транзакции позволяют делать изменения с возможностью отката:
344
-
345
- ```typescript
346
- type ResourceTransaction = {
347
- patches: ImmerPatch[] // Патчи изменений
348
- inversePatches: ImmerPatch[] // Патчи для отката
349
- status: 'pending' | 'committed' | 'aborted'
350
- abort(): void // Откатить изменения
351
- commit(): void // Подтвердить изменения
352
- }
353
- ```
354
-
355
- **Пример использования транзакций:**
356
-
357
- ```typescript
358
- import { useResourceRef } from '@fozy-labs/rx-toolkit';
359
-
360
- function TodoList() {
361
- const todoRef = useResourceRef(todoResource, undefined);
362
- const [pendingChanges, setPendingChanges] = useState([]);
363
-
364
- const handleToggle = (itemId: number) => {
365
- const transaction = todoRef.patch((draft) => {
366
- const item = draft.items.find(i => i.id === itemId);
367
- if (item) item.completed = !item.completed;
368
- });
369
-
370
- if (transaction) {
371
- setPendingChanges(prev => [...prev, {
372
- id: itemId,
373
- transaction
374
- }]);
375
- }
376
- };
377
-
378
- const commitChange = (id: number) => {
379
- const change = pendingChanges.find(c => c.id === id);
380
- change?.transaction.commit();
381
- setPendingChanges(prev => prev.filter(c => c.id !== id));
382
- };
383
-
384
- const abortChange = (id: number) => {
385
- const change = pendingChanges.find(c => c.id === id);
386
- change?.transaction.abort(); // Данные вернутся к исходным
387
- setPendingChanges(prev => prev.filter(c => c.id !== id));
388
- };
389
- }
390
- ```
391
-
392
- ---
393
-
394
- ## Lifecycle хуки
395
-
396
- ### onCacheEntryAdded
397
-
398
- Вызывается при добавлении нового элемента в кэш:
399
-
400
- ```typescript
401
- const userResource = createResource({
402
- queryFn: fetchUser,
403
-
404
- onCacheEntryAdded(args, { $cacheDataLoaded, $cacheEntryRemoved, dataChanged$ }) {
405
- // args — аргументы запроса
406
-
407
- // Ожидание первой загрузки данных
408
- $cacheDataLoaded.then(() => {
409
- console.log('Данные загружены в кэш');
410
- });
411
-
412
- // Ожидание удаления из кэша
413
- $cacheEntryRemoved.then(() => {
414
- console.log('Элемент удален из кэша');
415
- });
416
-
417
- // Подписка на изменения данных
418
- const sub = dataChanged$.subscribe(data => {
419
- console.log('Данные изменились:', data);
420
- });
421
- }
422
- });
423
- ```
424
-
425
- ### onQueryStarted
426
-
427
- Вызывается при старте каждого запроса:
428
-
429
- ```typescript
430
- const userResource = createResource({
431
- queryFn: fetchUser,
432
-
433
- async onQueryStarted(args, { $queryFulfilled }) {
434
- console.log('Запрос начат с аргументами:', args);
435
-
436
- const result = await $queryFulfilled;
437
-
438
- if (result.isError) {
439
- console.error('Ошибка запроса:', result.error);
440
- } else {
441
- console.log('Запрос успешен:', result.data);
442
- }
443
- }
444
- });
445
- ```
446
-
447
- ---
448
-
449
- ## Утилиты
450
-
451
- ### resetAllQueriesCache
452
-
453
- Сбрасывает кэш всех ресурсов в приложении:
454
-
455
- ```typescript
456
- import { resetAllQueriesCache } from '@fozy-labs/rx-toolkit';
457
-
458
- function LogoutButton() {
459
- const handleLogout = () => {
460
- // Очистить все кэшированные данные при выходе
461
- resetAllQueriesCache();
462
- navigate('/login');
463
- };
464
-
465
- return <button onClick={handleLogout}>Выйти</button>;
466
- }
467
- ```
468
-
469
- ### SKIP токен
470
-
471
- Используется для условного пропуска запроса:
472
-
473
- ```typescript
474
- import { useResourceAgent, SKIP } from '@fozy-labs/rx-toolkit';
475
-
476
- function UserProfile({ userId }: { userId: string | null }) {
477
- // Запрос будет выполнен только если userId не null
478
- const userQuery = useResourceAgent(
479
- userResource,
480
- userId ? { id: userId } : SKIP
481
- );
482
-
483
- if (!userId) return <div>Выберите пользователя</div>;
484
- if (userQuery.isLoading) return <div>Загрузка...</div>;
485
-
486
- return <div>{userQuery.data?.name}</div>;
487
- }
488
- ```
489
-
490
- ---
491
-
492
- ## Примеры
493
-
494
- ### Корзина покупок с оптимистичными обновлениями
495
-
496
- ```typescript
497
- import { createResource, createCommand, useResourceAgent, useCommandAgent } from '@fozy-labs/rx-toolkit';
498
-
499
- const cartResource = createResource({
500
- queryFn: () => fetch('/api/cart').then(r => r.json()),
501
- devtoolsName: 'cart'
502
- });
503
-
504
- const toggleCartItem = createCommand({
505
- queryFn: (args: { id: string; enabled: boolean }) =>
506
- fetch('/api/cart/toggle', {
507
- method: 'POST',
508
- body: JSON.stringify(args)
509
- }).then(r => r.json()),
510
-
511
- link(add) {
512
- add({
513
- resource: cartResource,
514
- forwardArgs: () => undefined,
515
- optimisticUpdate: ({ draft, args }) => {
516
- const item = draft.items.find(i => i.id === args.id);
517
- if (item) item.enabled = args.enabled;
518
- }
519
- });
520
- }
521
- });
522
-
523
- function ShoppingCart() {
524
- const cartQuery = useResourceAgent(cartResource, undefined);
525
- const [toggleItem, toggleState] = useCommandAgent(toggleCartItem);
526
-
527
- return (
528
- <div>
529
- {cartQuery.data?.items.map(item => (
530
- <div key={item.id}>
531
- <span>{item.name}</span>
532
- <button onClick={() => toggleItem({
533
- id: item.id,
534
- enabled: !item.enabled
535
- })}>
536
- {item.enabled ? 'Убрать' : 'Добавить'}
537
- </button>
538
- </div>
539
- ))}
540
- </div>
541
- );
542
- }
543
- ```
544
-
545
- ### Зависимые запросы
546
-
547
- ```typescript
548
- const userResource = createResource({
549
- queryFn: (args: { id: number }) => fetch(`/api/users/${args.id}`).then(r => r.json()),
550
- });
551
-
552
- const userStatsResource = createResource({
553
- queryFn: (args: { userId: number; period: string }) =>
554
- fetch(`/api/users/${args.userId}/stats?period=${args.period}`).then(r => r.json()),
555
- });
556
-
557
- function UserDashboard({ userId }: { userId: number }) {
558
- const [period, setPeriod] = useState('daily');
559
-
560
- const userQuery = useResourceAgent(userResource, { id: userId });
561
-
562
- // Запрос статистики выполняется только после загрузки пользователя
563
- const statsQuery = useResourceAgent(
564
- userStatsResource,
565
- userQuery.isSuccess ? { userId, period } : SKIP
566
- );
567
-
568
- // ...
569
- }
570
- ```
571
-
572
- ## React интеграция
573
-
574
- См. [React интеграция](../usage/react/README.md) для подробной информации о React хуках.
575
28
 
29
+ ## Возможности
30
+
31
+ - **Кеширование** — автоматическое по аргументам, с настраиваемым временем жизни
32
+ - **Stale-While-Revalidate** — показ устаревших данных во время фонового обновления
33
+ - **Оптимистичные обновления** — Immer-патчи с автоматическим ребейсом при ответе сервера
34
+ - **SSR / гидрация** — снимки кеша для серверного рендеринга
35
+ - **Кросс-табовая синхронизация** — BroadcastChannel для актуальности данных между вкладками
36
+ - **Система плагинов** — расширение ресурсов и команд через `createApi({ plugins: [...] })`
37
+
38
+
39
+ ## Что читать дальше
40
+
41
+ | Цель | Рекомендуемый порядок |
42
+ |------|-----------------------|
43
+ | **Быстрый старт** | [usage/resource.md][resource] → [usage/command.md][command] |
44
+ | **Понять внутреннее устройство** | [concepts/machine.md][machine] → [concepts/cache.md][cache] → [concepts/agent.md][agent] |
45
+ | **Оптимистичные обновления** | [concepts/patching.md][patching] → [usage/links.md][links] |
46
+ | **SSR / гидрация** | [usage/snapshot.md][snapshot] |
47
+ | **Кросс-табовая синхронизация** | [usage/broadcast.md][broadcast] |
48
+ | **API-справочник** | [api/README.md][api] → [api/resource.md][api-resource] → [api/command.md][api-command] |
49
+ | **Написание плагинов** | [usage/plugins.md][plugins] |
50
+
51
+
52
+ [signals]: ../signals/README.md
53
+ [resource]: usage/resource.md
54
+ [command]: usage/command.md
55
+ [machine]: concepts/machine.md
56
+ [cache]: concepts/cache.md
57
+ [agent]: concepts/agent.md
58
+ [patching]: concepts/patching.md
59
+ [links]: usage/links.md
60
+ [snapshot]: usage/snapshot.md
61
+ [broadcast]: usage/broadcast.md
62
+ [api]: api/README.md
63
+ [api-resource]: api/resource.md
64
+ [api-command]: api/command.md
65
+ [plugins]: usage/plugins.md
@@ -0,0 +1,59 @@
1
+ # RxQuery API
2
+
3
+ API — центральный объект, управляющий ресурсами и командами.
4
+
5
+
6
+ ## Создание API
7
+
8
+ ```typescript
9
+ import { createApi, reactHooksPlugin } from '@fozy-labs/rx-toolkit';
10
+
11
+ const api = createApi({
12
+ keyPrefix: 'my-app', // (опционально) префикс для всех ключей ресурсов
13
+ plugins: [
14
+ reactHooksPlugin(), // (опционально) подключаем React Hooks плагин для удобного использования в React-приложениях
15
+ ],
16
+ });
17
+ ```
18
+
19
+
20
+ ## Опции API
21
+
22
+ | Опция | Тип | По умолчанию | Описание |
23
+ |----------------------|---------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------|
24
+ | `keyPrefix` | `string` \| `null` | `undefined` | Префикс, который добавляется ко всем ключам ресурсов и команд, создаваемых через этот API. |
25
+ | `plugins` | `IPlugin[]` | `[]` | Массив плагинов, которые будут использоваться этим API. |
26
+ | `serializeArgs` | `(args: TArgs) => string` | `stableStringify` | Функция сериализации аргументов в строку. |
27
+ | `resourceRetentionTime` | `number` \| `false` | `60_000 ms` | Время удержания кэша ресурсов. `false` — не удалять. |
28
+ | `commandRetentionTime` | `number` \| `false` | `0` | Время удержания кэша команд. `false` — не удалять. |
29
+ | `initialSnapshot` | `TApiSnapshot` \| `null` | `null` | Начальный [снимок] состояния всех ресурсов (для SSR или гидрации). |
30
+ | `snapshotValidTime` | `number` \| `false` | `false` | Время валидности данных в снимке. `false` - данные в [снимке][снимок] считаются всегда валидными. |
31
+ | `defaultSync` | `'none'` \| `'resources'` \| `'all'` | `'none'` | Режим синхронизации по умолчанию для ресурсов. `'none'` — выключена, `'resources'` / `'all'` — включена. Команды не поддерживают синхронизацию. |
32
+ | `syncDriver` | `ISyncDriver` | `undefined` | Драйвер для [синхронизации][синхронизация] состояния между несколькими экземплярами API (например, в разных вкладках браузера). |
33
+ | `onCacheEntryAdded` | `(args, ctx) => void` | — | Хук жизненного цикла уровня API — вызывается при создании любой кэш-записи. См. [lifecycle hooks][lifecycle]. |
34
+ | `onQueryStarted` | `(args, ctx) => void \| Promise<void>` | — | Хук жизненного цикла уровня API — вызывается при каждом запуске `queryFn`. См. [lifecycle hooks][lifecycle]. |
35
+
36
+ ## Методы API
37
+
38
+ | Метод | Опции | Возвращаемое значение | Описание |
39
+ |------------------|--------------------------------------------|-----------------------------------------|-----------------------------------------------------------------|
40
+ | `createResource` | `options: TResourceOptions<TArgs, TData>` | `IApiResource<TPlugins, TArgs, TData>` | Создаёт новый [ресурс]. |
41
+ | `createCommand` | `options: TCommandOptions<TArgs, TData>` | `IApiCommand<TPlugins, TArgs, TData>` | Создаёт новую [команду][команда]. |
42
+ | `getSnapshot()` | - | `TApiSnapshot` | Получает текущий [снимок] состояния всех [ресурсов][ресурс]. |
43
+ | `resetAll()` | - | `void` | Сбрасывает все ресурсы и очищает сохранённый снимок. |
44
+
45
+
46
+ ## См. также
47
+
48
+ - [Ресурс](../usage/resource.md)
49
+ - [Команда](../usage/command.md)
50
+ - [Снимок (SSR / гидрация)](../usage/snapshot.md)
51
+ - [Синхронизация между вкладками](../usage/broadcast.md)
52
+ - [Lifecycle hooks](../usage/lifecycle.md)
53
+
54
+
55
+ [снимок]: ../usage/snapshot.md
56
+ [синхронизация]: ../usage/broadcast.md
57
+ [lifecycle]: ../usage/lifecycle.md
58
+ [ресурс]: ../usage/resource.md
59
+ [команда]: ../usage/command.md