synapse-storage 4.1.2 → 5.0.3

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 (289) hide show
  1. package/README.md +142 -12
  2. package/dist/_utils/chunk.util.d.ts +0 -1
  3. package/dist/_utils/deepMerge.util.d.ts +0 -1
  4. package/dist/_utils/error-handling.util.d.ts +0 -1
  5. package/dist/_utils/flatMap.util.d.ts +0 -1
  6. package/dist/_utils/index.d.ts +0 -1
  7. package/dist/_utils/logger-console.util.d.ts +0 -1
  8. package/dist/api/api.module.d.ts +0 -1
  9. package/dist/api/components/endpoint.d.ts +11 -12
  10. package/dist/api/components/endpoint.js.map +1 -1
  11. package/dist/api/components/query-storage.d.ts +0 -1
  12. package/dist/api/components/query-storage.js +1 -1
  13. package/dist/api/components/query-storage.js.map +1 -1
  14. package/dist/api/index.d.ts +0 -1
  15. package/dist/api/types/api.interface.d.ts +0 -1
  16. package/dist/api/types/endpoint.interface.d.ts +0 -1
  17. package/dist/api/types/query.interface.d.ts +0 -1
  18. package/dist/api/utils/api-helpers.d.ts +0 -1
  19. package/dist/{core/storage → api}/utils/cache.util.d.ts +3 -6
  20. package/dist/{core/storage → api}/utils/cache.util.js +4 -7
  21. package/dist/api/utils/cache.util.js.map +1 -0
  22. package/dist/api/utils/create-header-context.d.ts +0 -1
  23. package/dist/api/utils/endpoint-headers.d.ts +0 -1
  24. package/dist/api/utils/fetch-base-query.d.ts +0 -1
  25. package/dist/api/utils/file-utils.d.ts +0 -1
  26. package/dist/api/utils/get-cacheable-headers.d.ts +0 -1
  27. package/dist/core/index.d.ts +0 -1
  28. package/dist/core/selector/index.d.ts +1 -1
  29. package/dist/core/selector/index.js +2 -0
  30. package/dist/core/selector/index.js.map +1 -1
  31. package/dist/core/selector/selector.interface.d.ts +15 -30
  32. package/dist/core/selector/selector.interface.js +2 -2
  33. package/dist/core/selector/selector.interface.js.map +1 -1
  34. package/dist/core/selector/selector.module.d.ts +16 -1
  35. package/dist/core/selector/selector.module.js +82 -20
  36. package/dist/core/selector/selector.module.js.map +1 -1
  37. package/dist/core/selector/selectors.base.d.ts +56 -0
  38. package/dist/core/selector/selectors.base.js +118 -0
  39. package/dist/core/selector/selectors.base.js.map +1 -0
  40. package/dist/core/storage/adapters/async-base-storage.service.d.ts +15 -4
  41. package/dist/core/storage/adapters/async-base-storage.service.js +106 -36
  42. package/dist/core/storage/adapters/async-base-storage.service.js.map +1 -1
  43. package/dist/core/storage/adapters/indexed-DB.service.d.ts +4 -5
  44. package/dist/core/storage/adapters/indexed-DB.service.js +66 -14
  45. package/dist/core/storage/adapters/indexed-DB.service.js.map +1 -1
  46. package/dist/core/storage/adapters/local-storage.service.d.ts +9 -4
  47. package/dist/core/storage/adapters/local-storage.service.js +25 -5
  48. package/dist/core/storage/adapters/local-storage.service.js.map +1 -1
  49. package/dist/core/storage/adapters/memory-storage.service.d.ts +2 -4
  50. package/dist/core/storage/adapters/memory-storage.service.js +5 -5
  51. package/dist/core/storage/adapters/memory-storage.service.js.map +1 -1
  52. package/dist/core/storage/adapters/path.utils.d.ts +0 -1
  53. package/dist/core/storage/adapters/storage-core.d.ts +6 -2
  54. package/dist/core/storage/adapters/storage-core.js +6 -3
  55. package/dist/core/storage/adapters/storage-core.js.map +1 -1
  56. package/dist/core/storage/adapters/sync-base-storage.service.d.ts +20 -4
  57. package/dist/core/storage/adapters/sync-base-storage.service.js +110 -35
  58. package/dist/core/storage/adapters/sync-base-storage.service.js.map +1 -1
  59. package/dist/core/storage/index.d.ts +2 -5
  60. package/dist/core/storage/index.js +1 -5
  61. package/dist/core/storage/index.js.map +1 -1
  62. package/dist/core/storage/middlewares/broadcast.middleware.d.ts +0 -1
  63. package/dist/core/storage/middlewares/index.d.ts +3 -1
  64. package/dist/core/storage/middlewares/index.js +6 -0
  65. package/dist/core/storage/middlewares/index.js.map +1 -1
  66. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts +0 -1
  67. package/dist/core/storage/middlewares/storage-logger.middleware.d.ts +20 -0
  68. package/dist/core/storage/middlewares/storage-logger.middleware.js +53 -0
  69. package/dist/core/storage/middlewares/storage-logger.middleware.js.map +1 -0
  70. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts +0 -1
  71. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js +4 -10
  72. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js.map +1 -1
  73. package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts +0 -1
  74. package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts +0 -1
  75. package/dist/core/storage/middlewares/sync-storage-logger.middleware.d.ts +7 -0
  76. package/dist/core/storage/middlewares/sync-storage-logger.middleware.js +48 -0
  77. package/dist/core/storage/middlewares/sync-storage-logger.middleware.js.map +1 -0
  78. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts +0 -1
  79. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js +4 -10
  80. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js.map +1 -1
  81. package/dist/core/storage/modules/singleton/mixin.util.d.ts +0 -1
  82. package/dist/core/storage/modules/singleton/models.d.ts +0 -1
  83. package/dist/core/storage/modules/singleton/singleton.util.d.ts +0 -1
  84. package/dist/core/storage/storage.interface.d.ts +59 -4
  85. package/dist/core/storage/storage.interface.js +0 -2
  86. package/dist/core/storage/storage.interface.js.map +1 -1
  87. package/dist/core/storage/utils/broadcast.util.d.ts +0 -1
  88. package/dist/core/storage/utils/middleware-module.d.ts +0 -3
  89. package/dist/core/storage/utils/middleware-module.js +0 -8
  90. package/dist/core/storage/utils/middleware-module.js.map +1 -1
  91. package/dist/core/storage/utils/migration.util.d.ts +38 -0
  92. package/dist/core/storage/utils/migration.util.js +48 -0
  93. package/dist/core/storage/utils/migration.util.js.map +1 -0
  94. package/dist/core/storage/utils/path-selector.util.d.ts +0 -1
  95. package/dist/core/storage/utils/state-diff.util.d.ts +8 -1
  96. package/dist/core/storage/utils/state-diff.util.js +17 -1
  97. package/dist/core/storage/utils/state-diff.util.js.map +1 -1
  98. package/dist/core/storage/utils/storage-factory.util.d.ts +7 -9
  99. package/dist/core/storage/utils/storage-factory.util.js +10 -10
  100. package/dist/core/storage/utils/storage-factory.util.js.map +1 -1
  101. package/dist/core/storage/utils/storage-key.d.ts +0 -1
  102. package/dist/index.d.ts +0 -1
  103. package/dist/react/hooks/index.d.ts +2 -1
  104. package/dist/react/hooks/index.js +4 -0
  105. package/dist/react/hooks/index.js.map +1 -1
  106. package/dist/react/hooks/useCreateStorage.d.ts +5 -6
  107. package/dist/react/hooks/useCreateStorage.js +2 -2
  108. package/dist/react/hooks/useCreateStorage.js.map +1 -1
  109. package/dist/react/hooks/useObservable.d.ts +17 -0
  110. package/dist/react/hooks/useObservable.js +38 -0
  111. package/dist/react/hooks/useObservable.js.map +1 -0
  112. package/dist/react/hooks/useSelector.d.ts +0 -1
  113. package/dist/react/hooks/useSelector.js +5 -2
  114. package/dist/react/hooks/useSelector.js.map +1 -1
  115. package/dist/react/hooks/useStorage.d.ts +0 -1
  116. package/dist/react/hooks/useStorageSubscribe.d.ts +0 -1
  117. package/dist/react/hooks/useSubscription.d.ts +13 -0
  118. package/dist/react/hooks/useSubscription.js +23 -0
  119. package/dist/react/hooks/useSubscription.js.map +1 -0
  120. package/dist/react/index.d.ts +0 -1
  121. package/dist/react/utils/awaitSynapse.d.ts +9 -10
  122. package/dist/react/utils/awaitSynapse.js +3 -2
  123. package/dist/react/utils/awaitSynapse.js.map +1 -1
  124. package/dist/react/utils/createSynapseCtx.d.ts +18 -23
  125. package/dist/react/utils/createSynapseCtx.js +64 -39
  126. package/dist/react/utils/createSynapseCtx.js.map +1 -1
  127. package/dist/react/utils/index.d.ts +0 -1
  128. package/dist/reactive/dispatcher/dispatcher.base.d.ts +122 -0
  129. package/dist/reactive/dispatcher/dispatcher.base.js +294 -0
  130. package/dist/reactive/dispatcher/dispatcher.base.js.map +1 -0
  131. package/dist/reactive/dispatcher/dispatcher.module.d.ts +12 -67
  132. package/dist/reactive/dispatcher/dispatcher.module.js +13 -72
  133. package/dist/reactive/dispatcher/dispatcher.module.js.map +1 -1
  134. package/dist/reactive/dispatcher/index.d.ts +1 -1
  135. package/dist/reactive/dispatcher/index.js +2 -0
  136. package/dist/reactive/dispatcher/index.js.map +1 -1
  137. package/dist/reactive/dispatcher/middlewares/index.d.ts +0 -1
  138. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts +0 -1
  139. package/dist/reactive/dispatcher/path.util.d.ts +15 -0
  140. package/dist/reactive/dispatcher/path.util.js +34 -0
  141. package/dist/reactive/dispatcher/path.util.js.map +1 -0
  142. package/dist/reactive/dispatcher/standalone.d.ts +1 -150
  143. package/dist/reactive/dispatcher/standalone.js +6 -217
  144. package/dist/reactive/dispatcher/standalone.js.map +1 -1
  145. package/dist/reactive/effects/effects.base.d.ts +62 -0
  146. package/dist/reactive/effects/effects.base.js +90 -0
  147. package/dist/reactive/effects/effects.base.js.map +1 -0
  148. package/dist/reactive/effects/effects.module.d.ts +122 -11
  149. package/dist/reactive/effects/effects.module.js +129 -17
  150. package/dist/reactive/effects/effects.module.js.map +1 -1
  151. package/dist/reactive/effects/index.d.ts +1 -1
  152. package/dist/reactive/effects/index.js +2 -0
  153. package/dist/reactive/effects/index.js.map +1 -1
  154. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts +0 -1
  155. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts +0 -1
  156. package/dist/reactive/effects/utils/fromRequest.d.ts +0 -1
  157. package/dist/reactive/effects/utils/index.d.ts +0 -1
  158. package/dist/reactive/effects/utils/toObservable.d.ts +0 -1
  159. package/dist/reactive/index.d.ts +0 -1
  160. package/dist/utils/createEventBus.d.ts +47 -46
  161. package/dist/utils/createEventBus.js +152 -174
  162. package/dist/utils/createEventBus.js.map +1 -1
  163. package/dist/utils/createSynapse/createSynapse.d.ts +25 -7
  164. package/dist/utils/createSynapse/createSynapse.js +28 -98
  165. package/dist/utils/createSynapse/createSynapse.js.map +1 -1
  166. package/dist/utils/createSynapse/factory.d.ts +6 -0
  167. package/dist/utils/createSynapse/factory.js +256 -0
  168. package/dist/utils/createSynapse/factory.js.map +1 -0
  169. package/dist/utils/createSynapse/index.d.ts +2 -2
  170. package/dist/utils/createSynapse/index.js.map +1 -1
  171. package/dist/utils/createSynapse/synapse.types.d.ts +87 -0
  172. package/dist/utils/createSynapse/synapse.types.js +11 -0
  173. package/dist/utils/createSynapse/synapse.types.js.map +1 -0
  174. package/dist/utils/createSynapse/types.d.ts +6 -85
  175. package/dist/utils/createSynapse/types.js +2 -1
  176. package/dist/utils/createSynapse/types.js.map +1 -1
  177. package/dist/utils/createSynapse/waitForDependencies.d.ts +0 -1
  178. package/dist/utils/createSynapse/waitForDependencies.js +1 -1
  179. package/dist/utils/createSynapse/waitForDependencies.js.map +1 -1
  180. package/dist/utils/createSynapseAwaiter.d.ts +13 -10
  181. package/dist/utils/createSynapseAwaiter.js +30 -3
  182. package/dist/utils/createSynapseAwaiter.js.map +1 -1
  183. package/dist/utils/dehydrateModule.d.ts +6 -0
  184. package/dist/utils/dehydrateModule.js +43 -0
  185. package/dist/utils/dehydrateModule.js.map +1 -0
  186. package/dist/utils/index.d.ts +3 -3
  187. package/dist/utils/index.js +3 -0
  188. package/dist/utils/index.js.map +1 -1
  189. package/package.json +12 -2
  190. package/dist/_utils/chunk.util.d.ts.map +0 -1
  191. package/dist/_utils/deepMerge.util.d.ts.map +0 -1
  192. package/dist/_utils/error-handling.util.d.ts.map +0 -1
  193. package/dist/_utils/flatMap.util.d.ts.map +0 -1
  194. package/dist/_utils/index.d.ts.map +0 -1
  195. package/dist/_utils/logger-console.util.d.ts.map +0 -1
  196. package/dist/api/api.module.d.ts.map +0 -1
  197. package/dist/api/components/endpoint.d.ts.map +0 -1
  198. package/dist/api/components/query-storage.d.ts.map +0 -1
  199. package/dist/api/example.d.ts +0 -83
  200. package/dist/api/example.d.ts.map +0 -1
  201. package/dist/api/example.js +0 -90
  202. package/dist/api/example.js.map +0 -1
  203. package/dist/api/index.d.ts.map +0 -1
  204. package/dist/api/types/api.interface.d.ts.map +0 -1
  205. package/dist/api/types/endpoint.interface.d.ts.map +0 -1
  206. package/dist/api/types/query.interface.d.ts.map +0 -1
  207. package/dist/api/utils/api-helpers.d.ts.map +0 -1
  208. package/dist/api/utils/create-header-context.d.ts.map +0 -1
  209. package/dist/api/utils/endpoint-headers.d.ts.map +0 -1
  210. package/dist/api/utils/fetch-base-query.d.ts.map +0 -1
  211. package/dist/api/utils/file-utils.d.ts.map +0 -1
  212. package/dist/api/utils/get-cacheable-headers.d.ts.map +0 -1
  213. package/dist/core/index.d.ts.map +0 -1
  214. package/dist/core/selector/index.d.ts.map +0 -1
  215. package/dist/core/selector/selector.interface.d.ts.map +0 -1
  216. package/dist/core/selector/selector.module.d.ts.map +0 -1
  217. package/dist/core/storage/adapters/async-base-storage.service.d.ts.map +0 -1
  218. package/dist/core/storage/adapters/indexed-DB.service.d.ts.map +0 -1
  219. package/dist/core/storage/adapters/local-storage.service.d.ts.map +0 -1
  220. package/dist/core/storage/adapters/memory-storage.service.d.ts.map +0 -1
  221. package/dist/core/storage/adapters/path.utils.d.ts.map +0 -1
  222. package/dist/core/storage/adapters/storage-core.d.ts.map +0 -1
  223. package/dist/core/storage/adapters/sync-base-storage.service.d.ts.map +0 -1
  224. package/dist/core/storage/index.d.ts.map +0 -1
  225. package/dist/core/storage/middlewares/broadcast.middleware.d.ts.map +0 -1
  226. package/dist/core/storage/middlewares/index.d.ts.map +0 -1
  227. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts.map +0 -1
  228. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts.map +0 -1
  229. package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts.map +0 -1
  230. package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts.map +0 -1
  231. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts.map +0 -1
  232. package/dist/core/storage/modules/plugin/plugin.interface.d.ts +0 -101
  233. package/dist/core/storage/modules/plugin/plugin.interface.d.ts.map +0 -1
  234. package/dist/core/storage/modules/plugin/plugin.interface.js +0 -8
  235. package/dist/core/storage/modules/plugin/plugin.interface.js.map +0 -1
  236. package/dist/core/storage/modules/plugin/plugin.service.d.ts +0 -49
  237. package/dist/core/storage/modules/plugin/plugin.service.d.ts.map +0 -1
  238. package/dist/core/storage/modules/plugin/plugin.service.js +0 -406
  239. package/dist/core/storage/modules/plugin/plugin.service.js.map +0 -1
  240. package/dist/core/storage/modules/singleton/mixin.util.d.ts.map +0 -1
  241. package/dist/core/storage/modules/singleton/models.d.ts.map +0 -1
  242. package/dist/core/storage/modules/singleton/singleton.util.d.ts.map +0 -1
  243. package/dist/core/storage/storage.interface.d.ts.map +0 -1
  244. package/dist/core/storage/utils/broadcast.util.d.ts.map +0 -1
  245. package/dist/core/storage/utils/cache.util.d.ts.map +0 -1
  246. package/dist/core/storage/utils/cache.util.js.map +0 -1
  247. package/dist/core/storage/utils/middleware-module.d.ts.map +0 -1
  248. package/dist/core/storage/utils/path-selector.util.d.ts.map +0 -1
  249. package/dist/core/storage/utils/state-diff.util.d.ts.map +0 -1
  250. package/dist/core/storage/utils/storage-factory.util.d.ts.map +0 -1
  251. package/dist/core/storage/utils/storage-key.d.ts.map +0 -1
  252. package/dist/core/storage/utils/storage.utils.d.ts +0 -17
  253. package/dist/core/storage/utils/storage.utils.d.ts.map +0 -1
  254. package/dist/core/storage/utils/storage.utils.js +0 -57
  255. package/dist/core/storage/utils/storage.utils.js.map +0 -1
  256. package/dist/index.d.ts.map +0 -1
  257. package/dist/react/hooks/index.d.ts.map +0 -1
  258. package/dist/react/hooks/useCreateStorage.d.ts.map +0 -1
  259. package/dist/react/hooks/useSelector.d.ts.map +0 -1
  260. package/dist/react/hooks/useStorage.d.ts.map +0 -1
  261. package/dist/react/hooks/useStorageSubscribe.d.ts.map +0 -1
  262. package/dist/react/index.d.ts.map +0 -1
  263. package/dist/react/utils/awaitSynapse.d.ts.map +0 -1
  264. package/dist/react/utils/createSynapseCtx.d.ts.map +0 -1
  265. package/dist/react/utils/index.d.ts.map +0 -1
  266. package/dist/reactive/dispatcher/dispatcher.module.d.ts.map +0 -1
  267. package/dist/reactive/dispatcher/index.d.ts.map +0 -1
  268. package/dist/reactive/dispatcher/middlewares/index.d.ts.map +0 -1
  269. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts.map +0 -1
  270. package/dist/reactive/dispatcher/standalone.d.ts.map +0 -1
  271. package/dist/reactive/effects/effects.module.d.ts.map +0 -1
  272. package/dist/reactive/effects/index.d.ts.map +0 -1
  273. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts.map +0 -1
  274. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts.map +0 -1
  275. package/dist/reactive/effects/utils/fromRequest.d.ts.map +0 -1
  276. package/dist/reactive/effects/utils/index.d.ts.map +0 -1
  277. package/dist/reactive/effects/utils/toObservable.d.ts.map +0 -1
  278. package/dist/reactive/index.d.ts.map +0 -1
  279. package/dist/utils/createEventBus.d.ts.map +0 -1
  280. package/dist/utils/createSynapse/createSynapse.d.ts.map +0 -1
  281. package/dist/utils/createSynapse/index.d.ts.map +0 -1
  282. package/dist/utils/createSynapse/types.d.ts.map +0 -1
  283. package/dist/utils/createSynapse/validate.d.ts +0 -2
  284. package/dist/utils/createSynapse/validate.d.ts.map +0 -1
  285. package/dist/utils/createSynapse/validate.js +0 -76
  286. package/dist/utils/createSynapse/validate.js.map +0 -1
  287. package/dist/utils/createSynapse/waitForDependencies.d.ts.map +0 -1
  288. package/dist/utils/createSynapseAwaiter.d.ts.map +0 -1
  289. package/dist/utils/index.d.ts.map +0 -1
