@fozy-labs/rx-toolkit 0.5.3-rc.2 → 0.5.4

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 (196) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +143 -137
  3. package/dist/common/devtools/combineDevtools.js +3 -3
  4. package/dist/common/devtools/index.d.ts +3 -3
  5. package/dist/common/devtools/index.js +3 -3
  6. package/dist/common/devtools/reduxDevtools.d.ts +1 -1
  7. package/dist/common/devtools/reduxDevtools.js +17 -17
  8. package/dist/common/devtools/types.d.ts +0 -6
  9. package/dist/common/options/SharedOptions.d.ts +1 -0
  10. package/dist/common/options/SharedOptions.js +6 -0
  11. package/dist/common/options/index.d.ts +1 -1
  12. package/dist/common/options/index.js +1 -1
  13. package/dist/common/react/index.d.ts +2 -2
  14. package/dist/common/react/index.js +2 -2
  15. package/dist/common/react/useConstant.js +1 -1
  16. package/dist/common/utils/deepEqual.js +1 -1
  17. package/dist/common/utils/index.d.ts +3 -3
  18. package/dist/common/utils/index.js +3 -3
  19. package/dist/common/utils/shallowEqual.js +1 -1
  20. package/dist/index.d.ts +8 -7
  21. package/dist/index.js +8 -7
  22. package/dist/query/SKIP_TOKEN.js +1 -1
  23. package/dist/query/api/createCommand.d.ts +1 -1
  24. package/dist/query/api/createOperation.d.ts +1 -1
  25. package/dist/query/api/createOperation.js +1 -1
  26. package/dist/query/api/createResource.d.ts +1 -1
  27. package/dist/query/api/createResourceDuplicator.d.ts +1 -1
  28. package/dist/query/core/Command/Command.d.ts +7 -7
  29. package/dist/query/core/Command/Command.js +2 -2
  30. package/dist/query/core/Command/CommandAgent.d.ts +1 -1
  31. package/dist/query/core/Command/index.d.ts +2 -2
  32. package/dist/query/core/Command/index.js +2 -2
  33. package/dist/query/core/{Opertation → Operation}/Operation.d.ts +2 -2
  34. package/dist/query/core/{Opertation → Operation}/Operation.js +1 -1
  35. package/dist/query/core/{Opertation → Operation}/OperationAgent.d.ts +1 -1
  36. package/dist/query/core/{Opertation → Operation}/OperationAgent.js +1 -1
  37. package/dist/query/core/QueriesCache.d.ts +1 -1
  38. package/dist/query/core/QueriesCache.js +1 -1
  39. package/dist/query/core/QueriesLifetimeHooks.js +7 -7
  40. package/dist/query/core/Resource/Resource.d.ts +15 -15
  41. package/dist/query/core/Resource/Resource.js +7 -7
  42. package/dist/query/core/Resource/ResourceAgent.d.ts +1 -1
  43. package/dist/query/core/Resource/ResourceAgent.js +2 -2
  44. package/dist/query/core/Resource/ResourceDuplicator.d.ts +16 -16
  45. package/dist/query/core/Resource/ResourceDuplicator.js +18 -20
  46. package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +5 -5
  47. package/dist/query/core/Resource/ResourceDuplicatorAgent.js +2 -2
  48. package/dist/query/core/Resource/ResourceRef.d.ts +2 -2
  49. package/dist/query/core/Resource/ResourceRef.js +12 -12
  50. package/dist/query/index.d.ts +11 -10
  51. package/dist/query/index.js +11 -10
  52. package/dist/query/lib/IndirectMap.js +4 -4
  53. package/dist/query/react/useCommandAgent.d.ts +2 -2
  54. package/dist/query/react/useOperationAgent.d.ts +1 -1
  55. package/dist/query/react/useOperationAgent.js +1 -1
  56. package/dist/query/react/useResourceAgent.d.ts +3 -3
  57. package/dist/query/react/useResourceAgent.js +1 -1
  58. package/dist/query/react/useResourceRef.d.ts +3 -3
  59. package/dist/query/react/useResourceRef.js +7 -2
  60. package/dist/query/types/Command.types.d.ts +1 -1
  61. package/dist/query/types/Operation.types.d.ts +1 -1
  62. package/dist/query/types/Resource.types.d.ts +7 -5
  63. package/dist/query/types/index.d.ts +4 -4
  64. package/dist/query/types/index.js +4 -4
  65. package/dist/query-v2/api/createApi.d.ts +10 -0
  66. package/dist/query-v2/api/createApi.js +83 -0
  67. package/dist/query-v2/core/common/CacheEntry.d.ts +29 -0
  68. package/dist/query-v2/core/common/CacheEntry.js +71 -0
  69. package/dist/query-v2/core/common/CacheMap.d.ts +38 -0
  70. package/dist/query-v2/core/common/CacheMap.js +127 -0
  71. package/dist/query-v2/core/common/LifecycleHooks.d.ts +22 -0
  72. package/dist/query-v2/core/common/LifecycleHooks.js +104 -0
  73. package/dist/query-v2/core/common/index.d.ts +3 -0
  74. package/dist/query-v2/core/common/index.js +3 -0
  75. package/dist/query-v2/core/index.d.ts +3 -0
  76. package/dist/query-v2/core/index.js +3 -0
  77. package/dist/query-v2/core/machines/Machine.d.ts +14 -0
  78. package/dist/query-v2/core/machines/Machine.js +33 -0
  79. package/dist/query-v2/core/machines/MachineError.d.ts +11 -0
  80. package/dist/query-v2/core/machines/MachineError.js +26 -0
  81. package/dist/query-v2/core/machines/MachineIdle.d.ts +8 -0
  82. package/dist/query-v2/core/machines/MachineIdle.js +19 -0
  83. package/dist/query-v2/core/machines/MachinePending.d.ts +12 -0
  84. package/dist/query-v2/core/machines/MachinePending.js +29 -0
  85. package/dist/query-v2/core/machines/MachineRefreshing.d.ts +14 -0
  86. package/dist/query-v2/core/machines/MachineRefreshing.js +46 -0
  87. package/dist/query-v2/core/machines/MachineSuccess.d.ts +16 -0
  88. package/dist/query-v2/core/machines/MachineSuccess.js +42 -0
  89. package/dist/query-v2/core/machines/MachineWithData.d.ts +18 -0
  90. package/dist/query-v2/core/machines/MachineWithData.js +40 -0
  91. package/dist/query-v2/core/machines/Patcher.d.ts +20 -0
  92. package/dist/query-v2/core/machines/Patcher.js +104 -0
  93. package/dist/query-v2/core/machines/index.d.ts +8 -0
  94. package/dist/query-v2/core/machines/index.js +8 -0
  95. package/dist/query-v2/core/resource/ResourceV2.d.ts +120 -0
  96. package/dist/query-v2/core/resource/ResourceV2.js +464 -0
  97. package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +26 -0
  98. package/dist/query-v2/core/resource/ResourceV2Agent.js +132 -0
  99. package/dist/query-v2/core/resource/index.d.ts +2 -0
  100. package/dist/query-v2/core/resource/index.js +2 -0
  101. package/dist/query-v2/index.d.ts +11 -0
  102. package/dist/query-v2/index.js +17 -0
  103. package/dist/query-v2/lib/NO_VALUE.d.ts +2 -0
  104. package/dist/query-v2/lib/NO_VALUE.js +1 -0
  105. package/dist/query-v2/lib/SKIP_TOKEN.d.ts +2 -0
  106. package/dist/query-v2/lib/SKIP_TOKEN.js +1 -0
  107. package/dist/query-v2/lib/index.d.ts +4 -0
  108. package/dist/query-v2/lib/index.js +3 -0
  109. package/dist/query-v2/lib/stableStringify.d.ts +8 -0
  110. package/dist/query-v2/lib/stableStringify.js +23 -0
  111. package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +25 -0
  112. package/dist/query-v2/plugins/ReactHooksPlugin.js +19 -0
  113. package/dist/query-v2/plugins/types.d.ts +1 -0
  114. package/dist/query-v2/plugins/types.js +1 -0
  115. package/dist/query-v2/react/__tests__/helpers.d.ts +12 -0
  116. package/dist/query-v2/react/__tests__/helpers.js +33 -0
  117. package/dist/query-v2/react/index.d.ts +2 -0
  118. package/dist/query-v2/react/index.js +2 -0
  119. package/dist/query-v2/react/useResourceV2Agent.d.ts +12 -0
  120. package/dist/query-v2/react/useResourceV2Agent.js +36 -0
  121. package/dist/query-v2/react/useResourceV2Ref.d.ts +12 -0
  122. package/dist/query-v2/react/useResourceV2Ref.js +57 -0
  123. package/dist/query-v2/snapshot/Snapshot.d.ts +13 -0
  124. package/dist/query-v2/snapshot/Snapshot.js +76 -0
  125. package/dist/query-v2/types/agent.types.d.ts +54 -0
  126. package/dist/query-v2/types/agent.types.js +1 -0
  127. package/dist/query-v2/types/api.types.d.ts +22 -0
  128. package/dist/query-v2/types/api.types.js +1 -0
  129. package/dist/query-v2/types/cache.types.d.ts +37 -0
  130. package/dist/query-v2/types/cache.types.js +1 -0
  131. package/dist/query-v2/types/index.d.ts +9 -0
  132. package/dist/query-v2/types/index.js +9 -0
  133. package/dist/query-v2/types/lifecycle.types.d.ts +25 -0
  134. package/dist/query-v2/types/lifecycle.types.js +1 -0
  135. package/dist/query-v2/types/machine.types.d.ts +67 -0
  136. package/dist/query-v2/types/machine.types.js +1 -0
  137. package/dist/query-v2/types/plugin.types.d.ts +38 -0
  138. package/dist/query-v2/types/plugin.types.js +1 -0
  139. package/dist/query-v2/types/resource.types.d.ts +35 -0
  140. package/dist/query-v2/types/resource.types.js +1 -0
  141. package/dist/query-v2/types/shared.types.d.ts +20 -0
  142. package/dist/query-v2/types/shared.types.js +1 -0
  143. package/dist/query-v2/types/snapshot.types.d.ts +21 -0
  144. package/dist/query-v2/types/snapshot.types.js +1 -0
  145. package/dist/signals/base/Batcher.js +9 -5
  146. package/dist/signals/base/ComputeCache.js +3 -3
  147. package/dist/signals/base/DependencyTracker.js +1 -1
  148. package/dist/signals/base/Devtools.d.ts +3 -2
  149. package/dist/signals/base/Devtools.js +54 -27
  150. package/dist/signals/base/Indexer.js +1 -1
  151. package/dist/signals/base/ReadonlySignal.js +1 -1
  152. package/dist/signals/base/SyncObservable.d.ts +1 -2
  153. package/dist/signals/base/SyncObservable.js +2 -5
  154. package/dist/signals/base/index.d.ts +6 -6
  155. package/dist/signals/base/index.js +6 -6
  156. package/dist/signals/index.d.ts +5 -4
  157. package/dist/signals/index.js +5 -4
  158. package/dist/signals/operators/index.d.ts +1 -1
  159. package/dist/signals/operators/index.js +1 -1
  160. package/dist/signals/react/index.d.ts +1 -1
  161. package/dist/signals/react/index.js +1 -1
  162. package/dist/signals/signals/Computed.d.ts +3 -4
  163. package/dist/signals/signals/Computed.js +18 -10
  164. package/dist/signals/signals/Effect.js +2 -1
  165. package/dist/signals/signals/LocalState.d.ts +3 -4
  166. package/dist/signals/signals/LocalState.js +8 -8
  167. package/dist/signals/signals/Signal.d.ts +7 -6
  168. package/dist/signals/signals/Signal.js +4 -1
  169. package/dist/signals/signals/State.d.ts +4 -5
  170. package/dist/signals/signals/State.js +23 -9
  171. package/dist/signals/signals/index.d.ts +5 -5
  172. package/dist/signals/signals/index.js +5 -6
  173. package/dist/signals/types/SignalOptions.d.ts +16 -0
  174. package/dist/signals/types/SignalOptions.js +1 -0
  175. package/dist/signals/types/index.d.ts +3 -1
  176. package/dist/signals/types/index.js +3 -1
  177. package/dist/signals/types/normalizeSignalOptions.d.ts +2 -0
  178. package/dist/signals/types/normalizeSignalOptions.js +10 -0
  179. package/dist/signals/types/signals.types.d.ts +2 -3
  180. package/docs/CHANGELOG.md +95 -90
  181. package/docs/CONTRIBUTING.md +230 -0
  182. package/docs/contributing/ai-assisted-development.md +47 -0
  183. package/docs/contributing/query-v2/README.md +379 -0
  184. package/docs/{release → contributing/release}/README.md +59 -59
  185. package/docs/devtools/README.md +228 -228
  186. package/docs/migrations/0.5.0.md +58 -58
  187. package/docs/migrations/query-v2.md +171 -0
  188. package/docs/options/README.md +92 -92
  189. package/docs/query/README.md +575 -573
  190. package/docs/query-v2/README.md +280 -0
  191. package/docs/query-v2/api-reference.md +235 -0
  192. package/docs/query-v2/optimistic-updates.md +148 -0
  193. package/docs/query-v2/ssr.md +130 -0
  194. package/docs/signals/README.md +300 -300
  195. package/docs/usage/react/README.md +309 -309
  196. package/package.json +85 -63
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Vladimir Panev
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vladimir Panev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,137 +1,143 @@
1
- # RxToolkit
2
-
3
- > Фреймворк агностик набор инструментов для **реактивного** управления состоянием, построенный поверх RxJS.
4
-
5
- [![npm version](https://badge.fury.io/js/%40fozy-labs%2Frx-toolkit.svg)](https://badge.fury.io/js/%40fozy-labs%2Frx-toolkit)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
7
- [![RxJS](https://img.shields.io/badge/RxJS-7.8-purple.svg)](https://rxjs.dev/)
8
- ## 📦 Установка
9
-
10
- ```bash
11
- npm install @fozy-labs/rx-toolkit rxjs
12
- ```
13
-
14
- ## 🎯 Цель
15
-
16
- RxJS действительно мощный инструмент реактивного программирования,
17
- он удобен когда мы работаем с потоком событий, но когда речь заходит о состоянии приложения,
18
- из-за асинхронной природы rx'а, его использование становится сложным и громоздким, не говоря уже о кешировании данных
19
- (хотя некоторые разработчики "продают" rxjs, как альтернативу Query библиотекам,
20
- на самом деле реализация подобного функционала выльется в создание отдельной библиотеки).
21
-
22
- RxToolkit решает эти проблемы, предоставляя свою реализацию сигналов и кеш-менеджера.
23
-
24
- ## ✨ Особенности
25
-
26
- - 🧩 **Реактивные примитивы** — Привычные Signal, Computed и Effect.
27
- - 🔧 **Framework-agnostic** — Стройте систему и описывайте логику в изолированном месте.
28
- - ⚡ **Built on RxJS** — Наследует всю мощь RxJS.
29
- - 💾 **Кеш-менеджер** — Предоставляет Query реализацию для работы с данными.
30
- - 🔷 **TypeScript-first** — Полная типизация.
31
- - 🔗 **Интеграция с фреймворками** Как и RxJS напрямую работает в Angular, Svelte и SolidJS.
32
- Поставляется с React-хуками из коробки.
33
-
34
- ## 📚 Документация
35
- - [**RxSignals**](./docs/signals/README.md) - реактивные примитивы
36
- - [**RxQuery**](./docs/query/README.md) - кеш-менеджер для работы с данными
37
- - [**React**](./docs/usage/react/README.md) - интеграция с React
38
- - [**Devtools**](./docs/devtools/README.md) - инструменты разработчика
39
- - [**Changelog**](./docs/CHANGELOG.md) - история изменений
40
- - [**DefaultOptions**](./docs/options/README.md) - глобальные настройки
41
-
42
- ## 🌟 Примеры
43
-
44
- ###### Создаем сигнал
45
- ```typescript
46
- // Описываем логику в обычном JavaScript
47
- const count$ = Signal.state(0);
48
- const doubled$ = Signal.compute(() => count$() * 2);
49
- const increment = () => count$.set(count$() + 1);
50
- ```
51
-
52
- ###### Подключаем к фреймворку
53
- ```typescript
54
- // React
55
- const count = useSignal(count$);
56
-
57
- // Angular signal
58
- public readonly count = toSignal(count$.obs);
59
-
60
- // Angular pipe
61
- {{ count$.obs | async }}
62
-
63
- // SolidJS
64
- const count = from(count$.obs)
65
-
66
- // Svelte
67
- $: count = count$.obs;
68
- ```
69
-
70
- ###### Работаем с RxJS
71
-
72
- ```typescript
73
- // Создаем Observable
74
- const clicker$ = fromEvent(document, 'click').pipe(
75
- debounceTime(300),
76
- scan(count => count + 1, 0),
77
- startWith(0),
78
- );
79
-
80
- // Получаем сигнал из Observable
81
- const clickCount$ = signalize(clicker$);
82
- const doubled$ = Signal.compute(() => clickCount$() * 2);
83
-
84
- console.log(doubled$()); // Всегда актуальное значение
85
-
86
- // Или наоборот, получаем событие из сигнала
87
- const on10click$ = doubled$.obs.pipe(
88
- filter(value => value === 10),
89
- take(1)
90
- );
91
-
92
- const sub = on10click$.subscribe(() => {
93
- console.log('Great! That you first reached 10 clicks!');
94
- });
95
- // Не забываем отписаться
96
- sub.unsubscribe();
97
- ```
98
-
99
- ###### RxQuery (Корзина покупок)
100
- ```tsx
101
- const getCart = createResource({
102
- queryFn: fetchCart,
103
- });
104
-
105
- const toggleCardItem = createCommand({
106
- queryFn: fetchToggleCardItem,
107
- link(add) {
108
- add({
109
- resource: getCart,
110
- forwardArgs: () => undefined,
111
- optimisticUpdate: ({ draft, args }) => {
112
- const item = draft.items.find(i => i.id === args.id);
113
- if (!item) return;
114
- item.enabled = args.enabled;
115
- }
116
- })
117
- }
118
- });
119
-
120
- function ShoppingCart() {
121
- const cartQuery = useResourceAgent(getCart);
122
- const [toggleItem] = useCommandAgent(toggleCardItem);
123
- const cart = cartQuery.data;
124
-
125
- return (
126
- <Container isLoading={cartQuery.isLoading}>
127
- {cart?.items.map(item => (
128
- <CartItem
129
- key={item.id}
130
- item={item}
131
- onToggle={() => toggleItem({ id: item.id, enabled: !item.enabled })}
132
- />
133
- ))}
134
- </Container>
135
- );
136
- }
137
- ```
1
+ # RxToolkit
2
+
3
+ > Фреймворк агностик набор инструментов для **реактивного** управления состоянием, построенный поверх RxJS.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40fozy-labs%2Frx-toolkit.svg)](https://badge.fury.io/js/%40fozy-labs%2Frx-toolkit)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
7
+ [![RxJS](https://img.shields.io/badge/RxJS-7.8-purple.svg)](https://rxjs.dev/)
8
+ ## 📦 Установка
9
+
10
+ ```bash
11
+ npm install @fozy-labs/rx-toolkit rxjs
12
+ ```
13
+
14
+ ## 🎯 Цель
15
+
16
+ RxJS действительно мощный инструмент реактивного программирования,
17
+ он удобен когда мы работаем с потоком событий, но когда речь заходит о состоянии приложения,
18
+ из-за асинхронной природы rx'а, его использование становится сложным и громоздким, не говоря уже о кешировании данных
19
+ (хотя некоторые разработчики "продают" rxjs, как альтернативу Query библиотекам,
20
+ на самом деле реализация подобного функционала выльется в создание отдельной библиотеки).
21
+
22
+ RxToolkit решает эти проблемы, предоставляя свою реализацию сигналов и кеш-менеджера.
23
+
24
+ ## ✨ Особенности
25
+
26
+ - 🧩 **Реактивные примитивы** — Привычные Signal, Computed и Effect.
27
+ - 🔧 **Framework-agnostic** — Стройте систему и описывайте логику в изолированном месте.
28
+ - ⚡ **Built on RxJS** — Наследует всю мощь RxJS.
29
+ - 💾 **Кеш-менеджер** — Предоставляет Query реализацию для работы с данными.
30
+ - 🧪 **Query v2** *(experimental)* Переработанный кеш-менеджер с machine states, плагинами и SSR snapshots.
31
+ - 🔷 **TypeScript-first**Полная типизация.
32
+ - 🔗 **Интеграция с фреймворками** Как и RxJS напрямую работает в Angular, Svelte и SolidJS.
33
+ Поставляется с React-хуками из коробки.
34
+
35
+ ## 📚 Документация
36
+ - [**RxSignals**](./docs/signals/README.md) - реактивные примитивы
37
+ - [**RxQuery**](./docs/query/README.md) - кеш-менеджер для работы с данными
38
+ - [**RxQuery v2**](./docs/query-v2/README.md) - кеш-менеджер v2 *(experimental)*
39
+ - [**React**](./docs/usage/react/README.md) - интеграция с React
40
+ - [**Devtools**](./docs/devtools/README.md) - инструменты разработчика
41
+ - [**DefaultOptions**](./docs/options/README.md) - глобальные настройки
42
+
43
+
44
+ [**CHANGELOG**](./docs/CHANGELOG.md)
45
+
46
+ [**CONTRIBUTING**](./docs/CONTRIBUTING.md)
47
+
48
+ ## 🌟 Примеры
49
+
50
+ ###### Создаем сигнал
51
+ ```typescript
52
+ // Описываем логику в обычном JavaScript
53
+ const count$ = Signal.state(0);
54
+ const doubled$ = Signal.compute(() => count$() * 2);
55
+ const increment = () => count$.set(count$() + 1);
56
+ ```
57
+
58
+ ###### Подключаем к фреймворку
59
+ ```typescript
60
+ // React
61
+ const count = useSignal(count$);
62
+
63
+ // Angular signal
64
+ public readonly count = toSignal(count$.obs);
65
+
66
+ // Angular pipe
67
+ {{ count$.obs | async }}
68
+
69
+ // SolidJS
70
+ const count = from(count$.obs)
71
+
72
+ // Svelte
73
+ $: count = count$.obs;
74
+ ```
75
+
76
+ ###### Работаем с RxJS
77
+
78
+ ```typescript
79
+ // Создаем Observable
80
+ const clicker$ = fromEvent(document, 'click').pipe(
81
+ debounceTime(300),
82
+ scan(count => count + 1, 0),
83
+ startWith(0),
84
+ );
85
+
86
+ // Получаем сигнал из Observable
87
+ const clickCount$ = signalize(clicker$);
88
+ const doubled$ = Signal.compute(() => clickCount$() * 2);
89
+
90
+ console.log(doubled$()); // Всегда актуальное значение
91
+
92
+ // Или наоборот, получаем событие из сигнала
93
+ const on10click$ = doubled$.obs.pipe(
94
+ filter(value => value === 10),
95
+ take(1)
96
+ );
97
+
98
+ const sub = on10click$.subscribe(() => {
99
+ console.log('Great! That you first reached 10 clicks!');
100
+ });
101
+ // Не забываем отписаться
102
+ sub.unsubscribe();
103
+ ```
104
+
105
+ ###### RxQuery (Корзина покупок)
106
+ ```tsx
107
+ const getCart = createResource({
108
+ queryFn: fetchCart,
109
+ });
110
+
111
+ const toggleCardItem = createCommand({
112
+ queryFn: fetchToggleCardItem,
113
+ link(add) {
114
+ add({
115
+ resource: getCart,
116
+ forwardArgs: () => undefined,
117
+ optimisticUpdate: ({ draft, args }) => {
118
+ const item = draft.items.find(i => i.id === args.id);
119
+ if (!item) return;
120
+ item.enabled = args.enabled;
121
+ }
122
+ })
123
+ }
124
+ });
125
+
126
+ function ShoppingCart() {
127
+ const cartQuery = useResourceAgent(getCart);
128
+ const [toggleItem] = useCommandAgent(toggleCardItem);
129
+ const cart = cartQuery.data;
130
+
131
+ return (
132
+ <Container isLoading={cartQuery.isLoading}>
133
+ {cart?.items.map(item => (
134
+ <CartItem
135
+ key={item.id}
136
+ item={item}
137
+ onToggle={() => toggleItem({ id: item.id, enabled: !item.enabled })}
138
+ />
139
+ ))}
140
+ </Container>
141
+ );
142
+ }
143
+ ```
@@ -1,10 +1,10 @@
1
1
  export function combineDevtools(...devtools) {
2
2
  return {
3
3
  state(name, initState) {
4
- const updaters = devtools.map(d => d.state(name, initState));
4
+ const updaters = devtools.map((d) => d.state(name, initState));
5
5
  return (newState) => {
6
- updaters.forEach(update => update(newState));
6
+ updaters.forEach((update) => update(newState));
7
7
  };
8
- }
8
+ },
9
9
  };
10
10
  }
@@ -1,3 +1,3 @@
1
- export * from './reduxDevtools';
2
- export * from './combineDevtools';
3
- export * from './types';
1
+ export * from "./reduxDevtools";
2
+ export * from "./combineDevtools";
3
+ export * from "./types";
@@ -1,3 +1,3 @@
1
- export * from './reduxDevtools';
2
- export * from './combineDevtools';
3
- export * from './types';
1
+ export * from "./reduxDevtools";
2
+ export * from "./combineDevtools";
3
+ export * from "./types";
@@ -14,7 +14,7 @@ interface ReduxDevtoolsConnection {
14
14
  * - 'microtask' - пакование в микротаске (queueMicrotask), все обновления в текущем синхронном потоке объединяются
15
15
  * - 'task' - пакование в макротаске (setTimeout), с настраиваемой задержкой
16
16
  */
17
- export type BatchStrategy = 'sync' | 'microtask' | 'task';
17
+ export type BatchStrategy = "sync" | "microtask" | "task";
18
18
  type Options = {
19
19
  name?: string;
20
20
  driver?: ReduxDevtoolsExtension;
@@ -28,15 +28,15 @@ function createBatchScheduler(strategy, taskDelay) {
28
28
  return; // Уже запланировано
29
29
  isPending = true;
30
30
  switch (strategy) {
31
- case 'sync':
31
+ case "sync":
32
32
  // Используем Batcher — выполнится в конце текущего батча сигналов
33
33
  // или сразу, если батч не активен
34
34
  batcherScheduler.schedule(executePending);
35
35
  break;
36
- case 'microtask':
36
+ case "microtask":
37
37
  queueMicrotask(executePending);
38
38
  break;
39
- case 'task':
39
+ case "task":
40
40
  timeoutId = setTimeout(executePending, taskDelay);
41
41
  break;
42
42
  }
@@ -75,47 +75,47 @@ function createBatchScheduler(strategy, taskDelay) {
75
75
  pendingFlush = null;
76
76
  fn();
77
77
  }
78
- }
78
+ },
79
79
  };
80
80
  }
81
81
  export function reduxDevtools(options = {}) {
82
82
  const devtools = options.driver ?? window.__REDUX_DEVTOOLS_EXTENSION__;
83
83
  if (!devtools) {
84
- throw new Error('Redux Devtools extension is not installed');
84
+ throw new Error("Redux Devtools extension is not installed");
85
85
  }
86
- const batchStrategy = options.batchStrategy ?? 'microtask';
86
+ const batchStrategy = options.batchStrategy ?? "microtask";
87
87
  const taskDelay = options.taskDelay ?? 0;
88
88
  let state = {};
89
- const connection = devtools.connect({ name: options.name ?? 'RxToolkit' });
89
+ const connection = devtools.connect({ name: options.name ?? "RxToolkit" });
90
90
  connection.init(state);
91
91
  const scheduler = createBatchScheduler(batchStrategy, taskDelay);
92
92
  // Отслеживаем тип последнего действия для правильного action type в devtools
93
- let pendingActionType = 'update';
93
+ let pendingActionType = "update";
94
94
  const flushToDevtools = () => {
95
95
  connection.send({ type: pendingActionType }, state);
96
- pendingActionType = 'update'; // Сбрасываем на дефолт после отправки
96
+ pendingActionType = "update"; // Сбрасываем на дефолт после отправки
97
97
  };
98
98
  return {
99
99
  state(name, initState) {
100
- const keys = name.split('/');
100
+ const keys = name.split("/");
101
101
  state = applyState(keys, initState, state);
102
- pendingActionType = 'create';
102
+ pendingActionType = "create";
103
103
  scheduler.schedule(flushToDevtools);
104
104
  return (newState) => {
105
- if (newState === '$COMPLETED' || newState === '$CLEANED') {
105
+ if (newState === "$COMPLETED" || newState === "$CLEANED") {
106
106
  state = deleteState(keys, state);
107
- pendingActionType = 'clear';
107
+ pendingActionType = "clear";
108
108
  scheduler.schedule(flushToDevtools);
109
109
  return;
110
110
  }
111
111
  state = applyState(keys, newState, state);
112
112
  // Не перезаписываем 'create' на 'update' если create еще не отправлен
113
- if (pendingActionType !== 'create') {
114
- pendingActionType = 'update';
113
+ if (pendingActionType !== "create") {
114
+ pendingActionType = "update";
115
115
  }
116
116
  scheduler.schedule(flushToDevtools);
117
117
  };
118
- }
118
+ },
119
119
  };
120
120
  }
121
121
  function applyState(keys, newState, state) {
@@ -140,7 +140,7 @@ function deleteState(keys, state) {
140
140
  // Рекурсивная функция для удаления с очисткой пустых объектов
141
141
  const deleteRecursive = (obj, pathKeys, index) => {
142
142
  const key = pathKeys[index];
143
- if (!obj || !obj.hasOwnProperty(key)) {
143
+ if (!obj || !Object.prototype.hasOwnProperty.call(obj, key)) {
144
144
  return false;
145
145
  }
146
146
  if (index === pathKeys.length - 1) {
@@ -4,9 +4,3 @@ export interface DevtoolsStateLike<T = any> {
4
4
  export interface DevtoolsLike {
5
5
  state<T>(name: string, initState: T): DevtoolsStateLike<T>;
6
6
  }
7
- export type StateDevtoolsOptions = {
8
- isDisabled?: boolean;
9
- name?: string;
10
- base?: string;
11
- _skipValues?: any[];
12
- } | string;
@@ -5,4 +5,5 @@ export declare class SharedOptions {
5
5
  static onQueryError: ((error: unknown) => void) | null;
6
6
  static getScopeName: (() => string | null) | null;
7
7
  static defaultCompareArgs: typeof shallowEqual;
8
+ static reset(): void;
8
9
  }
@@ -4,4 +4,10 @@ export class SharedOptions {
4
4
  static onQueryError = null;
5
5
  static getScopeName = null;
6
6
  static defaultCompareArgs = shallowEqual;
7
+ static reset() {
8
+ SharedOptions.DEVTOOLS = null;
9
+ SharedOptions.onQueryError = null;
10
+ SharedOptions.getScopeName = null;
11
+ SharedOptions.defaultCompareArgs = shallowEqual;
12
+ }
7
13
  }
@@ -1 +1 @@
1
- export * from './DefaultOptions';
1
+ export * from "./DefaultOptions";
@@ -1 +1 @@
1
- export * from './DefaultOptions';
1
+ export * from "./DefaultOptions";
@@ -1,2 +1,2 @@
1
- export * from './useConstant';
2
- export * from './useEventHandler';
1
+ export * from "./useConstant";
2
+ export * from "./useEventHandler";
@@ -1,2 +1,2 @@
1
- export * from './useConstant';
2
- export * from './useEventHandler';
1
+ export * from "./useConstant";
2
+ export * from "./useEventHandler";
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  /**
3
3
  * Hook like useMemo, but without unloading.
4
4
  */
@@ -12,7 +12,7 @@ export function deepEqual(a, b) {
12
12
  }
13
13
  for (let i = 0; i < keysA.length; i++) {
14
14
  const key = keysA[i];
15
- // @ts-ignore
15
+ // @ts-expect-error — indexing with dynamic key on generic object
16
16
  if (!Object.prototype.hasOwnProperty.call(b, key) || !deepEqual(a[key], b[key])) {
17
17
  return false;
18
18
  }
@@ -1,3 +1,3 @@
1
- export * from './PromiseResolver';
2
- export * from './deepEqual';
3
- export * from './shallowEqual';
1
+ export * from "./PromiseResolver";
2
+ export * from "./deepEqual";
3
+ export * from "./shallowEqual";
@@ -1,3 +1,3 @@
1
- export * from './PromiseResolver';
2
- export * from './deepEqual';
3
- export * from './shallowEqual';
1
+ export * from "./PromiseResolver";
2
+ export * from "./deepEqual";
3
+ export * from "./shallowEqual";
@@ -12,7 +12,7 @@ export function shallowEqual(a, b) {
12
12
  }
13
13
  for (let i = 0; i < keysA.length; i++) {
14
14
  const key = keysA[i];
15
- // @ts-ignore
15
+ // @ts-expect-error — indexing with dynamic key on generic object
16
16
  if (!Object.prototype.hasOwnProperty.call(b, key) || a[key] !== b[key]) {
17
17
  return false;
18
18
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export * from './common/devtools';
2
- export * from './common/options';
3
- export * from './common/react';
4
- export * from './common/utils/deepEqual';
5
- export * from './common/utils/shallowEqual';
6
- export * from './query';
7
- export * from './signals';
1
+ export * from "./common/devtools";
2
+ export * from "./common/options";
3
+ export * from "./common/react";
4
+ export * from "./common/utils/deepEqual";
5
+ export * from "./common/utils/shallowEqual";
6
+ export * from "./query";
7
+ export * from "./signals";
8
+ export * as unstable_queryV2 from "./query-v2";
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
- export * from './common/devtools';
2
- export * from './common/options';
3
- export * from './common/react';
4
- export * from './common/utils/deepEqual';
5
- export * from './common/utils/shallowEqual';
6
- export * from './query';
7
- export * from './signals';
1
+ export * from "./common/devtools";
2
+ export * from "./common/options";
3
+ export * from "./common/react";
4
+ export * from "./common/utils/deepEqual";
5
+ export * from "./common/utils/shallowEqual";
6
+ export * from "./query";
7
+ export * from "./signals";
8
+ export * as unstable_queryV2 from "./query-v2";
@@ -1 +1 @@
1
- export const SKIP = Symbol('SKIP');
1
+ export const SKIP = Symbol("SKIP");
@@ -1,5 +1,5 @@
1
- import type { CommandCreateOptions, CommandDefinition } from "../../query/types";
2
1
  import { Command } from "../../query/core/Command/Command";
2
+ import type { CommandCreateOptions, CommandDefinition } from "../../query/types";
3
3
  /**
4
4
  * Создаёт команду (command) — единицу мутирующего запроса.
5
5
  *
@@ -2,4 +2,4 @@
2
2
  * @deprecated Use `createCommand` instead. Will be removed in v0.6.0.
3
3
  * @see createCommand
4
4
  */
5
- export declare const createOperation: <ARGS, RESULT, SELECTED = never>(options: import("../types").CommandCreateOptions<import("../types").CommandDefinition<ARGS, RESULT, SELECTED>>) => import("../core/Command").Command<import("../types").CommandDefinition<ARGS, RESULT, SELECTED>>;
5
+ export declare const createOperation: <ARGS, RESULT, SELECTED = never>(options: import("..").CommandCreateOptions<import("..").CommandDefinition<ARGS, RESULT, SELECTED>>) => import("../core/Command").Command<import("..").CommandDefinition<ARGS, RESULT, SELECTED>>;
@@ -1,4 +1,4 @@
1
- import { createCommand } from './createCommand';
1
+ import { createCommand } from "./createCommand";
2
2
  /**
3
3
  * @deprecated Use `createCommand` instead. Will be removed in v0.6.0.
4
4
  * @see createCommand
@@ -1,3 +1,3 @@
1
- import type { ResourceCreateOptions, ResourceDefinition } from "../../query/types";
2
1
  import { Resource } from "../../query/core/Resource/Resource";
2
+ import type { ResourceCreateOptions, ResourceDefinition } from "../../query/types";
3
3
  export declare const createResource: <ARGS, RESULT, SELECTED = never>(options: ResourceCreateOptions<ResourceDefinition<ARGS, RESULT, SELECTED>>) => Resource<ResourceDefinition<ARGS, RESULT, SELECTED>>;
@@ -1,4 +1,4 @@
1
- import { DuplicatorOptions, ResourceDuplicator, DuplicatorDefinition } from "../../query/core/Resource/ResourceDuplicator";
1
+ import { DuplicatorDefinition, DuplicatorOptions, ResourceDuplicator } from "../../query/core/Resource/ResourceDuplicator";
2
2
  import { ResourceDefinition } from "../../query/types";
3
3
  export declare const createResourceDuplicator: <ARGS, RESULT, SELECTED = never>(options: DuplicatorOptions<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>) => ResourceDuplicator<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>;
4
4
  export type ResourceDuplicatorCreateFn<ARGS, RESULT, SELECTED = never> = (options: DuplicatorOptions<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>) => ResourceDuplicator<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>;