@@ -0,0 +1,38 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+
3
+
4
+
5
+ /**
6
+ * Подписка на Observable из компонента.
7
+ *
8
+ * `source` — либо готовый `Observable<T>` (например `selector.$`), либо фабрика
9
+ * `() => Observable<T>`, собирающая цепочку (`pipe(debounceTime(...))`) при подписке.
10
+ *
11
+ * До первого эмита возвращается `initialValue`. Подписка снимается на unmount и
12
+ * пересоздаётся при смене `deps` (вся цепочка строится заново — актуально для
13
+ * операторов с состоянием вроде `debounceTime`/`scan`). Если `deps` не переданы:
14
+ * для прямого Observable цепочка пересоздаётся при смене ссылки `source`, для
15
+ * фабрики — создаётся один раз.
16
+ *
17
+ * @template T тип значения потока
18
+ */ function useObservable(source, initialValue, deps) {
19
+ const [value, setValue] = useState(initialValue);
20
+ // Держим source в ref, чтобы замыкание эффекта всегда читало актуальную фабрику,
21
+ // но переподписка управлялась исключительно через deps.
22
+ const sourceRef = useRef(source);
23
+ sourceRef.current = source;
24
+ const effectDeps = deps ?? (typeof source === 'function' ? [] : [
25
+ source
26
+ ]);
27
+ useEffect(()=>{
28
+ const current = sourceRef.current;
29
+ const observable = typeof current === 'function' ? current() : current;
30
+ const subscription = observable.subscribe((next)=>setValue(next));
31
+ return ()=>subscription.unsubscribe();
32
+ }, effectDeps);
33
+ return value;
34
+ }
35
+
36
+ export { useObservable };
37
+
38
+ //# sourceMappingURL=useObservable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react/hooks/useObservable.js","sources":["../../../src/react/hooks/useObservable.ts"],"sourcesContent":["import { DependencyList, useEffect, useRef, useState } from 'react'\nimport { Observable } from 'rxjs'\n\n/**\n * Подписка на Observable из компонента.\n *\n * `source` — либо готовый `Observable<T>` (например `selector.$`), либо фабрика\n * `() => Observable<T>`, собирающая цепочку (`pipe(debounceTime(...))`) при подписке.\n *\n * До первого эмита возвращается `initialValue`. Подписка снимается на unmount и\n * пересоздаётся при смене `deps` (вся цепочка строится заново — актуально для\n * операторов с состоянием вроде `debounceTime`/`scan`). Если `deps` не переданы:\n * для прямого Observable цепочка пересоздаётся при смене ссылки `source`, для\n * фабрики — создаётся один раз.\n *\n * @template T тип значения потока\n */\nexport function useObservable<T>(source: Observable<T> | (() => Observable<T>), initialValue: T, deps?: DependencyList): T {\n const [value, setValue] = useState<T>(initialValue)\n\n // Держим source в ref, чтобы замыкание эффекта всегда читало актуальную фабрику,\n // но переподписка управлялась исключительно через deps.\n const sourceRef = useRef(source)\n sourceRef.current = source\n\n const effectDeps = deps ?? (typeof source === 'function' ? [] : [source])\n\n useEffect(() => {\n const current = sourceRef.current\n const observable = typeof current === 'function' ? (current as () => Observable<T>)() : current\n const subscription = observable.subscribe((next) => setValue(next))\n return () => subscription.unsubscribe()\n }, effectDeps)\n\n return value\n}\n"],"names":["useEffect","useRef","useState","useObservable","source","initialValue","deps","value","setValue","sourceRef","effectDeps","current","observable","subscription","next"],"mappings":";;;AAAmE;AAGnE;;;;;;;;;;;;;CAaC,GACM,SAASG,aAAaA,CAAIC,MAA6C,EAAEC,YAAe,EAAEC,IAAqB;IACpH,MAAM,CAACC,OAAOC,SAAS,GAAGN,QAAQA,CAAIG;IAEtC,iFAAiF;IACjF,wDAAwD;IACxD,MAAMI,YAAYR,MAAMA,CAACG;IACzBK,UAAU,OAAO,GAAGL;IAEpB,MAAMM,aAAaJ,QAAS,QAAOF,WAAW,aAAa,EAAE,GAAG;QAACA;KAAM;IAEvEJ,SAASA,CAAC;QACR,MAAMW,UAAUF,UAAU,OAAO;QACjC,MAAMG,aAAa,OAAOD,YAAY,aAAcA,YAAoCA;QACxF,MAAME,eAAeD,WAAW,SAAS,CAAC,CAACE,OAASN,SAASM;QAC7D,OAAO,IAAMD,aAAa,WAAW;IACvC,GAAGH;IAEH,OAAOH;AACT"}
@@ -33,4 +33,3 @@ export declare function useSelector<T>(selector: SelectorAPI<T>, options: UseSel
33
33
  */
34
34
  export declare function useKeyedSliceSelector<V>(selector: SelectorAPI<Record<string, V>>, key: string, fallback: V): V;
35
35
  export {};
36
- //# sourceMappingURL=useSelector.d.ts.map
@@ -27,7 +27,10 @@ function useSelector(selector, options) {
27
27
  }, [
28
28
  selector
29
29
  ]);
30
- const value = useSyncExternalStore(subscribe, getSnapshot);
30
+ // getServerSnapshot === getSnapshot: на сервере `selectSync()` синхронно читает
31
+ // засеянный (hydrate) стор. Без серверного снапшота useSyncExternalStore на сервере
32
+ // падает и откатывается на client-only рендер (контент не попадает в SSR-HTML).
33
+ const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
31
34
  // Подписка на статус готовности storage (используется только при withLoading)
32
35
  const subscribeToStatus = useCallback((onStoreChange)=>{
33
36
  return selector.onSourceStatusChange(()=>{
@@ -41,7 +44,7 @@ function useSelector(selector, options) {
41
44
  }, [
42
45
  selector
43
46
  ]);
44
- const isLoading = useSyncExternalStore(subscribeToStatus, getStatusSnapshot);
47
+ const isLoading = useSyncExternalStore(subscribeToStatus, getStatusSnapshot, getStatusSnapshot);
45
48
  if (options?.withLoading) {
46
49
  return {
47
50
  data: value,
@@ -1 +1 @@
1
- {"version":3,"file":"react/hooks/useSelector.js","sources":["../../../src/react/hooks/useSelector.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { SelectorAPI } from '../../core'\n\ninterface UseSelectorOptions<T> {\n /** Функция сравнения для предотвращения лишних ререндеров */\n equals?: (a: T, b: T) => boolean\n /** Включать ли статус загрузки в возвращаемый результат */\n withLoading?: boolean\n}\n\n/**\n * Хук для использования селекторов в компонентах React.\n * Использует useSyncExternalStore для корректной работы в Concurrent Mode.\n * Подписывается напрямую через selector.subscribe() — без глобального реестра.\n */\nexport function useSelector<T>(selector: SelectorAPI<T>): T\nexport function useSelector<T>(selector: SelectorAPI<T>, options: UseSelectorOptions<T> & { withLoading: true }): { data: T; isLoading: boolean }\nexport function useSelector<T>(selector: SelectorAPI<T>, options: UseSelectorOptions<T> & { withLoading?: false }): T\nexport function useSelector<T>(selector: SelectorAPI<T>, options?: UseSelectorOptions<T>): { data: T; isLoading: boolean } | T {\n const equalsRef = useRef(options?.equals)\n\n // Кеш для мемоизации результата getSnapshot (предотвращает лишние ререндеры)\n const cachedRef = useRef<T | undefined>(undefined)\n\n const subscribe = useCallback(\n (onStoreChange: VoidFunction) => {\n return selector.subscribe({\n notify: () => {\n onStoreChange()\n },\n })\n },\n [selector],\n )\n\n const getSnapshot = useCallback((): T => {\n const value = selector.selectSync()\n\n // Если есть пользовательская функция сравнения — мемоизируем\n const equals = equalsRef.current\n if (equals && cachedRef.current !== undefined && equals(cachedRef.current, value)) {\n return cachedRef.current\n }\n\n cachedRef.current = value\n return value\n }, [selector])\n\n const value = useSyncExternalStore(subscribe, getSnapshot)\n\n // Подписка на статус готовности storage (используется только при withLoading)\n const subscribeToStatus = useCallback(\n (onStoreChange: VoidFunction) => {\n return selector.onSourceStatusChange(() => {\n onStoreChange()\n })\n },\n [selector],\n )\n\n const getStatusSnapshot = useCallback((): boolean => {\n return !selector.isSourceReady()\n }, [selector])\n\n const isLoading = useSyncExternalStore(subscribeToStatus, getStatusSnapshot)\n\n if (options?.withLoading) {\n return { data: value, isLoading }\n }\n\n return value\n}\n\n/**\n * Изоляция ре-рендеров для keyed-map стора (паттерн «equals»). Подписка идёт на\n * ВЕСЬ map (`selector`), но `equals` сравнивает только срез по `key` → компонент\n * ре-рендерится лишь когда меняется его `map[key]` по ссылке. Работает, т.к.\n * иммутабельные мутации по одному ключу не трогают ссылку чужих срезов.\n * Гранулярность живёт в месте вызова, а селекторы остаются плоскими (без фабрик\n * с `Map<key, selector>`).\n *\n * `fallback` ОБЯЗАН быть стабильной ссылкой (module-level константа), иначе\n * `?? fallback` будет давать новый объект каждый тик и рвать нижестоящие `useMemo`.\n */\nexport function useKeyedSliceSelector<V>(selector: SelectorAPI<Record<string, V>>, key: string, fallback: V): V {\n const map = useSelector(selector, {\n equals: (a, b) => a[key] === b[key],\n })\n return map[key] ?? fallback\n}\n"],"names":["useCallback","useRef","useSyncExternalStore","useSelector","selector","options","equalsRef","cachedRef","undefined","subscribe","onStoreChange","getSnapshot","value","equals","subscribeToStatus","getStatusSnapshot","isLoading","useKeyedSliceSelector","key","fallback","map","a","b"],"mappings":";;;AAAiE;AAmB1D,SAASG,WAAWA,CAAIC,QAAwB,EAAEC,OAA+B;IACtF,MAAMC,YAAYL,MAAMA,CAACI,SAAS;IAElC,6EAA6E;IAC7E,MAAME,YAAYN,MAAMA,CAAgBO;IAExC,MAAMC,YAAYT,WAAWA,CAC3B,CAACU;QACC,OAAON,SAAS,SAAS,CAAC;YACxB,QAAQ;gBACNM;YACF;QACF;IACF,GACA;QAACN;KAAS;IAGZ,MAAMO,cAAcX,WAAWA,CAAC;QAC9B,MAAMY,QAAQR,SAAS,UAAU;QAEjC,6DAA6D;QAC7D,MAAMS,SAASP,UAAU,OAAO;QAChC,IAAIO,UAAUN,UAAU,OAAO,KAAKC,aAAaK,OAAON,UAAU,OAAO,EAAEK,QAAQ;YACjF,OAAOL,UAAU,OAAO;QAC1B;QAEAA,UAAU,OAAO,GAAGK;QACpB,OAAOA;IACT,GAAG;QAACR;KAAS;IAEb,MAAMQ,QAAQV,oBAAoBA,CAACO,WAAWE;IAE9C,8EAA8E;IAC9E,MAAMG,oBAAoBd,WAAWA,CACnC,CAACU;QACC,OAAON,SAAS,oBAAoB,CAAC;YACnCM;QACF;IACF,GACA;QAACN;KAAS;IAGZ,MAAMW,oBAAoBf,WAAWA,CAAC;QACpC,OAAO,CAACI,SAAS,aAAa;IAChC,GAAG;QAACA;KAAS;IAEb,MAAMY,YAAYd,oBAAoBA,CAACY,mBAAmBC;IAE1D,IAAIV,SAAS,aAAa;QACxB,OAAO;YAAE,MAAMO;YAAOI;QAAU;IAClC;IAEA,OAAOJ;AACT;AAEA;;;;;;;;;;CAUC,GACM,SAASK,qBAAqBA,CAAIb,QAAwC,EAAEc,GAAW,EAAEC,QAAW;IACzG,MAAMC,MAAMjB,WAAWA,CAACC,UAAU;QAChC,QAAQ,CAACiB,GAAGC,IAAMD,CAAC,CAACH,IAAI,KAAKI,CAAC,CAACJ,IAAI;IACrC;IACA,OAAOE,GAAG,CAACF,IAAI,IAAIC;AACrB"}
1
+ {"version":3,"file":"react/hooks/useSelector.js","sources":["../../../src/react/hooks/useSelector.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { SelectorAPI } from '../../core'\n\ninterface UseSelectorOptions<T> {\n /** Функция сравнения для предотвращения лишних ререндеров */\n equals?: (a: T, b: T) => boolean\n /** Включать ли статус загрузки в возвращаемый результат */\n withLoading?: boolean\n}\n\n/**\n * Хук для использования селекторов в компонентах React.\n * Использует useSyncExternalStore для корректной работы в Concurrent Mode.\n * Подписывается напрямую через selector.subscribe() — без глобального реестра.\n */\nexport function useSelector<T>(selector: SelectorAPI<T>): T\nexport function useSelector<T>(selector: SelectorAPI<T>, options: UseSelectorOptions<T> & { withLoading: true }): { data: T; isLoading: boolean }\nexport function useSelector<T>(selector: SelectorAPI<T>, options: UseSelectorOptions<T> & { withLoading?: false }): T\nexport function useSelector<T>(selector: SelectorAPI<T>, options?: UseSelectorOptions<T>): { data: T; isLoading: boolean } | T {\n const equalsRef = useRef(options?.equals)\n\n // Кеш для мемоизации результата getSnapshot (предотвращает лишние ререндеры)\n const cachedRef = useRef<T | undefined>(undefined)\n\n const subscribe = useCallback(\n (onStoreChange: VoidFunction) => {\n return selector.subscribe({\n notify: () => {\n onStoreChange()\n },\n })\n },\n [selector],\n )\n\n const getSnapshot = useCallback((): T => {\n const value = selector.selectSync()\n\n // Если есть пользовательская функция сравнения — мемоизируем\n const equals = equalsRef.current\n if (equals && cachedRef.current !== undefined && equals(cachedRef.current, value)) {\n return cachedRef.current\n }\n\n cachedRef.current = value\n return value\n }, [selector])\n\n // getServerSnapshot === getSnapshot: на сервере `selectSync()` синхронно читает\n // засеянный (hydrate) стор. Без серверного снапшота useSyncExternalStore на сервере\n // падает и откатывается на client-only рендер (контент не попадает в SSR-HTML).\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n // Подписка на статус готовности storage (используется только при withLoading)\n const subscribeToStatus = useCallback(\n (onStoreChange: VoidFunction) => {\n return selector.onSourceStatusChange(() => {\n onStoreChange()\n })\n },\n [selector],\n )\n\n const getStatusSnapshot = useCallback((): boolean => {\n return !selector.isSourceReady()\n }, [selector])\n\n const isLoading = useSyncExternalStore(subscribeToStatus, getStatusSnapshot, getStatusSnapshot)\n\n if (options?.withLoading) {\n return { data: value, isLoading }\n }\n\n return value\n}\n\n/**\n * Изоляция ре-рендеров для keyed-map стора (паттерн «equals»). Подписка идёт на\n * ВЕСЬ map (`selector`), но `equals` сравнивает только срез по `key` → компонент\n * ре-рендерится лишь когда меняется его `map[key]` по ссылке. Работает, т.к.\n * иммутабельные мутации по одному ключу не трогают ссылку чужих срезов.\n * Гранулярность живёт в месте вызова, а селекторы остаются плоскими (без фабрик\n * с `Map<key, selector>`).\n *\n * `fallback` ОБЯЗАН быть стабильной ссылкой (module-level константа), иначе\n * `?? fallback` будет давать новый объект каждый тик и рвать нижестоящие `useMemo`.\n */\nexport function useKeyedSliceSelector<V>(selector: SelectorAPI<Record<string, V>>, key: string, fallback: V): V {\n const map = useSelector(selector, {\n equals: (a, b) => a[key] === b[key],\n })\n return map[key] ?? fallback\n}\n"],"names":["useCallback","useRef","useSyncExternalStore","useSelector","selector","options","equalsRef","cachedRef","undefined","subscribe","onStoreChange","getSnapshot","value","equals","subscribeToStatus","getStatusSnapshot","isLoading","useKeyedSliceSelector","key","fallback","map","a","b"],"mappings":";;;AAAiE;AAmB1D,SAASG,WAAWA,CAAIC,QAAwB,EAAEC,OAA+B;IACtF,MAAMC,YAAYL,MAAMA,CAACI,SAAS;IAElC,6EAA6E;IAC7E,MAAME,YAAYN,MAAMA,CAAgBO;IAExC,MAAMC,YAAYT,WAAWA,CAC3B,CAACU;QACC,OAAON,SAAS,SAAS,CAAC;YACxB,QAAQ;gBACNM;YACF;QACF;IACF,GACA;QAACN;KAAS;IAGZ,MAAMO,cAAcX,WAAWA,CAAC;QAC9B,MAAMY,QAAQR,SAAS,UAAU;QAEjC,6DAA6D;QAC7D,MAAMS,SAASP,UAAU,OAAO;QAChC,IAAIO,UAAUN,UAAU,OAAO,KAAKC,aAAaK,OAAON,UAAU,OAAO,EAAEK,QAAQ;YACjF,OAAOL,UAAU,OAAO;QAC1B;QAEAA,UAAU,OAAO,GAAGK;QACpB,OAAOA;IACT,GAAG;QAACR;KAAS;IAEb,gFAAgF;IAChF,oFAAoF;IACpF,gFAAgF;IAChF,MAAMQ,QAAQV,oBAAoBA,CAACO,WAAWE,aAAaA;IAE3D,8EAA8E;IAC9E,MAAMG,oBAAoBd,WAAWA,CACnC,CAACU;QACC,OAAON,SAAS,oBAAoB,CAAC;YACnCM;QACF;IACF,GACA;QAACN;KAAS;IAGZ,MAAMW,oBAAoBf,WAAWA,CAAC;QACpC,OAAO,CAACI,SAAS,aAAa;IAChC,GAAG;QAACA;KAAS;IAEb,MAAMY,YAAYd,oBAAoBA,CAACY,mBAAmBC,mBAAmBA;IAE7E,IAAIV,SAAS,aAAa;QACxB,OAAO;YAAE,MAAMO;YAAOI;QAAU;IAClC;IAEA,OAAOJ;AACT;AAEA;;;;;;;;;;CAUC,GACM,SAASK,qBAAqBA,CAAIb,QAAwC,EAAEc,GAAW,EAAEC,QAAW;IACzG,MAAMC,MAAMjB,WAAWA,CAACC,UAAU;QAChC,QAAQ,CAACiB,GAAGC,IAAMD,CAAC,CAACH,IAAI,KAAKI,CAAC,CAACJ,IAAI;IACrC;IACA,OAAOE,GAAG,CAACF,IAAI,IAAIC;AACrB"}
@@ -36,4 +36,3 @@ export type UseStorageReturn<S> = {
36
36
  * ```
37
37
  */
38
38
  export declare function useStorage<S extends IStorageBase<any>>(storage: S, options?: UseStorageOptions): UseStorageReturn<S>;
39
- //# sourceMappingURL=useStorage.d.ts.map
@@ -13,4 +13,3 @@ import { IStorageBase } from '../../core';
13
13
  * @returns Значение из хранилища
14
14
  */
15
15
  export declare const useStorageSubscribe: <S extends Record<string, any>, R = any>(storage: IStorageBase<S> | null, selector: (state: S) => R) => R | undefined;
16
- //# sourceMappingURL=useStorageSubscribe.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { DependencyList } from 'react';
2
+ import { Unsubscribable } from 'rxjs';
3
+ /**
4
+ * Императивная подписка-side-effect без возврата значения в рендер.
5
+ *
6
+ * `factory` создаёт подписку (`source$.subscribe(...)`) — её side-effect'ы (логирование,
7
+ * императивные вызовы, диспатч) живут внутри коллбэка `subscribe`. Возвращённый
8
+ * `Unsubscribable` снимается на unmount и при смене `deps` (перед созданием новой
9
+ * подписки).
10
+ *
11
+ * В отличие от `useObservable`, ничего не рендерит — только запускает и гасит подписку.
12
+ */
13
+ export declare function useSubscription(factory: () => Unsubscribable, deps: DependencyList): void;
@@ -0,0 +1,23 @@
1
+ import { useEffect } from "react";
2
+
3
+
4
+
5
+ /**
6
+ * Императивная подписка-side-effect без возврата значения в рендер.
7
+ *
8
+ * `factory` создаёт подписку (`source$.subscribe(...)`) — её side-effect'ы (логирование,
9
+ * императивные вызовы, диспатч) живут внутри коллбэка `subscribe`. Возвращённый
10
+ * `Unsubscribable` снимается на unmount и при смене `deps` (перед созданием новой
11
+ * подписки).
12
+ *
13
+ * В отличие от `useObservable`, ничего не рендерит — только запускает и гасит подписку.
14
+ */ function useSubscription(factory, deps) {
15
+ useEffect(()=>{
16
+ const subscription = factory();
17
+ return ()=>subscription.unsubscribe();
18
+ }, deps);
19
+ }
20
+
21
+ export { useSubscription };
22
+
23
+ //# sourceMappingURL=useSubscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react/hooks/useSubscription.js","sources":["../../../src/react/hooks/useSubscription.ts"],"sourcesContent":["import { DependencyList, useEffect } from 'react'\nimport { Unsubscribable } from 'rxjs'\n\n/**\n * Императивная подписка-side-effect без возврата значения в рендер.\n *\n * `factory` создаёт подписку (`source$.subscribe(...)`) — её side-effect'ы (логирование,\n * императивные вызовы, диспатч) живут внутри коллбэка `subscribe`. Возвращённый\n * `Unsubscribable` снимается на unmount и при смене `deps` (перед созданием новой\n * подписки).\n *\n * В отличие от `useObservable`, ничего не рендерит — только запускает и гасит подписку.\n */\nexport function useSubscription(factory: () => Unsubscribable, deps: DependencyList): void {\n useEffect(() => {\n const subscription = factory()\n return () => subscription.unsubscribe()\n }, deps)\n}\n"],"names":["useEffect","useSubscription","factory","deps","subscription"],"mappings":";;;AAAiD;AAGjD;;;;;;;;;CASC,GACM,SAASC,eAAeA,CAACC,OAA6B,EAAEC,IAAoB;IACjFH,SAASA,CAAC;QACR,MAAMI,eAAeF;QACrB,OAAO,IAAME,aAAa,WAAW;IACvC,GAAGD;AACL"}
@@ -1,3 +1,2 @@
1
1
  export * from './hooks';
2
2
  export * from './utils';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,15 +1,15 @@
1
1
  import { ComponentType, ReactNode } from 'react';
2
- import { IStorage } from '../../core';
3
- import { AnySynapseStore } from '../../utils';
2
+ import { type AwaitableSynapse } from '../../utils';
4
3
  interface ReactAwaitSynapseOptions {
5
4
  loadingComponent?: ReactNode;
6
5
  errorComponent?: (error: Error) => ReactNode;
7
6
  }
8
7
  /**
9
- * React-обертка для фреймворк-независимой утилиты ожидания Synapse
10
- * Добавляет React-специфичные методы поверх createSynapseAwaiter
8
+ * React-обертка для фреймворк-независимой утилиты ожидания Synapse.
9
+ * Добавляет React-специфичные методы поверх createSynapseAwaiter. Принимает
10
+ * `SynapseModule`-handle (PromiseLike), Promise готового synapse или сам synapse.
11
11
  */
12
- export declare function awaitSynapse<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors = any, TActions = any>(synapseStorePromise: Promise<AnySynapseStore<TStore, TStorage, TSelectors, TActions>> | AnySynapseStore<TStore, TStorage, TSelectors, TActions>, options?: ReactAwaitSynapseOptions): {
12
+ export declare function awaitSynapse<TStore extends AwaitableSynapse>(synapseStorePromise: PromiseLike<TStore> | TStore, options?: ReactAwaitSynapseOptions): {
13
13
  withSynapseReady: <ComponentProps>(Component: ComponentType<ComponentProps>) => {
14
14
  (props: ComponentProps): import("react/jsx-runtime").JSX.Element;
15
15
  displayName: string;
@@ -18,17 +18,16 @@ export declare function awaitSynapse<TStore extends Record<string, any>, TStorag
18
18
  isReady: boolean;
19
19
  isError: boolean;
20
20
  isPending: boolean;
21
- store: AnySynapseStore<TStore, TStorage, TSelectors, TActions> | undefined;
21
+ store: TStore | undefined;
22
22
  error: Error | null;
23
23
  };
24
- waitForReady: () => Promise<AnySynapseStore<TStore, TStorage, TSelectors, TActions>>;
24
+ waitForReady: () => Promise<TStore>;
25
25
  isReady: () => boolean;
26
- getStoreIfReady: () => AnySynapseStore<TStore, TStorage, TSelectors, TActions> | undefined;
27
- onReady: (cb: Parameters<(callback: (store: AnySynapseStore<TStore, TStorage, TSelectors, TActions>) => void) => VoidFunction>[0]) => VoidFunction;
26
+ getStoreIfReady: () => TStore | undefined;
27
+ onReady: (cb: Parameters<(callback: (store: TStore) => void) => VoidFunction>[0]) => VoidFunction;
28
28
  onError: (cb: Parameters<(callback: (error: Error) => void) => VoidFunction>[0]) => VoidFunction;
29
29
  getStatus: () => "error" | "ready" | "pending";
30
30
  getError: () => Error | null;
31
31
  destroy: () => void;
32
32
  };
33
33
  export {};
34
- //# sourceMappingURL=awaitSynapse.d.ts.map
@@ -9,8 +9,9 @@ import { createSynapseAwaiter } from "../../utils/index.js";
9
9
 
10
10
 
11
11
  /**
12
- * React-обертка для фреймворк-независимой утилиты ожидания Synapse
13
- * Добавляет React-специфичные методы поверх createSynapseAwaiter
12
+ * React-обертка для фреймворк-независимой утилиты ожидания Synapse.
13
+ * Добавляет React-специфичные методы поверх createSynapseAwaiter. Принимает
14
+ * `SynapseModule`-handle (PromiseLike), Promise готового synapse или сам synapse.
14
15
  */ function awaitSynapse(synapseStorePromise, options) {
15
16
  const { loadingComponent = /*#__PURE__*/ jsx("div", {
16
17
  children: "Инициализация..."
@@ -1 +1 @@
1
- {"version":3,"file":"react/utils/awaitSynapse.js","sources":["../../../src/react/utils/awaitSynapse.tsx"],"sourcesContent":["import { ComponentType, PropsWithChildren, ReactNode, useEffect, useState } from 'react'\n\nimport { IStorage } from '../../core'\nimport { AnySynapseStore, createSynapseAwaiter } from '../../utils'\n\ninterface ReactAwaitSynapseOptions {\n loadingComponent?: ReactNode\n errorComponent?: (error: Error) => ReactNode\n}\n\n/**\n * React-обертка для фреймворк-независимой утилиты ожидания Synapse\n * Добавляет React-специфичные методы поверх createSynapseAwaiter\n */\nexport function awaitSynapse<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors = any, TActions = any>(\n synapseStorePromise: Promise<AnySynapseStore<TStore, TStorage, TSelectors, TActions>> | AnySynapseStore<TStore, TStorage, TSelectors, TActions>,\n options?: ReactAwaitSynapseOptions,\n) {\n const { loadingComponent = <div>Инициализация...</div>, errorComponent = (error: Error) => <div>Ошибка инициализации: {error.message}</div> } = options || {}\n\n const awaiter = createSynapseAwaiter(synapseStorePromise)\n\n /**\n * Хук для получения текущего состояния готовности\n */\n function useSynapseReady() {\n const [status, setStatus] = useState<'pending' | 'ready' | 'error'>(() => awaiter.getStatus())\n const [store, setStore] = useState<AnySynapseStore<TStore, TStorage, TSelectors, TActions> | undefined>(() => awaiter.getStoreIfReady())\n const [error, setError] = useState<Error | null>(() => awaiter.getError())\n\n useEffect(() => {\n // Проверяем текущее состояние при монтировании\n const currentStatus = awaiter.getStatus()\n const currentStore = awaiter.getStoreIfReady()\n const currentError = awaiter.getError()\n\n setStatus(currentStatus)\n setStore(currentStore)\n setError(currentError)\n\n // Подписываемся на изменения\n const unsubscribeReady = awaiter.onReady((readyStore) => {\n setStatus('ready')\n setStore(readyStore)\n setError(null)\n })\n\n const unsubscribeError = awaiter.onError((err) => {\n setStatus('error')\n setStore(undefined)\n setError(err)\n })\n\n return () => {\n unsubscribeReady()\n unsubscribeError()\n }\n }, [])\n\n return {\n isReady: status === 'ready',\n isError: status === 'error',\n isPending: status === 'pending',\n store,\n error,\n }\n }\n\n /**\n * Обертка, которая ждет готовности Synapse\n */\n function withSynapseReady<ComponentProps>(Component: ComponentType<ComponentProps>) {\n function WrappedComponent(props: ComponentProps) {\n const { isReady, isError, error } = useSynapseReady()\n\n // Показываем ошибку\n if (isError && error) return <>{errorComponent(error)}</>\n\n // Показываем загрузку\n if (!isReady) return <>{loadingComponent}</>\n\n // Рендерим компонент когда все готово\n return <Component {...(props as PropsWithChildren<ComponentProps>)} />\n }\n\n // Устанавливаем отображаемое имя для отладки\n const componentName = Component.displayName || Component.name || 'Component'\n WrappedComponent.displayName = `AwaitSynapse(${componentName})`\n\n return WrappedComponent\n }\n\n return {\n // React методы\n withSynapseReady,\n useSynapseReady,\n\n // Проксируем все методы из awaiter (обёртки сохраняют контекст при деструктуризации)\n waitForReady: () => awaiter.waitForReady(),\n isReady: () => awaiter.isReady(),\n getStoreIfReady: () => awaiter.getStoreIfReady(),\n onReady: (cb: Parameters<typeof awaiter.onReady>[0]) => awaiter.onReady(cb),\n onError: (cb: Parameters<typeof awaiter.onError>[0]) => awaiter.onError(cb),\n getStatus: () => awaiter.getStatus(),\n getError: () => awaiter.getError(),\n destroy: () => awaiter.destroy(),\n }\n}\n"],"names":["useEffect","useState","createSynapseAwaiter","awaitSynapse","synapseStorePromise","options","loadingComponent","errorComponent","error","awaiter","useSynapseReady","status","setStatus","store","setStore","setError","currentStatus","currentStore","currentError","unsubscribeReady","readyStore","unsubscribeError","err","undefined","withSynapseReady","Component","WrappedComponent","props","isReady","isError","componentName","cb"],"mappings":";;;;;;;;AAAwF;AAGrB;AAOnE;;;CAGC,GACM,SAASG,YAAYA,CAC1BC,mBAA+I,EAC/IC,OAAkC;IAElC,MAAM,EAAEC,iCAAmB,IAAC;kBAAI;MAAsB,EAAEC,iBAAiB,CAACC,sBAAiB,KAAC;;gBAAI;gBAAuBA,MAAM,OAAO;;UAAO,EAAE,GAAGH,WAAW,CAAC;IAE5J,MAAMI,UAAUP,oBAAoBA,CAACE;IAErC;;GAEC,GACD,SAASM;QACP,MAAM,CAACC,QAAQC,UAAU,GAAGX,QAAQA,CAAgC,IAAMQ,QAAQ,SAAS;QAC3F,MAAM,CAACI,OAAOC,SAAS,GAAGb,QAAQA,CAAsE,IAAMQ,QAAQ,eAAe;QACrI,MAAM,CAACD,OAAOO,SAAS,GAAGd,QAAQA,CAAe,IAAMQ,QAAQ,QAAQ;QAEvET,SAASA,CAAC;YACR,+CAA+C;YAC/C,MAAMgB,gBAAgBP,QAAQ,SAAS;YACvC,MAAMQ,eAAeR,QAAQ,eAAe;YAC5C,MAAMS,eAAeT,QAAQ,QAAQ;YAErCG,UAAUI;YACVF,SAASG;YACTF,SAASG;YAET,6BAA6B;YAC7B,MAAMC,mBAAmBV,QAAQ,OAAO,CAAC,CAACW;gBACxCR,UAAU;gBACVE,SAASM;gBACTL,SAAS;YACX;YAEA,MAAMM,mBAAmBZ,QAAQ,OAAO,CAAC,CAACa;gBACxCV,UAAU;gBACVE,SAASS;gBACTR,SAASO;YACX;YAEA,OAAO;gBACLH;gBACAE;YACF;QACF,GAAG,EAAE;QAEL,OAAO;YACL,SAASV,WAAW;YACpB,SAASA,WAAW;YACpB,WAAWA,WAAW;YACtBE;YACAL;QACF;IACF;IAEA;;GAEC,GACD,SAASgB,iBAAiCC,SAAwC;QAChF,SAASC,iBAAiBC,KAAqB;YAC7C,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAErB,KAAK,EAAE,GAAGE;YAEpC,oBAAoB;YACpB,IAAImB,WAAWrB,OAAO,qBAAO;0BAAGD,eAAeC;;YAE/C,sBAAsB;YACtB,IAAI,CAACoB,SAAS,qBAAO;0BAAGtB;;YAExB,sCAAsC;YACtC,qBAAO,IAACmB;gBAAW,GAAIE,KAAK;;QAC9B;QAEA,6CAA6C;QAC7C,MAAMG,gBAAgBL,UAAU,WAAW,IAAIA,UAAU,IAAI,IAAI;QACjEC,iBAAiB,WAAW,GAAG,CAAC,aAAa,EAAEI,cAAc,CAAC,CAAC;QAE/D,OAAOJ;IACT;IAEA,OAAO;QACL,eAAe;QACfF;QACAd;QAEA,qFAAqF;QACrF,cAAc,IAAMD,QAAQ,YAAY;QACxC,SAAS,IAAMA,QAAQ,OAAO;QAC9B,iBAAiB,IAAMA,QAAQ,eAAe;QAC9C,SAAS,CAACsB,KAA8CtB,QAAQ,OAAO,CAACsB;QACxE,SAAS,CAACA,KAA8CtB,QAAQ,OAAO,CAACsB;QACxE,WAAW,IAAMtB,QAAQ,SAAS;QAClC,UAAU,IAAMA,QAAQ,QAAQ;QAChC,SAAS,IAAMA,QAAQ,OAAO;IAChC;AACF"}
1
+ {"version":3,"file":"react/utils/awaitSynapse.js","sources":["../../../src/react/utils/awaitSynapse.tsx"],"sourcesContent":["import { ComponentType, PropsWithChildren, ReactNode, useEffect, useState } from 'react'\n\nimport { type AwaitableSynapse, createSynapseAwaiter } from '../../utils'\n\ninterface ReactAwaitSynapseOptions {\n loadingComponent?: ReactNode\n errorComponent?: (error: Error) => ReactNode\n}\n\n/**\n * React-обертка для фреймворк-независимой утилиты ожидания Synapse.\n * Добавляет React-специфичные методы поверх createSynapseAwaiter. Принимает\n * `SynapseModule`-handle (PromiseLike), Promise готового synapse или сам synapse.\n */\nexport function awaitSynapse<TStore extends AwaitableSynapse>(synapseStorePromise: PromiseLike<TStore> | TStore, options?: ReactAwaitSynapseOptions) {\n const { loadingComponent = <div>Инициализация...</div>, errorComponent = (error: Error) => <div>Ошибка инициализации: {error.message}</div> } = options || {}\n\n const awaiter = createSynapseAwaiter<TStore>(synapseStorePromise)\n\n /**\n * Хук для получения текущего состояния готовности\n */\n function useSynapseReady() {\n const [status, setStatus] = useState<'pending' | 'ready' | 'error'>(() => awaiter.getStatus())\n const [store, setStore] = useState<TStore | undefined>(() => awaiter.getStoreIfReady())\n const [error, setError] = useState<Error | null>(() => awaiter.getError())\n\n useEffect(() => {\n // Проверяем текущее состояние при монтировании\n const currentStatus = awaiter.getStatus()\n const currentStore = awaiter.getStoreIfReady()\n const currentError = awaiter.getError()\n\n setStatus(currentStatus)\n setStore(currentStore)\n setError(currentError)\n\n // Подписываемся на изменения\n const unsubscribeReady = awaiter.onReady((readyStore) => {\n setStatus('ready')\n setStore(readyStore)\n setError(null)\n })\n\n const unsubscribeError = awaiter.onError((err) => {\n setStatus('error')\n setStore(undefined)\n setError(err)\n })\n\n return () => {\n unsubscribeReady()\n unsubscribeError()\n }\n }, [])\n\n return {\n isReady: status === 'ready',\n isError: status === 'error',\n isPending: status === 'pending',\n store,\n error,\n }\n }\n\n /**\n * Обертка, которая ждет готовности Synapse\n */\n function withSynapseReady<ComponentProps>(Component: ComponentType<ComponentProps>) {\n function WrappedComponent(props: ComponentProps) {\n const { isReady, isError, error } = useSynapseReady()\n\n // Показываем ошибку\n if (isError && error) return <>{errorComponent(error)}</>\n\n // Показываем загрузку\n if (!isReady) return <>{loadingComponent}</>\n\n // Рендерим компонент когда все готово\n return <Component {...(props as PropsWithChildren<ComponentProps>)} />\n }\n\n // Устанавливаем отображаемое имя для отладки\n const componentName = Component.displayName || Component.name || 'Component'\n WrappedComponent.displayName = `AwaitSynapse(${componentName})`\n\n return WrappedComponent\n }\n\n return {\n // React методы\n withSynapseReady,\n useSynapseReady,\n\n // Проксируем все методы из awaiter (обёртки сохраняют контекст при деструктуризации)\n waitForReady: () => awaiter.waitForReady(),\n isReady: () => awaiter.isReady(),\n getStoreIfReady: () => awaiter.getStoreIfReady(),\n onReady: (cb: Parameters<typeof awaiter.onReady>[0]) => awaiter.onReady(cb),\n onError: (cb: Parameters<typeof awaiter.onError>[0]) => awaiter.onError(cb),\n getStatus: () => awaiter.getStatus(),\n getError: () => awaiter.getError(),\n destroy: () => awaiter.destroy(),\n }\n}\n"],"names":["useEffect","useState","createSynapseAwaiter","awaitSynapse","synapseStorePromise","options","loadingComponent","errorComponent","error","awaiter","useSynapseReady","status","setStatus","store","setStore","setError","currentStatus","currentStore","currentError","unsubscribeReady","readyStore","unsubscribeError","err","undefined","withSynapseReady","Component","WrappedComponent","props","isReady","isError","componentName","cb"],"mappings":";;;;;;;;AAAwF;AAEf;AAOzE;;;;CAIC,GACM,SAASG,YAAYA,CAAkCC,mBAAiD,EAAEC,OAAkC;IACjJ,MAAM,EAAEC,iCAAmB,IAAC;kBAAI;MAAsB,EAAEC,iBAAiB,CAACC,sBAAiB,KAAC;;gBAAI;gBAAuBA,MAAM,OAAO;;UAAO,EAAE,GAAGH,WAAW,CAAC;IAE5J,MAAMI,UAAUP,oBAAoBA,CAASE;IAE7C;;GAEC,GACD,SAASM;QACP,MAAM,CAACC,QAAQC,UAAU,GAAGX,QAAQA,CAAgC,IAAMQ,QAAQ,SAAS;QAC3F,MAAM,CAACI,OAAOC,SAAS,GAAGb,QAAQA,CAAqB,IAAMQ,QAAQ,eAAe;QACpF,MAAM,CAACD,OAAOO,SAAS,GAAGd,QAAQA,CAAe,IAAMQ,QAAQ,QAAQ;QAEvET,SAASA,CAAC;YACR,+CAA+C;YAC/C,MAAMgB,gBAAgBP,QAAQ,SAAS;YACvC,MAAMQ,eAAeR,QAAQ,eAAe;YAC5C,MAAMS,eAAeT,QAAQ,QAAQ;YAErCG,UAAUI;YACVF,SAASG;YACTF,SAASG;YAET,6BAA6B;YAC7B,MAAMC,mBAAmBV,QAAQ,OAAO,CAAC,CAACW;gBACxCR,UAAU;gBACVE,SAASM;gBACTL,SAAS;YACX;YAEA,MAAMM,mBAAmBZ,QAAQ,OAAO,CAAC,CAACa;gBACxCV,UAAU;gBACVE,SAASS;gBACTR,SAASO;YACX;YAEA,OAAO;gBACLH;gBACAE;YACF;QACF,GAAG,EAAE;QAEL,OAAO;YACL,SAASV,WAAW;YACpB,SAASA,WAAW;YACpB,WAAWA,WAAW;YACtBE;YACAL;QACF;IACF;IAEA;;GAEC,GACD,SAASgB,iBAAiCC,SAAwC;QAChF,SAASC,iBAAiBC,KAAqB;YAC7C,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAErB,KAAK,EAAE,GAAGE;YAEpC,oBAAoB;YACpB,IAAImB,WAAWrB,OAAO,qBAAO;0BAAGD,eAAeC;;YAE/C,sBAAsB;YACtB,IAAI,CAACoB,SAAS,qBAAO;0BAAGtB;;YAExB,sCAAsC;YACtC,qBAAO,IAACmB;gBAAW,GAAIE,KAAK;;QAC9B;QAEA,6CAA6C;QAC7C,MAAMG,gBAAgBL,UAAU,WAAW,IAAIA,UAAU,IAAI,IAAI;QACjEC,iBAAiB,WAAW,GAAG,CAAC,aAAa,EAAEI,cAAc,CAAC,CAAC;QAE/D,OAAOJ;IACT;IAEA,OAAO;QACL,eAAe;QACfF;QACAd;QAEA,qFAAqF;QACrF,cAAc,IAAMD,QAAQ,YAAY;QACxC,SAAS,IAAMA,QAAQ,OAAO;QAC9B,iBAAiB,IAAMA,QAAQ,eAAe;QAC9C,SAAS,CAACsB,KAA8CtB,QAAQ,OAAO,CAACsB;QACxE,SAAS,CAACA,KAA8CtB,QAAQ,OAAO,CAACsB;QACxE,WAAW,IAAMtB,QAAQ,SAAS;QAClC,UAAU,IAAMA,QAAQ,QAAQ;QAChC,SAAS,IAAMA,QAAQ,OAAO;IAChC;AACF"}
@@ -1,33 +1,28 @@
1
1
  import { ComponentType } from 'react';
2
2
  import { Observable } from 'rxjs';
3
3
  import { IStorage } from '../../core';
4
- import { SynapseStoreBasic, SynapseStoreWithDispatcher, SynapseStoreWithEffects } from '../../utils';
4
+ import { type SynapseModule } from '../../utils';
5
5
  interface SimplifiedOptions {
6
6
  loadingComponent?: React.ReactNode;
7
+ /**
8
+ * Включает серверный рендер засеянных sync-сторов (Memory/LocalStorage). При `ssr: true`
9
+ * и синхронно-готовом сторе Provider рендерит children сразу (без `loadingComponent`),
10
+ * что даёт контент в серверном HTML и совпадающий первый кадр при гидрации.
11
+ * Для async-сторов (IndexedDB) поведение прежнее — гейт `loadingComponent`.
12
+ */
13
+ ssr?: boolean;
7
14
  }
8
- /**
9
- * Перегрузки для createSynapseCtx в зависимости от типа хранилища
10
- */
11
- export declare function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions>(synapseStorePromise: Promise<SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>> | SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>, options?: SimplifiedOptions): {
12
- contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>;
13
- useSynapseStorage: () => TStorage;
14
- useSynapseSelectors: () => TSelectors;
15
- useSynapseActions: () => TActions;
16
- useSynapseState$: () => Observable<TStore>;
17
- cleanupSynapse: () => Promise<void>;
18
- };
19
- export declare function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions>(synapseStorePromise: Promise<SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>> | SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>, options?: SimplifiedOptions): {
20
- contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>;
21
- useSynapseStorage: () => TStorage;
22
- useSynapseSelectors: () => TSelectors;
23
- useSynapseActions: () => TActions;
24
- cleanupSynapse: () => Promise<void>;
25
- };
26
- export declare function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors>(synapseStorePromise: Promise<SynapseStoreBasic<TStore, TStorage, TSelectors>> | SynapseStoreBasic<TStore, TStorage, TSelectors>, options?: SimplifiedOptions): {
27
- contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>;
28
- useSynapseStorage: () => TStorage;
15
+ export declare function createSynapseCtx<TState extends Record<string, any>, TDispatcher, TSelectors>(synapseModule: SynapseModule<TState, TDispatcher, TSelectors>, options?: SimplifiedOptions): {
16
+ contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps & {
17
+ dehydratedState?: TState;
18
+ }>;
19
+ dehydrate: (opts?: {
20
+ initialState?: Partial<TState>;
21
+ }) => Promise<TState>;
22
+ useSynapseStorage: () => IStorage<TState>;
29
23
  useSynapseSelectors: () => TSelectors;
24
+ useSynapseActions: () => TDispatcher;
25
+ useSynapseState$: () => Observable<TState>;
30
26
  cleanupSynapse: () => Promise<void>;
31
27
  };
32
28
  export {};
33
- //# sourceMappingURL=createSynapseCtx.d.ts.map
@@ -1,7 +1,10 @@
1
1
  import { Fragment, jsx } from "react/jsx-runtime";
2
- import { createContext, forwardRef, useContext, useEffect, useState } from "react";
2
+ import { createContext, forwardRef, useContext, useEffect, useRef, useState } from "react";
3
3
  import { handleCleanupError } from "../../_utils/error-handling.util.js";
4
- import { createSynapseAwaiter } from "../../utils/index.js";
4
+ import { StorageStatus } from "../../core/index.js";
5
+ import { createSynapseAwaiter, dehydrateModule } from "../../utils/index.js";
6
+
7
+
5
8
 
6
9
 
7
10
 
@@ -13,19 +16,20 @@ import { createSynapseAwaiter } from "../../utils/index.js";
13
16
 
14
17
  const ERROR_HOOK_MESSAGE = 'Хук необходимо использовать внутри компонента contextSynapse';
15
18
  const ERROR_CONTEXT_INIT = 'Ошибка при инициализации контекста:';
16
- // Основная реализация
17
- function createSynapseCtx(synapseStorePromise, options) {
19
+ function createSynapseCtx(synapseModule, options) {
18
20
  const { loadingComponent = /*#__PURE__*/ jsx("div", {
19
21
  children: "Инициализация контекста..."
20
- }) } = options || {};
21
- // Lazy-инициализация: awaiter создаётся при первом обращении и сбрасывается при cleanup.
22
- // Сам awaiter (createSynapseAwaiter) инкапсулирует ожидание готовности, статус и подписки.
23
- let awaiter = null;
24
- const getAwaiter = ()=>{
25
- if (!awaiter) awaiter = createSynapseAwaiter(synapseStorePromise);
26
- return awaiter;
27
- };
22
+ }), ssr = false } = options || {};
28
23
  const SynapseContext = /*#__PURE__*/ createContext(null);
24
+ // ── Awaiter ───────────────────────────────────────────────────────────────
25
+ // Клиент сохраняет прежнюю синглтон-семантику: один awaiter на handle (общий стор,
26
+ // фабрика стартует один раз при первом mount). На сервере синглтон уровня модуля
27
+ // запрещён (request bleed), поэтому там awaiter живёт per-render-tree и не шарится.
28
+ let clientAwaiter = null;
29
+ const getClientAwaiter = ()=>{
30
+ if (!clientAwaiter) clientAwaiter = createSynapseAwaiter(synapseModule);
31
+ return clientAwaiter;
32
+ };
29
33
  const useSynapseStorage = ()=>{
30
34
  const context = useContext(SynapseContext);
31
35
  if (!context) throw new Error(`useSynapseStorage: ${ERROR_HOOK_MESSAGE}`);
@@ -36,36 +40,59 @@ function createSynapseCtx(synapseStorePromise, options) {
36
40
  if (!context) throw new Error(`useSynapseSelectors: ${ERROR_HOOK_MESSAGE}`);
37
41
  return context.selectors;
38
42
  };
39
- // Условный хук для actions (только если есть dispatcher)
40
43
  const useSynapseActions = ()=>{
41
44
  const context = useContext(SynapseContext);
42
45
  if (!context) throw new Error(`useSynapseActions: ${ERROR_HOOK_MESSAGE}`);
43
- if ('actions' in context) {
44
- return context.actions;
45
- }
46
- throw new Error('useSynapseActions: actions недоступны для этого типа хранилища. Убедитесь, что передана функция createDispatcherFn при создании хранилища.');
46
+ return context.actions;
47
47
  };
48
- // Условный хук для state$ (только если есть effects)
49
48
  const useSynapseState$ = ()=>{
50
49
  const context = useContext(SynapseContext);
51
50
  if (!context) throw new Error(`useSynapseState$: ${ERROR_HOOK_MESSAGE}`);
52
- if ('state$' in context) {
53
- return context.state$;
54
- }
55
- throw new Error('useSynapseState$: state$ недоступен для этого типа хранилища. Убедитесь, что переданы функции createDispatcherFn и createEffectConfig при создании хранилища.');
51
+ return context.state$;
56
52
  };
53
+ // Серверный помощник: тонкая обёртка над server-safe dehydrateModule (вся логика там).
54
+ // initialState — серверные данные под запрос, не статический initialState модуля; ssr — из
55
+ // опций контекста.
56
+ const dehydrate = (opts)=>dehydrateModule(synapseModule, {
57
+ state: opts?.initialState,
58
+ ssr
59
+ });
57
60
  /**
58
- * Декоратор для обертывания компонентов в контекст Synapse
61
+ * Декоратор для обёртки компонентов в контекст Synapse.
59
62
  */ function contextSynapse(Component) {
60
63
  const WrappedComponent = /*#__PURE__*/ forwardRef(function WrappedComponent(props, ref) {
61
- const [synapseStore, setSynapseStore] = useState(()=>getAwaiter().getStoreIfReady());
62
- const [error, setError] = useState(()=>getAwaiter().getError());
64
+ const { dehydratedState, ...restProps } = props;
65
+ // Per-tree awaiter при наличии dehydratedState (изоляция server-рендера); иначе —
66
+ // общий клиентский awaiter (обратная совместимость).
67
+ const treeAwaiterRef = useRef(null);
68
+ const resolveAwaiter = ()=>{
69
+ if (dehydratedState !== undefined) {
70
+ if (!treeAwaiterRef.current) treeAwaiterRef.current = createSynapseAwaiter(synapseModule);
71
+ return treeAwaiterRef.current;
72
+ }
73
+ return getClientAwaiter();
74
+ };
75
+ // Синхронный засев снапшота ДО первого рендера: одинаковый HTML на сервере и клиенте.
76
+ const seedHydration = (store)=>{
77
+ if (store && dehydratedState !== undefined && store.storage.initStatus.status === StorageStatus.READY) {
78
+ store.storage.hydrate(dehydratedState);
79
+ }
80
+ };
81
+ const [synapseStore, setSynapseStore] = useState(()=>{
82
+ const store = resolveAwaiter().getStoreIfReady();
83
+ seedHydration(store);
84
+ return store;
85
+ });
86
+ const [error, setError] = useState(()=>resolveAwaiter().getError());
63
87
  useEffect(()=>{
64
- // awaiter мог поменять состояние между рендером и эффектом синхронизируемся
65
- const instance = getAwaiter();
66
- setSynapseStore(instance.getStoreIfReady());
88
+ // На сервере эффект не исполняется подписки/догрузка стартуют только на клиенте.
89
+ const instance = resolveAwaiter();
90
+ const current = instance.getStoreIfReady();
91
+ seedHydration(current);
92
+ setSynapseStore(current);
67
93
  setError(instance.getError());
68
94
  const unsubscribeReady = instance.onReady((store)=>{
95
+ seedHydration(store);
69
96
  setSynapseStore(store);
70
97
  setError(null);
71
98
  });
@@ -78,23 +105,23 @@ function createSynapseCtx(synapseStorePromise, options) {
78
105
  unsubscribeError();
79
106
  };
80
107
  }, []);
81
- // Показываем ошибку если что-то пошло не так
82
108
  if (error) return /*#__PURE__*/ jsx("div", {
83
109
  children: `${ERROR_CONTEXT_INIT} ${error.message}`
84
110
  });
85
- // Показываем загрузку пока store не готов
111
+ // SSR-гейт: при ssr и синхронно-готовом сторе (сервер после dehydrate / клиентская
112
+ // гидрация) synapseStore уже есть → рендерим children. Иначе — прежний гейт загрузки
113
+ // (async-сторы и обычный клиентский старт).
86
114
  if (!synapseStore) return /*#__PURE__*/ jsx(Fragment, {
87
115
  children: loadingComponent
88
116
  });
89
117
  return /*#__PURE__*/ jsx(SynapseContext.Provider, {
90
118
  value: synapseStore,
91
119
  children: /*#__PURE__*/ jsx(Component, {
92
- ...props,
120
+ ...restProps,
93
121
  ref: ref
94
122
  })
95
123
  });
96
124
  });
97
- // Устанавливаем отображаемое имя для отладки
98
125
  const componentName = Component.displayName || Component.name || 'Component';
99
126
  WrappedComponent.displayName = `SynapseContext(${componentName})`;
100
127
  // Копируем статические свойства оригинального компонента
@@ -114,20 +141,18 @@ function createSynapseCtx(synapseStorePromise, options) {
114
141
  return WrappedComponent;
115
142
  }
116
143
  const cleanupSynapse = async ()=>{
117
- if (!awaiter) return;
118
- const instance = awaiter;
119
- awaiter = null; // сбрасываем сразу, чтобы следующий маунт создал новый awaiter
144
+ const instance = clientAwaiter;
145
+ clientAwaiter = null;
120
146
  try {
121
- const store = instance.getStoreIfReady() ?? await instance.waitForReady();
122
- instance.destroy();
123
- await store?.destroy();
147
+ instance?.destroy();
148
+ await synapseModule.destroy();
124
149
  } catch (error) {
125
- instance.destroy();
126
150
  handleCleanupError('createSynapseCtx: error during Synapse cleanup', error);
127
151
  }
128
152
  };
129
153
  return {
130
154
  contextSynapse,
155
+ dehydrate,
131
156
  useSynapseStorage,
132
157
  useSynapseSelectors,
133
158
  useSynapseActions,
@@ -1 +1 @@
1
- {"version":3,"file":"react/utils/createSynapseCtx.js","sources":["../../../src/react/utils/createSynapseCtx.tsx"],"sourcesContent":["import { ComponentType, createContext, forwardRef, PropsWithChildren, useContext, useEffect, useState } from 'react'\nimport { Observable } from 'rxjs'\n\nimport { handleCleanupError } from '../../_utils/error-handling.util'\nimport { IStorage } from '../../core'\nimport { AnySynapseStore, createSynapseAwaiter, SynapseStoreBasic, SynapseStoreWithDispatcher, SynapseStoreWithEffects } from '../../utils'\n\nconst ERROR_HOOK_MESSAGE = 'Хук необходимо использовать внутри компонента contextSynapse'\nconst ERROR_CONTEXT_INIT = 'Ошибка при инициализации контекста:'\n\ninterface SimplifiedOptions {\n loadingComponent?: React.ReactNode\n}\n\n/**\n * Перегрузки для createSynapseCtx в зависимости от типа хранилища\n */\n\n// Для хранилища с effects\nexport function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions>(\n synapseStorePromise: Promise<SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>> | SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>,\n options?: SimplifiedOptions,\n): {\n contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>\n useSynapseStorage: () => TStorage\n useSynapseSelectors: () => TSelectors\n useSynapseActions: () => TActions\n useSynapseState$: () => Observable<TStore>\n cleanupSynapse: () => Promise<void>\n}\n\n// Для хранилища с dispatcher (без effects)\nexport function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors, TActions>(\n synapseStorePromise: Promise<SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>> | SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions>,\n options?: SimplifiedOptions,\n): {\n contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>\n useSynapseStorage: () => TStorage\n useSynapseSelectors: () => TSelectors\n useSynapseActions: () => TActions\n cleanupSynapse: () => Promise<void>\n}\n\n// Для базового хранилища\nexport function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors>(\n synapseStorePromise: Promise<SynapseStoreBasic<TStore, TStorage, TSelectors>> | SynapseStoreBasic<TStore, TStorage, TSelectors>,\n options?: SimplifiedOptions,\n): {\n contextSynapse: <SelfComponentProps>(Component: ComponentType<SelfComponentProps>) => ComponentType<SelfComponentProps>\n useSynapseStorage: () => TStorage\n useSynapseSelectors: () => TSelectors\n cleanupSynapse: () => Promise<void>\n}\n\n// Основная реализация\nexport function createSynapseCtx<TStore extends Record<string, any>, TStorage extends IStorage<TStore>, TSelectors = any, TActions = any>(\n synapseStorePromise: Promise<AnySynapseStore<TStore, TStorage, TSelectors, TActions>> | AnySynapseStore<TStore, TStorage, TSelectors, TActions>,\n options?: SimplifiedOptions,\n) {\n const { loadingComponent = <div>Инициализация контекста...</div> } = options || {}\n\n // Lazy-инициализация: awaiter создаётся при первом обращении и сбрасывается при cleanup.\n // Сам awaiter (createSynapseAwaiter) инкапсулирует ожидание готовности, статус и подписки.\n let awaiter: ReturnType<typeof createSynapseAwaiter<TStore, TStorage, TSelectors, TActions>> | null = null\n\n const getAwaiter = () => {\n if (!awaiter) awaiter = createSynapseAwaiter(synapseStorePromise)\n return awaiter\n }\n\n const SynapseContext = createContext<AnySynapseStore<TStore, TStorage, TSelectors, TActions> | null>(null)\n\n const useSynapseStorage = (): TStorage => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseStorage: ${ERROR_HOOK_MESSAGE}`)\n return context.storage\n }\n\n const useSynapseSelectors = (): TSelectors => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseSelectors: ${ERROR_HOOK_MESSAGE}`)\n return context.selectors\n }\n\n // Условный хук для actions (только если есть dispatcher)\n const useSynapseActions = (): TActions => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseActions: ${ERROR_HOOK_MESSAGE}`)\n\n if ('actions' in context) {\n return (context as SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, TActions> | SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>).actions\n }\n\n throw new Error('useSynapseActions: actions недоступны для этого типа хранилища. Убедитесь, что передана функция createDispatcherFn при создании хранилища.')\n }\n\n // Условный хук для state$ (только если есть effects)\n const useSynapseState$ = (): Observable<TStore> => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseState$: ${ERROR_HOOK_MESSAGE}`)\n\n if ('state$' in context) {\n return (context as SynapseStoreWithEffects<TStore, TStorage, TSelectors, TActions>).state$\n }\n\n throw new Error('useSynapseState$: state$ недоступен для этого типа хранилища. Убедитесь, что переданы функции createDispatcherFn и createEffectConfig при создании хранилища.')\n }\n\n /**\n * Декоратор для обертывания компонентов в контекст Synapse\n */\n function contextSynapse<SelfComponentProps>(Component: ComponentType<SelfComponentProps>) {\n const WrappedComponent = forwardRef<unknown, SelfComponentProps>(function WrappedComponent(props, ref) {\n const [synapseStore, setSynapseStore] = useState<AnySynapseStore<TStore, TStorage, TSelectors, TActions> | undefined>(() => getAwaiter().getStoreIfReady())\n const [error, setError] = useState<Error | null>(() => getAwaiter().getError())\n\n useEffect(() => {\n // awaiter мог поменять состояние между рендером и эффектом — синхронизируемся\n const instance = getAwaiter()\n setSynapseStore(instance.getStoreIfReady())\n setError(instance.getError())\n\n const unsubscribeReady = instance.onReady((store) => {\n setSynapseStore(store)\n setError(null)\n })\n const unsubscribeError = instance.onError((err) => {\n setSynapseStore(undefined)\n setError(err)\n })\n\n return () => {\n unsubscribeReady()\n unsubscribeError()\n }\n }, [])\n\n // Показываем ошибку если что-то пошло не так\n if (error) return <div>{`${ERROR_CONTEXT_INIT} ${error.message}`}</div>\n\n // Показываем загрузку пока store не готов\n if (!synapseStore) return <>{loadingComponent}</>\n\n return (\n <SynapseContext.Provider value={synapseStore}>\n <Component {...(props as PropsWithChildren<SelfComponentProps>)} ref={ref} />\n </SynapseContext.Provider>\n )\n })\n\n // Устанавливаем отображаемое имя для отладки\n const componentName = Component.displayName || Component.name || 'Component'\n WrappedComponent.displayName = `SynapseContext(${componentName})`\n\n // Копируем статические свойства оригинального компонента\n const excludedKeys = new Set(['$$typeof', 'render', 'defaultProps', 'displayName', 'propTypes'])\n Object.keys(Component).forEach((key) => {\n if (!excludedKeys.has(key)) {\n ;(WrappedComponent as any)[key] = (Component as any)[key]\n }\n })\n\n return WrappedComponent as ComponentType<SelfComponentProps>\n }\n\n const cleanupSynapse = async (): Promise<void> => {\n if (!awaiter) return\n\n const instance = awaiter\n awaiter = null // сбрасываем сразу, чтобы следующий маунт создал новый awaiter\n\n try {\n const store = instance.getStoreIfReady() ?? (await instance.waitForReady())\n instance.destroy()\n await store?.destroy()\n } catch (error) {\n instance.destroy()\n handleCleanupError('createSynapseCtx: error during Synapse cleanup', error)\n }\n }\n\n return {\n contextSynapse,\n useSynapseStorage,\n useSynapseSelectors,\n useSynapseActions,\n useSynapseState$,\n cleanupSynapse,\n }\n}\n"],"names":["createContext","forwardRef","useContext","useEffect","useState","handleCleanupError","createSynapseAwaiter","ERROR_HOOK_MESSAGE","ERROR_CONTEXT_INIT","createSynapseCtx","synapseStorePromise","options","loadingComponent","awaiter","getAwaiter","SynapseContext","useSynapseStorage","context","Error","useSynapseSelectors","useSynapseActions","useSynapseState$","contextSynapse","Component","WrappedComponent","props","ref","synapseStore","setSynapseStore","error","setError","instance","unsubscribeReady","store","unsubscribeError","err","undefined","componentName","excludedKeys","Set","Object","key","cleanupSynapse"],"mappings":"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"}
1
+ {"version":3,"file":"react/utils/createSynapseCtx.js","sources":["../../../src/react/utils/createSynapseCtx.tsx"],"sourcesContent":["import { ComponentType, createContext, forwardRef, PropsWithChildren, useContext, useEffect, useRef, useState } from 'react'\nimport { Observable } from 'rxjs'\n\nimport { handleCleanupError } from '../../_utils/error-handling.util'\nimport { IStorage, StorageStatus } from '../../core'\nimport { createSynapseAwaiter, dehydrateModule, type Synapse, type SynapseAwaiter, type SynapseModule } from '../../utils'\n\nconst ERROR_HOOK_MESSAGE = 'Хук необходимо использовать внутри компонента contextSynapse'\nconst ERROR_CONTEXT_INIT = 'Ошибка при инициализации контекста:'\n\ninterface SimplifiedOptions {\n loadingComponent?: React.ReactNode\n /**\n * Включает серверный рендер засеянных sync-сторов (Memory/LocalStorage). При `ssr: true`\n * и синхронно-готовом сторе Provider рендерит children сразу (без `loadingComponent`),\n * что даёт контент в серверном HTML и совпадающий первый кадр при гидрации.\n * Для async-сторов (IndexedDB) поведение прежнее — гейт `loadingComponent`.\n */\n ssr?: boolean\n}\n\nexport function createSynapseCtx<TState extends Record<string, any>, TDispatcher, TSelectors>(\n synapseModule: SynapseModule<TState, TDispatcher, TSelectors>,\n options?: SimplifiedOptions,\n) {\n const { loadingComponent = <div>Инициализация контекста...</div>, ssr = false } = options || {}\n\n type ReadySynapse = Synapse<TState, TDispatcher, TSelectors>\n\n const SynapseContext = createContext<ReadySynapse | null>(null)\n\n // ── Awaiter ───────────────────────────────────────────────────────────────\n // Клиент сохраняет прежнюю синглтон-семантику: один awaiter на handle (общий стор,\n // фабрика стартует один раз при первом mount). На сервере синглтон уровня модуля\n // запрещён (request bleed), поэтому там awaiter живёт per-render-tree и не шарится.\n let clientAwaiter: SynapseAwaiter<ReadySynapse> | null = null\n\n const getClientAwaiter = () => {\n if (!clientAwaiter) clientAwaiter = createSynapseAwaiter<ReadySynapse>(synapseModule)\n return clientAwaiter\n }\n\n const useSynapseStorage = (): IStorage<TState> => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseStorage: ${ERROR_HOOK_MESSAGE}`)\n return context.storage\n }\n\n const useSynapseSelectors = (): TSelectors => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseSelectors: ${ERROR_HOOK_MESSAGE}`)\n return context.selectors\n }\n\n const useSynapseActions = (): TDispatcher => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseActions: ${ERROR_HOOK_MESSAGE}`)\n return context.actions\n }\n\n const useSynapseState$ = (): Observable<TState> => {\n const context = useContext(SynapseContext)\n if (!context) throw new Error(`useSynapseState$: ${ERROR_HOOK_MESSAGE}`)\n return context.state$\n }\n\n // Серверный помощник: тонкая обёртка над server-safe dehydrateModule (вся логика там).\n // initialState — серверные данные под запрос, не статический initialState модуля; ssr — из\n // опций контекста.\n const dehydrate = (opts?: { initialState?: Partial<TState> }): Promise<TState> => dehydrateModule(synapseModule, { state: opts?.initialState, ssr })\n\n /**\n * Декоратор для обёртки компонентов в контекст Synapse.\n */\n function contextSynapse<SelfComponentProps>(Component: ComponentType<SelfComponentProps>) {\n const WrappedComponent = forwardRef<unknown, SelfComponentProps & { dehydratedState?: TState }>(function WrappedComponent(props, ref) {\n const { dehydratedState, ...restProps } = props as SelfComponentProps & { dehydratedState?: TState }\n\n // Per-tree awaiter при наличии dehydratedState (изоляция server-рендера); иначе —\n // общий клиентский awaiter (обратная совместимость).\n const treeAwaiterRef = useRef<SynapseAwaiter<ReadySynapse> | null>(null)\n const resolveAwaiter = (): SynapseAwaiter<ReadySynapse> => {\n if (dehydratedState !== undefined) {\n if (!treeAwaiterRef.current) treeAwaiterRef.current = createSynapseAwaiter<ReadySynapse>(synapseModule)\n return treeAwaiterRef.current\n }\n return getClientAwaiter()\n }\n\n // Синхронный засев снапшота ДО первого рендера: одинаковый HTML на сервере и клиенте.\n const seedHydration = (store: ReadySynapse | undefined) => {\n if (store && dehydratedState !== undefined && store.storage.initStatus.status === StorageStatus.READY) {\n store.storage.hydrate(dehydratedState)\n }\n }\n\n const [synapseStore, setSynapseStore] = useState<ReadySynapse | undefined>(() => {\n const store = resolveAwaiter().getStoreIfReady()\n seedHydration(store)\n return store\n })\n const [error, setError] = useState<Error | null>(() => resolveAwaiter().getError())\n\n useEffect(() => {\n // На сервере эффект не исполняется — подписки/догрузка стартуют только на клиенте.\n const instance = resolveAwaiter()\n const current = instance.getStoreIfReady()\n seedHydration(current)\n setSynapseStore(current)\n setError(instance.getError())\n\n const unsubscribeReady = instance.onReady((store) => {\n seedHydration(store)\n setSynapseStore(store)\n setError(null)\n })\n const unsubscribeError = instance.onError((err) => {\n setSynapseStore(undefined)\n setError(err)\n })\n\n return () => {\n unsubscribeReady()\n unsubscribeError()\n }\n }, [])\n\n if (error) return <div>{`${ERROR_CONTEXT_INIT} ${error.message}`}</div>\n\n // SSR-гейт: при ssr и синхронно-готовом сторе (сервер после dehydrate / клиентская\n // гидрация) synapseStore уже есть → рендерим children. Иначе — прежний гейт загрузки\n // (async-сторы и обычный клиентский старт).\n if (!synapseStore) return <>{loadingComponent}</>\n\n return (\n <SynapseContext.Provider value={synapseStore}>\n <Component {...(restProps as PropsWithChildren<SelfComponentProps>)} ref={ref} />\n </SynapseContext.Provider>\n )\n })\n\n const componentName = Component.displayName || Component.name || 'Component'\n WrappedComponent.displayName = `SynapseContext(${componentName})`\n\n // Копируем статические свойства оригинального компонента\n const excludedKeys = new Set(['$$typeof', 'render', 'defaultProps', 'displayName', 'propTypes'])\n Object.keys(Component).forEach((key) => {\n if (!excludedKeys.has(key)) {\n ;(WrappedComponent as any)[key] = (Component as any)[key]\n }\n })\n\n return WrappedComponent as ComponentType<SelfComponentProps & { dehydratedState?: TState }>\n }\n\n const cleanupSynapse = async (): Promise<void> => {\n const instance = clientAwaiter\n clientAwaiter = null\n try {\n instance?.destroy()\n await synapseModule.destroy()\n } catch (error) {\n handleCleanupError('createSynapseCtx: error during Synapse cleanup', error)\n }\n }\n\n return {\n contextSynapse,\n dehydrate,\n useSynapseStorage,\n useSynapseSelectors,\n useSynapseActions,\n useSynapseState$,\n cleanupSynapse,\n }\n}\n"],"names":["createContext","forwardRef","useContext","useEffect","useRef","useState","handleCleanupError","StorageStatus","createSynapseAwaiter","dehydrateModule","ERROR_HOOK_MESSAGE","ERROR_CONTEXT_INIT","createSynapseCtx","synapseModule","options","loadingComponent","ssr","SynapseContext","clientAwaiter","getClientAwaiter","useSynapseStorage","context","Error","useSynapseSelectors","useSynapseActions","useSynapseState$","dehydrate","opts","contextSynapse","Component","WrappedComponent","props","ref","dehydratedState","restProps","treeAwaiterRef","resolveAwaiter","undefined","seedHydration","store","synapseStore","setSynapseStore","error","setError","instance","current","unsubscribeReady","unsubscribeError","err","componentName","excludedKeys","Set","Object","key","cleanupSynapse"],"mappings":"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"}
@@ -1,3 +1,2 @@
1
1
  export { awaitSynapse } from './awaitSynapse';
2
2
  export { createSynapseCtx } from './createSynapseCtx';
3
- //# sourceMappingURL=index.d.ts.map