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
@@ -1,101 +1,31 @@
1
- import { handleCallbackError, handleOperationError } from "../../_utils/error-handling.util.js";
2
- import { SelectorModule } from "../../core/index.js";
3
- import { EffectsModule } from "../../reactive/index.js";
4
- import { validateSynapseConfig } from "./validate.js";
5
- import { waitForDependencies } from "./waitForDependencies.js";
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
- // Основная реализация
18
- async function createSynapse(config) {
19
- // 0. Валидируем конфигурацию
20
- try {
21
- validateSynapseConfig(config);
22
- } catch (error) {
23
- handleOperationError('createSynapse: configuration validation failed', error);
24
- }
25
- // 1. Сначала ждем готовности всех зависимостей
26
- await waitForDependencies(config.dependencies, config.dependencyTimeout);
27
- // 2. Выполняем setup (например, инициализация API-клиентов)
28
- if (config.setup) {
29
- try {
30
- await config.setup();
31
- } catch (error) {
32
- handleOperationError('createSynapse: setup failed', error);
33
- }
34
- }
35
- // 3. Создаем и инициализируем хранилище
36
- const storageInstance = config.createStorageFn ? await config.createStorageFn() : config.storage;
37
- await storageInstance.initialize();
38
- // Создаем сборщики для последующей очистки
39
- const cleanupCallbacks = [];
40
- const result = {
41
- storage: storageInstance,
42
- selectors: {},
43
- destroy: async ()=>{
44
- for (const callback of cleanupCallbacks){
45
- await callback();
46
- }
47
- }
48
- };
49
- cleanupCallbacks.push(()=>storageInstance.destroy());
50
- let dispatcher;
51
- let selectorModule;
52
- let effectsModule;
53
- // 4. Создаем модуль селекторов
54
- if (config.createSelectorsFn) {
55
- try {
56
- selectorModule = new SelectorModule(storageInstance);
57
- const externalSelectors = config.externalSelectors || {};
58
- result.selectors = config.createSelectorsFn(selectorModule, externalSelectors);
59
- if (typeof selectorModule.destroy === 'function') {
60
- cleanupCallbacks.push(()=>selectorModule.destroy());
61
- }
62
- } catch (error) {
63
- handleCallbackError('createSynapse: error creating selectors', error);
64
- }
65
- }
66
- // 5. Создаем диспетчер
67
- if (config.createDispatcherFn) {
68
- dispatcher = config.createDispatcherFn(storageInstance);
69
- result.dispatcher = dispatcher;
70
- // @ts-ignore
71
- if (dispatcher && 'dispatch' in dispatcher) {
72
- result.actions = dispatcher.dispatch;
73
- if (typeof dispatcher.destroy === 'function') {
74
- cleanupCallbacks.push(()=>dispatcher.destroy());
75
- }
76
- }
77
- }
78
- // 6. Создаем и настраиваем модуль эффектов
79
- if (config.createEffectConfig && dispatcher) {
80
- try {
81
- const { services, config: effectConfig, externalDispatchers, externalStates } = config.createEffectConfig();
82
- effectsModule = new EffectsModule(storageInstance, dispatcher, externalDispatchers || {}, services, effectConfig, externalStates || {});
83
- if (Array.isArray(config.effects)) {
84
- // @ts-ignore
85
- config.effects.forEach((effect)=>{
86
- if (effectsModule) effectsModule.add(effect);
87
- });
88
- }
89
- await effectsModule.start();
90
- result.state$ = effectsModule.state$;
91
- cleanupCallbacks.push(()=>{
92
- if (effectsModule) effectsModule.stop();
93
- });
94
- } catch (error) {
95
- handleCallbackError('createSynapse: error creating effects module', error);
96
- }
97
- }
98
- return result;
1
+ import { createSynapseModule } from "./factory.js";
2
+
3
+
4
+
5
+ /**
6
+ * Создаёт ленивый class-based synapse из фабрики-конфига.
7
+ *
8
+ * Фабрика возвращает {@link SynapseConfig} с уже сконструированными class-слоями
9
+ * (`Dispatcher`/`Selectors`/`Effects`). Возвращается {@link SynapseModule}-handle:
10
+ * фабрика исполняется один раз при первом `await`/`ready()`, повторные `await` делят
11
+ * один промис, `destroy()` сбрасывает мемоизацию (handle пересоздаваемый).
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const postsSynapse = createSynapse(() => {
16
+ * const storage = new MemoryStorage<PostsState>({ name: 'posts', initialState })
17
+ * return {
18
+ * storage,
19
+ * dispatcher: new PostsDispatcher(storage),
20
+ * selectors: new PostsSelectors(storage),
21
+ * effects: new PostsEffects(api),
22
+ * }
23
+ * })
24
+ *
25
+ * const { dispatcher, selectors } = await postsSynapse
26
+ * ```
27
+ */ function createSynapse(factory) {
28
+ return createSynapseModule(factory);
99
29
  }
100
30
 
101
31
  export { createSynapse };
@@ -1 +1 @@
1
- {"version":3,"file":"utils/createSynapse/createSynapse.js","sources":["../../../src/utils/createSynapse/createSynapse.ts"],"sourcesContent":["import { handleCallbackError, handleOperationError } from '../../_utils/error-handling.util'\nimport { ISelectorModule, IStorage, SelectorModule } from '../../core'\nimport { EffectsModule } from '../../reactive'\nimport type {\n CreateSynapseConfigBasic,\n CreateSynapseConfigWithDispatcher,\n CreateSynapseConfigWithEffects,\n ExtractDispatchType,\n SynapseStoreBasic,\n SynapseStoreWithDispatcher,\n SynapseStoreWithEffects,\n} from './types'\nimport { validateSynapseConfig } from './validate'\nimport { waitForDependencies } from './waitForDependencies'\n\n/**\n * Перегрузки функции createSynapse\n */\n\n// Случай 1: С dispatcher и effects\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TServices extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithEffects<TStore, TSelectors, TDispatcher, TServices, TConfig, TExternalSelectors>,\n): Promise<SynapseStoreWithEffects<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 2: Только с dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(\n config: CreateSynapseConfigWithDispatcher<TStore, TSelectors, TDispatcher, TExternalSelectors>,\n): Promise<SynapseStoreWithDispatcher<TStore, TStorage, TSelectors, ExtractDispatchType<TDispatcher>>>\n\n// Случай 3: Без dispatcher\nexport function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: CreateSynapseConfigBasic<TStore, TSelectors, TExternalSelectors>): Promise<SynapseStoreBasic<TStore, TStorage, TSelectors>>\n\n// Основная реализация\nexport async function createSynapse<\n TStore extends Record<string, any>,\n TSelectors = any,\n TDispatcher = any,\n TApi extends Record<string, any> = Record<string, never>,\n TConfig extends Record<string, any> = Record<string, never>,\n TExternalSelectors extends Record<string, any> = Record<string, any>,\n TStorage extends IStorage<TStore> = IStorage<TStore>,\n>(config: any): Promise<any> {\n // 0. Валидируем конфигурацию\n try {\n validateSynapseConfig(config)\n } catch (error) {\n handleOperationError('createSynapse: configuration validation failed', error)\n }\n\n // 1. Сначала ждем готовности всех зависимостей\n await waitForDependencies(config.dependencies, config.dependencyTimeout)\n\n // 2. Выполняем setup (например, инициализация API-клиентов)\n if (config.setup) {\n try {\n await config.setup()\n } catch (error) {\n handleOperationError('createSynapse: setup failed', error)\n }\n }\n\n // 3. Создаем и инициализируем хранилище\n const storageInstance = (config.createStorageFn ? await config.createStorageFn() : config.storage!) as TStorage\n await storageInstance.initialize()\n\n // Создаем сборщики для последующей очистки\n const cleanupCallbacks: Array<() => Promise<void> | void> = []\n\n const result: any = {\n storage: storageInstance,\n selectors: {} as TSelectors,\n destroy: async () => {\n for (const callback of cleanupCallbacks) {\n await callback()\n }\n },\n }\n\n cleanupCallbacks.push(() => storageInstance.destroy())\n\n let dispatcher: TDispatcher | undefined\n let selectorModule: ISelectorModule<TStore>\n let effectsModule: any\n\n // 4. Создаем модуль селекторов\n if (config.createSelectorsFn) {\n try {\n selectorModule = new SelectorModule(storageInstance)\n\n const externalSelectors = config.externalSelectors || ({} as TExternalSelectors)\n\n result.selectors = config.createSelectorsFn(selectorModule, externalSelectors)\n\n if (typeof (selectorModule as any).destroy === 'function') {\n cleanupCallbacks.push(() => selectorModule.destroy())\n }\n } catch (error) {\n handleCallbackError('createSynapse: error creating selectors', error)\n }\n }\n\n // 5. Создаем диспетчер\n if (config.createDispatcherFn) {\n dispatcher = config.createDispatcherFn(storageInstance)\n result.dispatcher = dispatcher\n\n // @ts-ignore\n if (dispatcher && 'dispatch' in dispatcher) {\n result.actions = (dispatcher as any).dispatch\n\n if (typeof (dispatcher as any).destroy === 'function') {\n cleanupCallbacks.push(() => (dispatcher as any).destroy())\n }\n }\n }\n\n // 6. Создаем и настраиваем модуль эффектов\n if (config.createEffectConfig && dispatcher) {\n try {\n const { services, config: effectConfig, externalDispatchers, externalStates } = config.createEffectConfig()\n\n effectsModule = new EffectsModule(storageInstance, dispatcher as any, externalDispatchers || {}, services, effectConfig, externalStates || {})\n\n if (Array.isArray(config.effects)) {\n // @ts-ignore\n config.effects.forEach((effect) => {\n if (effectsModule) effectsModule.add(effect)\n })\n }\n\n await effectsModule.start()\n result.state$ = effectsModule.state$\n\n cleanupCallbacks.push(() => {\n if (effectsModule) effectsModule.stop()\n })\n } catch (error) {\n handleCallbackError('createSynapse: error creating effects module', error)\n }\n }\n\n return result\n}\n"],"names":["handleCallbackError","handleOperationError","SelectorModule","EffectsModule","validateSynapseConfig","waitForDependencies","createSynapse","config","error","storageInstance","cleanupCallbacks","result","callback","dispatcher","selectorModule","effectsModule","externalSelectors","services","effectConfig","externalDispatchers","externalStates","Array","effect"],"mappings":";;;;;;;;;;;AAA4F;AACtB;AACxB;AAUI;AACS;AAsC3D,sBAAsB;AACf,eAAeM,aAAaA,CAQjCC,MAAW;IACX,6BAA6B;IAC7B,IAAI;QACFH,qBAAqBA,CAACG;IACxB,EAAE,OAAOC,OAAO;QACdP,oBAAoBA,CAAC,kDAAkDO;IACzE;IAEA,+CAA+C;IAC/C,MAAMH,mBAAmBA,CAACE,OAAO,YAAY,EAAEA,OAAO,iBAAiB;IAEvE,4DAA4D;IAC5D,IAAIA,OAAO,KAAK,EAAE;QAChB,IAAI;YACF,MAAMA,OAAO,KAAK;QACpB,EAAE,OAAOC,OAAO;YACdP,oBAAoBA,CAAC,+BAA+BO;QACtD;IACF;IAEA,wCAAwC;IACxC,MAAMC,kBAAmBF,OAAO,eAAe,GAAG,MAAMA,OAAO,eAAe,KAAKA,OAAO,OAAO;IACjG,MAAME,gBAAgB,UAAU;IAEhC,2CAA2C;IAC3C,MAAMC,mBAAsD,EAAE;IAE9D,MAAMC,SAAc;QAClB,SAASF;QACT,WAAW,CAAC;QACZ,SAAS;YACP,KAAK,MAAMG,YAAYF,iBAAkB;gBACvC,MAAME;YACR;QACF;IACF;IAEAF,iBAAiB,IAAI,CAAC,IAAMD,gBAAgB,OAAO;IAEnD,IAAII;IACJ,IAAIC;IACJ,IAAIC;IAEJ,+BAA+B;IAC/B,IAAIR,OAAO,iBAAiB,EAAE;QAC5B,IAAI;YACFO,iBAAiB,IAAIZ,cAAcA,CAACO;YAEpC,MAAMO,oBAAoBT,OAAO,iBAAiB,IAAK,CAAC;YAExDI,OAAO,SAAS,GAAGJ,OAAO,iBAAiB,CAACO,gBAAgBE;YAE5D,IAAI,OAAQF,eAAuB,OAAO,KAAK,YAAY;gBACzDJ,iBAAiB,IAAI,CAAC,IAAMI,eAAe,OAAO;YACpD;QACF,EAAE,OAAON,OAAO;YACdR,mBAAmBA,CAAC,2CAA2CQ;QACjE;IACF;IAEA,uBAAuB;IACvB,IAAID,OAAO,kBAAkB,EAAE;QAC7BM,aAAaN,OAAO,kBAAkB,CAACE;QACvCE,OAAO,UAAU,GAAGE;QAEpB,aAAa;QACb,IAAIA,cAAc,cAAcA,YAAY;YAC1CF,OAAO,OAAO,GAAIE,WAAmB,QAAQ;YAE7C,IAAI,OAAQA,WAAmB,OAAO,KAAK,YAAY;gBACrDH,iBAAiB,IAAI,CAAC,IAAOG,WAAmB,OAAO;YACzD;QACF;IACF;IAEA,2CAA2C;IAC3C,IAAIN,OAAO,kBAAkB,IAAIM,YAAY;QAC3C,IAAI;YACF,MAAM,EAAEI,QAAQ,EAAE,QAAQC,YAAY,EAAEC,mBAAmB,EAAEC,cAAc,EAAE,GAAGb,OAAO,kBAAkB;YAEzGQ,gBAAgB,IAAIZ,aAAaA,CAACM,iBAAiBI,YAAmBM,uBAAuB,CAAC,GAAGF,UAAUC,cAAcE,kBAAkB,CAAC;YAE5I,IAAIC,MAAM,OAAO,CAACd,OAAO,OAAO,GAAG;gBACjC,aAAa;gBACbA,OAAO,OAAO,CAAC,OAAO,CAAC,CAACe;oBACtB,IAAIP,eAAeA,cAAc,GAAG,CAACO;gBACvC;YACF;YAEA,MAAMP,cAAc,KAAK;YACzBJ,OAAO,MAAM,GAAGI,cAAc,MAAM;YAEpCL,iBAAiB,IAAI,CAAC;gBACpB,IAAIK,eAAeA,cAAc,IAAI;YACvC;QACF,EAAE,OAAOP,OAAO;YACdR,mBAAmBA,CAAC,gDAAgDQ;QACtE;IACF;IAEA,OAAOG;AACT"}
1
+ {"version":3,"file":"utils/createSynapse/createSynapse.js","sources":["../../../src/utils/createSynapse/createSynapse.ts"],"sourcesContent":["import type { Selectors } from '../../core'\nimport type { Dispatcher, Effects } from '../../reactive'\nimport { createSynapseModule } from './factory'\nimport type { SynapseConfig, SynapseModule } from './synapse.types'\n\n/**\n * Создаёт ленивый class-based synapse из фабрики-конфига.\n *\n * Фабрика возвращает {@link SynapseConfig} с уже сконструированными class-слоями\n * (`Dispatcher`/`Selectors`/`Effects`). Возвращается {@link SynapseModule}-handle:\n * фабрика исполняется один раз при первом `await`/`ready()`, повторные `await` делят\n * один промис, `destroy()` сбрасывает мемоизацию (handle пересоздаваемый).\n *\n * @example\n * ```ts\n * const postsSynapse = createSynapse(() => {\n * const storage = new MemoryStorage<PostsState>({ name: 'posts', initialState })\n * return {\n * storage,\n * dispatcher: new PostsDispatcher(storage),\n * selectors: new PostsSelectors(storage),\n * effects: new PostsEffects(api),\n * }\n * })\n *\n * const { dispatcher, selectors } = await postsSynapse\n * ```\n */\nexport function createSynapse<\n TState extends Record<string, any>,\n TDispatcher extends Dispatcher<TState> | undefined = undefined,\n TSelectors extends Selectors<TState> | undefined = undefined,\n TEffects extends Effects<TState, NonNullable<TDispatcher>, any> | undefined = undefined,\n>(\n factory: () => SynapseConfig<TState, TDispatcher, TSelectors, TEffects> | Promise<SynapseConfig<TState, TDispatcher, TSelectors, TEffects>>,\n): SynapseModule<TState, TDispatcher, TSelectors> {\n return createSynapseModule<TState, TDispatcher, TSelectors>(factory)\n}\n"],"names":["createSynapseModule","createSynapse","factory"],"mappings":";;;AAE+C;AAG/C;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACM,SAASC,aAAaA,CAM3BC,OAA2I;IAE3I,OAAOF,mBAAmBA,CAAkCE;AAC9D"}
@@ -0,0 +1,6 @@
1
+ import type { SynapseConfig, SynapseModule } from './synapse.types';
2
+ /**
3
+ * Создаёт ленивый пересоздаваемый handle поверх фабрики. Фабрика исполняется один раз
4
+ * при первом `ready()`/`await`; параллельные `await` делят один промис.
5
+ */
6
+ export declare function createSynapseModule<TState extends Record<string, any>, TDispatcher, TSelectors>(factory: () => SynapseConfig<any, any, any, any> | Promise<SynapseConfig<any, any, any, any>>): SynapseModule<TState, TDispatcher, TSelectors>;
@@ -0,0 +1,256 @@
1
+ import { Selectors } from "../../core/index.js";
2
+ import { Dispatcher, Effects, EffectsModule, FINALIZE, toObservable } from "../../reactive/index.js";
3
+ import { waitForDependencies } from "./waitForDependencies.js";
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ /**
12
+ * Минимальная runtime-валидация конфига фабрики (`instanceof`-проверки). Полная
13
+ * типизация — на уровне TS; здесь только страховка от грубых ошибок в рантайме.
14
+ */ function validateFactoryConfig(config) {
15
+ if (!config || typeof config !== 'object') {
16
+ throw new Error('createSynapse(factory): фабрика должна вернуть объект-конфиг.');
17
+ }
18
+ const storage = config.storage;
19
+ if (!storage || typeof storage.initialize !== 'function' || typeof storage.waitForReady !== 'function') {
20
+ throw new Error('createSynapse(factory): "storage" обязателен и должен быть IStorage.');
21
+ }
22
+ if (config.dispatcher && !(config.dispatcher instanceof Dispatcher)) {
23
+ throw new Error('createSynapse(factory): "dispatcher" должен быть инстансом класса Dispatcher.');
24
+ }
25
+ if (config.selectors && !(config.selectors instanceof Selectors)) {
26
+ throw new Error('createSynapse(factory): "selectors" должен быть инстансом класса Selectors.');
27
+ }
28
+ }
29
+ /**
30
+ * Раскладывает `effects` (инстанс, функция или их смесь) в плоский список
31
+ * module-совместимых эффектов + список инстансов `Effects` (для `onDestroy`).
32
+ */ function collectEffects(input) {
33
+ const items = input === undefined ? [] : Array.isArray(input) ? input : [
34
+ input
35
+ ];
36
+ const moduleEffects = [];
37
+ const instances = [];
38
+ for (const item of items){
39
+ if (item instanceof Effects) {
40
+ instances.push(item);
41
+ moduleEffects.push(...item.getEffects());
42
+ } else if (typeof item === 'function') {
43
+ moduleEffects.push(item);
44
+ } else {
45
+ throw new Error('createSynapse(factory): каждый элемент "effects" должен быть инстансом Effects или функцией-эффектом.');
46
+ }
47
+ }
48
+ return {
49
+ moduleEffects,
50
+ instances
51
+ };
52
+ }
53
+ /** Выполняет накопленные шаги очистки в обратном порядке (LIFO). */ async function teardown(cleanup) {
54
+ for(let i = cleanup.length - 1; i >= 0; i--){
55
+ await cleanup[i]();
56
+ }
57
+ }
58
+ /**
59
+ * Полный пайплайн запуска (один раз на `ready()`):
60
+ *
61
+ * 1. `config = await factory()` — async-пролог (await чужих synapse, API-клиенты)
62
+ * 2. минимальная runtime-валидация (instanceof)
63
+ * 3. `await waitForDependencies(...)`
64
+ * 4. `await storage.initialize()`
65
+ * 5. `dispatcher[FINALIZE]()` — имена экшенов из имён полей
66
+ * 6. селекторы уже материализованы конструктором — шага нет
67
+ * 7. `state$ = toObservable(storage)` — всегда
68
+ * 8. `EffectsModule(...)` → `addEffects` → `await start()`
69
+ * 9. teardown в LIFO: stop effects → onDestroy → destroy dispatcher → selectors → storage
70
+ *
71
+ * Любая ошибка любого шага → откат уже созданного (partial teardown) и проброс наверх
72
+ * (никакой тихой частичной инициализации).
73
+ *
74
+ * `withEffects: false` (серверный путь дегидрации, см. {@link SynapseModule.ready}) собирает
75
+ * стор целиком (storage/dispatcher/selectors/state$), но ПРОПУСКАЕТ шаг 8 — эффекты не
76
+ * стартуют. Нужен только снапшот состояния + READY-storage для SSR-seed; запуск эффектов
77
+ * на сервере — лишняя работа (форк) либо «висящие» подписки (синглтон main handle).
78
+ */ async function buildSynapse(factory, options) {
79
+ const { withEffects = true } = options ?? {};
80
+ const config = await factory();
81
+ validateFactoryConfig(config);
82
+ const cleanup = [];
83
+ try {
84
+ await waitForDependencies(config.dependencies, config.dependencyTimeout);
85
+ const storage = config.storage;
86
+ await storage.initialize();
87
+ cleanup.push(()=>storage.destroy());
88
+ const selectors = config.selectors;
89
+ if (selectors) {
90
+ cleanup.push(()=>selectors.destroy());
91
+ }
92
+ const dispatcher = config.dispatcher;
93
+ if (dispatcher) {
94
+ dispatcher[FINALIZE]();
95
+ cleanup.push(()=>dispatcher.destroy());
96
+ }
97
+ // state$ — всегда, даже без эффектов.
98
+ const state$ = toObservable(storage);
99
+ const { moduleEffects, instances } = collectEffects(config.effects);
100
+ // onDestroy инстансов нужен на teardown в любом случае (даже без запуска эффектов).
101
+ const registerInstanceCleanup = ()=>{
102
+ for (const instance of instances){
103
+ if (instance.onDestroy) {
104
+ cleanup.push(()=>instance.onDestroy());
105
+ }
106
+ }
107
+ };
108
+ if (withEffects && moduleEffects.length > 0) {
109
+ if (!dispatcher) {
110
+ throw new Error('createSynapse(factory): "effects" требуют "dispatcher".');
111
+ }
112
+ const effectsModule = new EffectsModule(storage, dispatcher, config.externalDispatchers ?? {});
113
+ effectsModule.addEffects(moduleEffects);
114
+ // onDestroy инстансов — перед stop в порядке teardown: пушим onDestroy раньше stop,
115
+ // LIFO-обход выполнит stop первым, затем onDestroy.
116
+ registerInstanceCleanup();
117
+ cleanup.push(()=>{
118
+ effectsModule.stop();
119
+ });
120
+ await effectsModule.start();
121
+ } else {
122
+ // withEffects: false (серверная дегидрация) либо эффектов нет — EffectsModule не
123
+ // конструируется и не стартует; регистрируем только onDestroy инстансов на teardown.
124
+ registerInstanceCleanup();
125
+ }
126
+ let destroyed = false;
127
+ const synapse = {
128
+ storage,
129
+ state$,
130
+ dispatcher: dispatcher,
131
+ actions: dispatcher,
132
+ selectors: selectors,
133
+ destroy: async ()=>{
134
+ if (destroyed) return;
135
+ destroyed = true;
136
+ await teardown(cleanup);
137
+ }
138
+ };
139
+ return synapse;
140
+ } catch (error) {
141
+ // Fail-fast: откатываем уже созданное и пробрасываем ошибку.
142
+ await teardown(cleanup).catch(()=>{});
143
+ throw error;
144
+ }
145
+ }
146
+ /**
147
+ * Создаёт ленивый пересоздаваемый handle поверх фабрики. Фабрика исполняется один раз
148
+ * при первом `ready()`/`await`; параллельные `await` делят один промис.
149
+ */ function createSynapseModule(factory) {
150
+ let pending;
151
+ let settled;
152
+ // Был ли текущий мемоизированный запуск собран С эффектами. Нужен для апгрейда
153
+ // прогрев(без эффектов) → честный ready() (см. ниже).
154
+ let startedWithEffects = false;
155
+ // Прогретые (без эффектов) запуски, вытесненные апгрейдом до честного ready(). Не рушим их
156
+ // сразу: они могли «утечь» наружу через getSnapshot()/awaiter и ещё обслуживать рендер до
157
+ // переключения на новый стор. Уничтожаем все скопом на destroy() handle.
158
+ const supersededWarmRuns = new Set();
159
+ // Единый запуск пайплайна с мемоизацией.
160
+ //
161
+ // Семантика withEffects:
162
+ // - `ready()` / `ready({ withEffects: true })` — обычный путь: фабрика + эффекты, мемо
163
+ // (pending/settled), повторные вызовы отдают тот же промис.
164
+ // - `ready({ withEffects: false })` — серверный прогрев: собирает стор БЕЗ эффектов, тоже
165
+ // мемоизируется — повторные серверные прогревы main handle переиспользуют стор, а
166
+ // getSnapshot() отдаёт READY-handle для синхронного SSR-seed.
167
+ // - Апгрейд (святой клиентский инвариант): если мемо-запуск собран БЕЗ эффектов, а затем
168
+ // зовут честный `ready()` (с эффектами) — стор пересобирается с эффектами. Прогретый стор
169
+ // при этом ПРОДОЛЖАЕТ обслуживать getSnapshot() (settled не зануляется), пока новый запуск
170
+ // не зарезолвится; затем settled свапается. Прогретый стор НЕ рушим сразу (он мог утечь в
171
+ // awaiter/рендер) — копим в supersededWarmRuns и уничтожаем на destroy() handle. Так
172
+ // getSnapshot() не «проваливается» в undefined (иначе SSR-провайдер показал бы
173
+ // loadingComponent → hydration mismatch), и при этом гарантируем: после
174
+ // `ready({ withEffects: false })` последующий `ready()` всегда вернёт инстанс с запущенными
175
+ // эффектами. Обратно НЕ пересобираем: `withEffects: false` поверх уже запущенного стора
176
+ // отдаёт существующий (эффекты — безопасный супер-сет).
177
+ const start = (withEffects)=>{
178
+ const needsUpgrade = withEffects && pending !== undefined && !startedWithEffects;
179
+ if (!pending || needsUpgrade) {
180
+ // Устаревший прогретый запуск (если это апгрейд) — переедет в supersededWarmRuns по готовности нового.
181
+ const stale = needsUpgrade ? pending : undefined;
182
+ const run = buildSynapse(factory, {
183
+ withEffects
184
+ });
185
+ pending = run;
186
+ startedWithEffects = withEffects;
187
+ run.then((synapse)=>{
188
+ // Учитываем только если этот запуск всё ещё актуален (не вытеснен destroy/апгрейдом).
189
+ if (pending === run) {
190
+ settled = synapse;
191
+ // Свап завершён — помечаем прогретый запуск на уничтожение при destroy() handle.
192
+ if (stale) supersededWarmRuns.add(stale);
193
+ }
194
+ }, ()=>{
195
+ // Fail-fast: возвращаем прежний мемо-запуск (или undefined вне апгрейда), чтобы
196
+ // следующий ready() мог повторить попытку; settled (прогретый стор) продолжает
197
+ // обслуживать getSnapshot(). При апгрейде сбрасываем флаг — повтор снова попробует
198
+ // запустить эффекты.
199
+ if (pending === run) {
200
+ pending = stale;
201
+ if (stale !== undefined) startedWithEffects = false;
202
+ }
203
+ });
204
+ }
205
+ return pending;
206
+ };
207
+ const handle = {
208
+ ready (options) {
209
+ const { withEffects = true } = options ?? {};
210
+ return start(withEffects);
211
+ },
212
+ isReady () {
213
+ return settled !== undefined;
214
+ },
215
+ getSnapshot () {
216
+ return settled;
217
+ },
218
+ fork () {
219
+ // Независимый handle из той же фабрики — со своим стором и жизненным циклом.
220
+ return createSynapseModule(factory);
221
+ },
222
+ async destroy () {
223
+ const run = pending;
224
+ const orphans = [
225
+ ...supersededWarmRuns
226
+ ];
227
+ pending = undefined;
228
+ settled = undefined;
229
+ startedWithEffects = false;
230
+ supersededWarmRuns.clear();
231
+ // Сначала прибираем вытесненные апгрейдом прогретые сторы (если были).
232
+ for (const orphan of orphans){
233
+ try {
234
+ await (await orphan).destroy();
235
+ } catch {
236
+ // Прогретый запуск упал — разрушать нечего.
237
+ }
238
+ }
239
+ if (!run) return;
240
+ try {
241
+ const synapse = await run;
242
+ await synapse.destroy();
243
+ } catch {
244
+ // Фабрика/пайплайн упали — разрушать нечего.
245
+ }
246
+ },
247
+ then (onFulfilled, onRejected) {
248
+ return handle.ready().then(onFulfilled, onRejected);
249
+ }
250
+ };
251
+ return handle;
252
+ }
253
+
254
+ export { createSynapseModule };
255
+
256
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils/createSynapse/factory.js","sources":["../../../src/utils/createSynapse/factory.ts"],"sourcesContent":["import type { IStorage } from '../../core'\nimport { Selectors } from '../../core'\nimport type { Effect } from '../../reactive'\nimport { Dispatcher, Effects, EffectsModule, FINALIZE, toObservable } from '../../reactive'\nimport type { Synapse, SynapseConfig, SynapseModule } from './synapse.types'\nimport { waitForDependencies } from './waitForDependencies'\n\n/** Шаг очистки, накапливаемый в порядке конструирования; выполняется в LIFO. */\ntype CleanupStep = () => Promise<void> | void\n\n/**\n * Минимальная runtime-валидация конфига фабрики (`instanceof`-проверки). Полная\n * типизация — на уровне TS; здесь только страховка от грубых ошибок в рантайме.\n */\nfunction validateFactoryConfig(config: SynapseConfig<any, any, any, any>): void {\n if (!config || typeof config !== 'object') {\n throw new Error('createSynapse(factory): фабрика должна вернуть объект-конфиг.')\n }\n const storage = config.storage as IStorage<any> | undefined\n if (!storage || typeof storage.initialize !== 'function' || typeof storage.waitForReady !== 'function') {\n throw new Error('createSynapse(factory): \"storage\" обязателен и должен быть IStorage.')\n }\n if (config.dispatcher && !(config.dispatcher instanceof Dispatcher)) {\n throw new Error('createSynapse(factory): \"dispatcher\" должен быть инстансом класса Dispatcher.')\n }\n if (config.selectors && !(config.selectors instanceof Selectors)) {\n throw new Error('createSynapse(factory): \"selectors\" должен быть инстансом класса Selectors.')\n }\n}\n\n/**\n * Раскладывает `effects` (инстанс, функция или их смесь) в плоский список\n * module-совместимых эффектов + список инстансов `Effects` (для `onDestroy`).\n */\nfunction collectEffects(input: SynapseConfig<any, any, any, any>['effects']): { moduleEffects: Effect[]; instances: Effects<any, any, any>[] } {\n const items = input === undefined ? [] : Array.isArray(input) ? input : [input]\n const moduleEffects: Effect[] = []\n const instances: Effects<any, any, any>[] = []\n\n for (const item of items) {\n if (item instanceof Effects) {\n instances.push(item)\n moduleEffects.push(...item.getEffects())\n } else if (typeof item === 'function') {\n moduleEffects.push(item as Effect)\n } else {\n throw new Error('createSynapse(factory): каждый элемент \"effects\" должен быть инстансом Effects или функцией-эффектом.')\n }\n }\n\n return { moduleEffects, instances }\n}\n\n/** Выполняет накопленные шаги очистки в обратном порядке (LIFO). */\nasync function teardown(cleanup: CleanupStep[]): Promise<void> {\n for (let i = cleanup.length - 1; i >= 0; i--) {\n await cleanup[i]()\n }\n}\n\n/**\n * Полный пайплайн запуска (один раз на `ready()`):\n *\n * 1. `config = await factory()` — async-пролог (await чужих synapse, API-клиенты)\n * 2. минимальная runtime-валидация (instanceof)\n * 3. `await waitForDependencies(...)`\n * 4. `await storage.initialize()`\n * 5. `dispatcher[FINALIZE]()` — имена экшенов из имён полей\n * 6. селекторы уже материализованы конструктором — шага нет\n * 7. `state$ = toObservable(storage)` — всегда\n * 8. `EffectsModule(...)` → `addEffects` → `await start()`\n * 9. teardown в LIFO: stop effects → onDestroy → destroy dispatcher → selectors → storage\n *\n * Любая ошибка любого шага → откат уже созданного (partial teardown) и проброс наверх\n * (никакой тихой частичной инициализации).\n *\n * `withEffects: false` (серверный путь дегидрации, см. {@link SynapseModule.ready}) собирает\n * стор целиком (storage/dispatcher/selectors/state$), но ПРОПУСКАЕТ шаг 8 — эффекты не\n * стартуют. Нужен только снапшот состояния + READY-storage для SSR-seed; запуск эффектов\n * на сервере — лишняя работа (форк) либо «висящие» подписки (синглтон main handle).\n */\nasync function buildSynapse<TState extends Record<string, any>, TDispatcher, TSelectors>(\n factory: () => SynapseConfig<any, any, any, any> | Promise<SynapseConfig<any, any, any, any>>,\n options?: { withEffects?: boolean },\n): Promise<Synapse<TState, TDispatcher, TSelectors>> {\n const { withEffects = true } = options ?? {}\n const config = await factory()\n validateFactoryConfig(config)\n\n const cleanup: CleanupStep[] = []\n\n try {\n await waitForDependencies(config.dependencies, config.dependencyTimeout)\n\n const storage = config.storage as IStorage<TState>\n await storage.initialize()\n cleanup.push(() => storage.destroy())\n\n const selectors = config.selectors as (Selectors<TState> & TSelectors) | undefined\n if (selectors) {\n cleanup.push(() => selectors.destroy())\n }\n\n const dispatcher = config.dispatcher as (Dispatcher<TState> & TDispatcher) | undefined\n if (dispatcher) {\n dispatcher[FINALIZE]()\n cleanup.push(() => dispatcher.destroy())\n }\n\n // state$ — всегда, даже без эффектов.\n const state$ = toObservable(storage)\n\n const { moduleEffects, instances } = collectEffects(config.effects)\n\n // onDestroy инстансов нужен на teardown в любом случае (даже без запуска эффектов).\n const registerInstanceCleanup = () => {\n for (const instance of instances) {\n if (instance.onDestroy) {\n cleanup.push(() => instance.onDestroy!())\n }\n }\n }\n\n if (withEffects && moduleEffects.length > 0) {\n if (!dispatcher) {\n throw new Error('createSynapse(factory): \"effects\" требуют \"dispatcher\".')\n }\n\n const effectsModule = new EffectsModule<TState>(storage, dispatcher as any, (config.externalDispatchers ?? {}) as any)\n effectsModule.addEffects(moduleEffects)\n\n // onDestroy инстансов — перед stop в порядке teardown: пушим onDestroy раньше stop,\n // LIFO-обход выполнит stop первым, затем onDestroy.\n registerInstanceCleanup()\n cleanup.push(() => {\n effectsModule.stop()\n })\n\n await effectsModule.start()\n } else {\n // withEffects: false (серверная дегидрация) либо эффектов нет — EffectsModule не\n // конструируется и не стартует; регистрируем только onDestroy инстансов на teardown.\n registerInstanceCleanup()\n }\n\n let destroyed = false\n const synapse: Synapse<TState, TDispatcher, TSelectors> = {\n storage,\n state$,\n dispatcher: dispatcher as TDispatcher,\n actions: dispatcher as TDispatcher,\n selectors: selectors as TSelectors,\n destroy: async () => {\n if (destroyed) return\n destroyed = true\n await teardown(cleanup)\n },\n }\n\n return synapse\n } catch (error) {\n // Fail-fast: откатываем уже созданное и пробрасываем ошибку.\n await teardown(cleanup).catch(() => {})\n throw error\n }\n}\n\n/**\n * Создаёт ленивый пересоздаваемый handle поверх фабрики. Фабрика исполняется один раз\n * при первом `ready()`/`await`; параллельные `await` делят один промис.\n */\nexport function createSynapseModule<TState extends Record<string, any>, TDispatcher, TSelectors>(\n factory: () => SynapseConfig<any, any, any, any> | Promise<SynapseConfig<any, any, any, any>>,\n): SynapseModule<TState, TDispatcher, TSelectors> {\n let pending: Promise<Synapse<TState, TDispatcher, TSelectors>> | undefined\n let settled: Synapse<TState, TDispatcher, TSelectors> | undefined\n // Был ли текущий мемоизированный запуск собран С эффектами. Нужен для апгрейда\n // прогрев(без эффектов) → честный ready() (см. ниже).\n let startedWithEffects = false\n // Прогретые (без эффектов) запуски, вытесненные апгрейдом до честного ready(). Не рушим их\n // сразу: они могли «утечь» наружу через getSnapshot()/awaiter и ещё обслуживать рендер до\n // переключения на новый стор. Уничтожаем все скопом на destroy() handle.\n const supersededWarmRuns = new Set<Promise<Synapse<TState, TDispatcher, TSelectors>>>()\n\n // Единый запуск пайплайна с мемоизацией.\n //\n // Семантика withEffects:\n // - `ready()` / `ready({ withEffects: true })` — обычный путь: фабрика + эффекты, мемо\n // (pending/settled), повторные вызовы отдают тот же промис.\n // - `ready({ withEffects: false })` — серверный прогрев: собирает стор БЕЗ эффектов, тоже\n // мемоизируется — повторные серверные прогревы main handle переиспользуют стор, а\n // getSnapshot() отдаёт READY-handle для синхронного SSR-seed.\n // - Апгрейд (святой клиентский инвариант): если мемо-запуск собран БЕЗ эффектов, а затем\n // зовут честный `ready()` (с эффектами) — стор пересобирается с эффектами. Прогретый стор\n // при этом ПРОДОЛЖАЕТ обслуживать getSnapshot() (settled не зануляется), пока новый запуск\n // не зарезолвится; затем settled свапается. Прогретый стор НЕ рушим сразу (он мог утечь в\n // awaiter/рендер) — копим в supersededWarmRuns и уничтожаем на destroy() handle. Так\n // getSnapshot() не «проваливается» в undefined (иначе SSR-провайдер показал бы\n // loadingComponent → hydration mismatch), и при этом гарантируем: после\n // `ready({ withEffects: false })` последующий `ready()` всегда вернёт инстанс с запущенными\n // эффектами. Обратно НЕ пересобираем: `withEffects: false` поверх уже запущенного стора\n // отдаёт существующий (эффекты — безопасный супер-сет).\n const start = (withEffects: boolean) => {\n const needsUpgrade = withEffects && pending !== undefined && !startedWithEffects\n\n if (!pending || needsUpgrade) {\n // Устаревший прогретый запуск (если это апгрейд) — переедет в supersededWarmRuns по готовности нового.\n const stale = needsUpgrade ? pending : undefined\n const run = buildSynapse<TState, TDispatcher, TSelectors>(factory, { withEffects })\n pending = run\n startedWithEffects = withEffects\n run.then(\n (synapse) => {\n // Учитываем только если этот запуск всё ещё актуален (не вытеснен destroy/апгрейдом).\n if (pending === run) {\n settled = synapse\n // Свап завершён — помечаем прогретый запуск на уничтожение при destroy() handle.\n if (stale) supersededWarmRuns.add(stale)\n }\n },\n () => {\n // Fail-fast: возвращаем прежний мемо-запуск (или undefined вне апгрейда), чтобы\n // следующий ready() мог повторить попытку; settled (прогретый стор) продолжает\n // обслуживать getSnapshot(). При апгрейде сбрасываем флаг — повтор снова попробует\n // запустить эффекты.\n if (pending === run) {\n pending = stale\n if (stale !== undefined) startedWithEffects = false\n }\n },\n )\n }\n return pending\n }\n\n const handle: SynapseModule<TState, TDispatcher, TSelectors> = {\n ready(options) {\n const { withEffects = true } = options ?? {}\n return start(withEffects)\n },\n\n isReady() {\n return settled !== undefined\n },\n\n getSnapshot() {\n return settled\n },\n\n fork() {\n // Независимый handle из той же фабрики — со своим стором и жизненным циклом.\n return createSynapseModule<TState, TDispatcher, TSelectors>(factory)\n },\n\n async destroy() {\n const run = pending\n const orphans = [...supersededWarmRuns]\n pending = undefined\n settled = undefined\n startedWithEffects = false\n supersededWarmRuns.clear()\n\n // Сначала прибираем вытесненные апгрейдом прогретые сторы (если были).\n for (const orphan of orphans) {\n try {\n await (await orphan).destroy()\n } catch {\n // Прогретый запуск упал — разрушать нечего.\n }\n }\n\n if (!run) return\n try {\n const synapse = await run\n await synapse.destroy()\n } catch {\n // Фабрика/пайплайн упали — разрушать нечего.\n }\n },\n\n then(onFulfilled, onRejected) {\n return handle.ready().then(onFulfilled, onRejected)\n },\n }\n\n return handle\n}\n"],"names":["Selectors","Dispatcher","Effects","EffectsModule","FINALIZE","toObservable","waitForDependencies","validateFactoryConfig","config","Error","storage","collectEffects","input","items","undefined","Array","moduleEffects","instances","item","teardown","cleanup","i","buildSynapse","factory","options","withEffects","selectors","dispatcher","state$","registerInstanceCleanup","instance","effectsModule","destroyed","synapse","error","createSynapseModule","pending","settled","startedWithEffects","supersededWarmRuns","Set","start","needsUpgrade","stale","run","handle","orphans","orphan","onFulfilled","onRejected"],"mappings":";;;;;;;AACsC;AAEqD;AAEhC;AAK3D;;;CAGC,GACD,SAASO,qBAAqBA,CAACC,MAAyC;IACtE,IAAI,CAACA,UAAU,OAAOA,WAAW,UAAU;QACzC,MAAM,IAAIC,MAAM;IAClB;IACA,MAAMC,UAAUF,OAAO,OAAO;IAC9B,IAAI,CAACE,WAAW,OAAOA,QAAQ,UAAU,KAAK,cAAc,OAAOA,QAAQ,YAAY,KAAK,YAAY;QACtG,MAAM,IAAID,MAAM;IAClB;IACA,IAAID,OAAO,UAAU,IAAI,CAAEA,CAAAA,OAAO,UAAU,YAAYP,UAAS,GAAI;QACnE,MAAM,IAAIQ,MAAM;IAClB;IACA,IAAID,OAAO,SAAS,IAAI,CAAEA,CAAAA,OAAO,SAAS,YAAYR,SAAQ,GAAI;QAChE,MAAM,IAAIS,MAAM;IAClB;AACF;AAEA;;;CAGC,GACD,SAASE,cAAcA,CAACC,KAAmD;IACzE,MAAMC,QAAQD,UAAUE,YAAY,EAAE,GAAGC,MAAM,OAAO,CAACH,SAASA,QAAQ;QAACA;KAAM;IAC/E,MAAMI,gBAA0B,EAAE;IAClC,MAAMC,YAAsC,EAAE;IAE9C,KAAK,MAAMC,QAAQL,MAAO;QACxB,IAAIK,gBAAgBhB,OAAOA,EAAE;YAC3Be,UAAU,IAAI,CAACC;YACfF,cAAc,IAAI,IAAIE,KAAK,UAAU;QACvC,OAAO,IAAI,OAAOA,SAAS,YAAY;YACrCF,cAAc,IAAI,CAACE;QACrB,OAAO;YACL,MAAM,IAAIT,MAAM;QAClB;IACF;IAEA,OAAO;QAAEO;QAAeC;IAAU;AACpC;AAEA,kEAAkE,GAClE,eAAeE,QAAQA,CAACC,OAAsB;IAC5C,IAAK,IAAIC,IAAID,QAAQ,MAAM,GAAG,GAAGC,KAAK,GAAGA,IAAK;QAC5C,MAAMD,OAAO,CAACC,EAAE;IAClB;AACF;AAEA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,eAAeC,YAAYA,CACzBC,OAA6F,EAC7FC,OAAmC;IAEnC,MAAM,EAAEC,cAAc,IAAI,EAAE,GAAGD,WAAW,CAAC;IAC3C,MAAMhB,SAAS,MAAMe;IACrBhB,qBAAqBA,CAACC;IAEtB,MAAMY,UAAyB,EAAE;IAEjC,IAAI;QACF,MAAMd,mBAAmBA,CAACE,OAAO,YAAY,EAAEA,OAAO,iBAAiB;QAEvE,MAAME,UAAUF,OAAO,OAAO;QAC9B,MAAME,QAAQ,UAAU;QACxBU,QAAQ,IAAI,CAAC,IAAMV,QAAQ,OAAO;QAElC,MAAMgB,YAAYlB,OAAO,SAAS;QAClC,IAAIkB,WAAW;YACbN,QAAQ,IAAI,CAAC,IAAMM,UAAU,OAAO;QACtC;QAEA,MAAMC,aAAanB,OAAO,UAAU;QACpC,IAAImB,YAAY;YACdA,UAAU,CAACvB,QAAQA,CAAC;YACpBgB,QAAQ,IAAI,CAAC,IAAMO,WAAW,OAAO;QACvC;QAEA,sCAAsC;QACtC,MAAMC,SAASvB,YAAYA,CAACK;QAE5B,MAAM,EAAEM,aAAa,EAAEC,SAAS,EAAE,GAAGN,cAAcA,CAACH,OAAO,OAAO;QAElE,oFAAoF;QACpF,MAAMqB,0BAA0B;YAC9B,KAAK,MAAMC,YAAYb,UAAW;gBAChC,IAAIa,SAAS,SAAS,EAAE;oBACtBV,QAAQ,IAAI,CAAC,IAAMU,SAAS,SAAS;gBACvC;YACF;QACF;QAEA,IAAIL,eAAeT,cAAc,MAAM,GAAG,GAAG;YAC3C,IAAI,CAACW,YAAY;gBACf,MAAM,IAAIlB,MAAM;YAClB;YAEA,MAAMsB,gBAAgB,IAAI5B,aAAaA,CAASO,SAASiB,YAAoBnB,OAAO,mBAAmB,IAAI,CAAC;YAC5GuB,cAAc,UAAU,CAACf;YAEzB,oFAAoF;YACpF,oDAAoD;YACpDa;YACAT,QAAQ,IAAI,CAAC;gBACXW,cAAc,IAAI;YACpB;YAEA,MAAMA,cAAc,KAAK;QAC3B,OAAO;YACL,iFAAiF;YACjF,qFAAqF;YACrFF;QACF;QAEA,IAAIG,YAAY;QAChB,MAAMC,UAAoD;YACxDvB;YACAkB;YACA,YAAYD;YACZ,SAASA;YACT,WAAWD;YACX,SAAS;gBACP,IAAIM,WAAW;gBACfA,YAAY;gBACZ,MAAMb,QAAQA,CAACC;YACjB;QACF;QAEA,OAAOa;IACT,EAAE,OAAOC,OAAO;QACd,6DAA6D;QAC7D,MAAMf,QAAQA,CAACC,SAAS,KAAK,CAAC,KAAO;QACrC,MAAMc;IACR;AACF;AAEA;;;CAGC,GACM,SAASC,mBAAmBA,CACjCZ,OAA6F;IAE7F,IAAIa;IACJ,IAAIC;IACJ,+EAA+E;IAC/E,sDAAsD;IACtD,IAAIC,qBAAqB;IACzB,2FAA2F;IAC3F,0FAA0F;IAC1F,yEAAyE;IACzE,MAAMC,qBAAqB,IAAIC;IAE/B,yCAAyC;IACzC,EAAE;IACF,yBAAyB;IACzB,uFAAuF;IACvF,8DAA8D;IAC9D,0FAA0F;IAC1F,oFAAoF;IACpF,gEAAgE;IAChE,yFAAyF;IACzF,4FAA4F;IAC5F,6FAA6F;IAC7F,4FAA4F;IAC5F,uFAAuF;IACvF,iFAAiF;IACjF,0EAA0E;IAC1E,8FAA8F;IAC9F,0FAA0F;IAC1F,0DAA0D;IAC1D,MAAMC,QAAQ,CAAChB;QACb,MAAMiB,eAAejB,eAAeW,YAAYtB,aAAa,CAACwB;QAE9D,IAAI,CAACF,WAAWM,cAAc;YAC5B,uGAAuG;YACvG,MAAMC,QAAQD,eAAeN,UAAUtB;YACvC,MAAM8B,MAAMtB,YAAYA,CAAkCC,SAAS;gBAAEE;YAAY;YACjFW,UAAUQ;YACVN,qBAAqBb;YACrBmB,IAAI,IAAI,CACN,CAACX;gBACC,sFAAsF;gBACtF,IAAIG,YAAYQ,KAAK;oBACnBP,UAAUJ;oBACV,iFAAiF;oBACjF,IAAIU,OAAOJ,mBAAmB,GAAG,CAACI;gBACpC;YACF,GACA;gBACE,gFAAgF;gBAChF,+EAA+E;gBAC/E,mFAAmF;gBACnF,qBAAqB;gBACrB,IAAIP,YAAYQ,KAAK;oBACnBR,UAAUO;oBACV,IAAIA,UAAU7B,WAAWwB,qBAAqB;gBAChD;YACF;QAEJ;QACA,OAAOF;IACT;IAEA,MAAMS,SAAyD;QAC7D,OAAMrB,OAAO;YACX,MAAM,EAAEC,cAAc,IAAI,EAAE,GAAGD,WAAW,CAAC;YAC3C,OAAOiB,MAAMhB;QACf;QAEA;YACE,OAAOY,YAAYvB;QACrB;QAEA;YACE,OAAOuB;QACT;QAEA;YACE,6EAA6E;YAC7E,OAAOF,mBAAmBA,CAAkCZ;QAC9D;QAEA,MAAM;YACJ,MAAMqB,MAAMR;YACZ,MAAMU,UAAU;mBAAIP;aAAmB;YACvCH,UAAUtB;YACVuB,UAAUvB;YACVwB,qBAAqB;YACrBC,mBAAmB,KAAK;YAExB,uEAAuE;YACvE,KAAK,MAAMQ,UAAUD,QAAS;gBAC5B,IAAI;oBACF,MAAO,OAAMC,MAAK,EAAG,OAAO;gBAC9B,EAAE,OAAM;gBACN,4CAA4C;gBAC9C;YACF;YAEA,IAAI,CAACH,KAAK;YACV,IAAI;gBACF,MAAMX,UAAU,MAAMW;gBACtB,MAAMX,QAAQ,OAAO;YACvB,EAAE,OAAM;YACN,6CAA6C;YAC/C;QACF;QAEA,MAAKe,WAAW,EAAEC,UAAU;YAC1B,OAAOJ,OAAO,KAAK,GAAG,IAAI,CAACG,aAAaC;QAC1C;IACF;IAEA,OAAOJ;AACT"}
@@ -1,3 +1,3 @@
1
1
  export { createSynapse } from './createSynapse';
2
- export type { AnySynapseStore, CreateSynapseConfigBasic, CreateSynapseConfigWithDispatcher, CreateSynapseConfigWithEffects, ExtractDispatchType, ExtractPromiseType, ExtractStorageType, StorageCreatorFunction, SynapseDependency, SynapseStoreBasic, SynapseStoreWithDispatcher, SynapseStoreWithEffects, } from './types';
3
- //# sourceMappingURL=index.d.ts.map
2
+ export type { Synapse, SynapseConfig, SynapseModule } from './synapse.types';
3
+ export type { DependencyInput, ExtractPromiseType, ExtractStorageType, StorageCreatorFunction, SynapseDependency } from './types';
@@ -1 +1 @@
1
- {"version":3,"file":"utils/createSynapse/index.js","sources":["../../../src/utils/createSynapse/index.ts"],"sourcesContent":["export { createSynapse } from './createSynapse'\nexport type {\n AnySynapseStore,\n CreateSynapseConfigBasic,\n CreateSynapseConfigWithDispatcher,\n CreateSynapseConfigWithEffects,\n ExtractDispatchType,\n ExtractPromiseType,\n ExtractStorageType,\n StorageCreatorFunction,\n SynapseDependency,\n SynapseStoreBasic,\n SynapseStoreWithDispatcher,\n SynapseStoreWithEffects,\n} from './types'\n"],"names":["createSynapse"],"mappings":";AAA+C"}
1
+ {"version":3,"file":"utils/createSynapse/index.js","sources":["../../../src/utils/createSynapse/index.ts"],"sourcesContent":["export { createSynapse } from './createSynapse'\nexport type { Synapse, SynapseConfig, SynapseModule } from './synapse.types'\nexport type { DependencyInput, ExtractPromiseType, ExtractStorageType, StorageCreatorFunction, SynapseDependency } from './types'\n"],"names":["createSynapse"],"mappings":";AAA+C"}
@@ -0,0 +1,87 @@
1
+ import type { Observable } from 'rxjs';
2
+ import type { IStorage, Selectors } from '../../core';
3
+ import type { Dispatcher, Effect, Effects } from '../../reactive';
4
+ import type { DependencyInput } from './types';
5
+ /**
6
+ * Конфиг новой (class-based) формы сборки — возвращается фабрикой, переданной в
7
+ * `createSynapse(factory)`. В отличие от старого объект-конфига здесь передаются уже
8
+ * сконструированные инстансы class-слоёв (`Dispatcher`/`Selectors`/`Effects`), а не
9
+ * фабричные функции.
10
+ *
11
+ * @template TState форма состояния хранилища
12
+ * @template TDispatcher инстанс class-диспетчера (или `undefined`, если его нет)
13
+ * @template TSelectors инстанс class-селекторов (или `undefined`)
14
+ * @template TEffects инстанс class-эффектов (или `undefined`)
15
+ */
16
+ export interface SynapseConfig<TState extends Record<string, any>, TDispatcher extends Dispatcher<TState> | undefined = undefined, TSelectors extends Selectors<TState> | undefined = undefined, TEffects extends Effects<TState, NonNullable<TDispatcher>, any> | undefined = undefined> {
17
+ /** Хранилище модуля (создаётся в фабрике; формат тот же, что у старого конфига). */
18
+ storage: IStorage<TState>;
19
+ /** Зависимости от других synapse — формат не меняется (`waitForDependencies`). */
20
+ dependencies?: DependencyInput[];
21
+ /** Таймаут ожидания готовности зависимостей (мс, по умолчанию 30000). */
22
+ dependencyTimeout?: number;
23
+ /** Инстанс class-диспетчера. Финализируется сборщиком (имена экшенов из имён полей). */
24
+ dispatcher?: TDispatcher;
25
+ /** Инстанс class-селекторов (уже материализованы конструктором). */
26
+ selectors?: TSelectors;
27
+ /** Class-эффекты и/или legacy-функции вперемешку. */
28
+ effects?: TEffects | Array<TEffects | Effect>;
29
+ /** Чужие диспетчеры, чьи экшены вливаются в `action$` (вариант коммуникации 3). */
30
+ externalDispatchers?: TEffects extends Effects<any, any, infer TExt> ? TExt : Record<string, Dispatcher<any>>;
31
+ }
32
+ /**
33
+ * Готовый synapse — результат запуска фабрики (`SynapseModule.ready()`).
34
+ */
35
+ export interface Synapse<TState extends Record<string, any>, TDispatcher, TSelectors> {
36
+ storage: IStorage<TState>;
37
+ /** Поток состояния — присутствует ВСЕГДА, даже без эффектов. */
38
+ state$: Observable<TState>;
39
+ /** Инстанс class-диспетчера (полный тип). `undefined`, если диспетчера нет. */
40
+ dispatcher: TDispatcher;
41
+ /** Алиас диспетчера: его поля и есть dispatch-функции. */
42
+ actions: TDispatcher;
43
+ /** Инстанс class-селекторов. `undefined`, если селекторов нет. */
44
+ selectors: TSelectors;
45
+ destroy(): Promise<void>;
46
+ }
47
+ /**
48
+ * Ленивый синглтон-handle. Фабрика исполняется один раз при первом `await`/`ready()`,
49
+ * а не на импорте — это поглощает userland-обёртку `createFeatureSynapse` и чинит
50
+ * SSR-боль жадного запуска при импорте.
51
+ *
52
+ * Handle — пересоздаваемый: `destroy()` сбрасывает мемоизацию, следующий `ready()`
53
+ * заново исполняет фабрику.
54
+ */
55
+ export interface SynapseModule<TState extends Record<string, any>, TDispatcher, TSelectors> extends PromiseLike<Synapse<TState, TDispatcher, TSelectors>> {
56
+ /**
57
+ * Первый вызов запускает фабрику и весь пайплайн; повторные — отдают тот же промис.
58
+ *
59
+ * `withEffects` (по умолчанию `true`) — запускать ли RxJS-эффекты:
60
+ * - `true` (клиент) — полноценный запуск со стартом эффектов;
61
+ * - `false` (серверный прогрев дегидрации, см. {@link import('../dehydrateModule').dehydrateModule})
62
+ * собирает стор целиком (storage/dispatcher/selectors/state$) для снапшота и SSR-seed,
63
+ * но пропускает `effectsModule.start()`.
64
+ *
65
+ * Мемо-семантика: прогрев (`withEffects: false`) тоже мемоизируется, но последующий честный
66
+ * `ready()` (с эффектами) пересоберёт стор и запустит эффекты — инвариант «клиентский
67
+ * `ready()` обязан стартовать эффекты» соблюдён.
68
+ */
69
+ ready(options?: {
70
+ withEffects?: boolean;
71
+ }): Promise<Synapse<TState, TDispatcher, TSelectors>>;
72
+ /** Запущена ли фабрика и успешно ли резолвился synapse. */
73
+ isReady(): boolean;
74
+ /**
75
+ * Синхронный доступ к уже собранному synapse (или `undefined`, если ещё не готов).
76
+ * Нужен SSR-биндингу: позволяет отдать стор на первом синхронном рендере без `await`.
77
+ */
78
+ getSnapshot(): Synapse<TState, TDispatcher, TSelectors> | undefined;
79
+ /**
80
+ * Создаёт независимый handle из той же фабрики. Каждый fork — со своим жизненным циклом
81
+ * и состоянием (общего стора нет). Нужен для per-request изоляции на сервере (SSR):
82
+ * `dehydrate` форкает модуль, чтобы параллельные запросы не делили состояние.
83
+ */
84
+ fork(): SynapseModule<TState, TDispatcher, TSelectors>;
85
+ /** Останавливает модуль (LIFO-teardown) и сбрасывает мемоизацию (пересоздаваемость). */
86
+ destroy(): Promise<void>;
87
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Ленивый синглтон-handle. Фабрика исполняется один раз при первом `await`/`ready()`,
3
+ * а не на импорте — это поглощает userland-обёртку `createFeatureSynapse` и чинит
4
+ * SSR-боль жадного запуска при импорте.
5
+ *
6
+ * Handle — пересоздаваемый: `destroy()` сбрасывает мемоизацию, следующий `ready()`
7
+ * заново исполняет фабрику.
8
+ */
9
+
10
+
11
+ //# sourceMappingURL=synapse.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils/createSynapse/synapse.types.js","sources":["../../../src/utils/createSynapse/synapse.types.ts"],"sourcesContent":["import type { Observable } from 'rxjs'\n\nimport type { IStorage, Selectors } from '../../core'\nimport type { Dispatcher, Effect, Effects } from '../../reactive'\nimport type { DependencyInput } from './types'\n\n/**\n * Конфиг новой (class-based) формы сборки — возвращается фабрикой, переданной в\n * `createSynapse(factory)`. В отличие от старого объект-конфига здесь передаются уже\n * сконструированные инстансы class-слоёв (`Dispatcher`/`Selectors`/`Effects`), а не\n * фабричные функции.\n *\n * @template TState форма состояния хранилища\n * @template TDispatcher инстанс class-диспетчера (или `undefined`, если его нет)\n * @template TSelectors инстанс class-селекторов (или `undefined`)\n * @template TEffects инстанс class-эффектов (или `undefined`)\n */\nexport interface SynapseConfig<\n TState extends Record<string, any>,\n TDispatcher extends Dispatcher<TState> | undefined = undefined,\n TSelectors extends Selectors<TState> | undefined = undefined,\n TEffects extends Effects<TState, NonNullable<TDispatcher>, any> | undefined = undefined,\n> {\n /** Хранилище модуля (создаётся в фабрике; формат тот же, что у старого конфига). */\n storage: IStorage<TState>\n /** Зависимости от других synapse — формат не меняется (`waitForDependencies`). */\n dependencies?: DependencyInput[]\n /** Таймаут ожидания готовности зависимостей (мс, по умолчанию 30000). */\n dependencyTimeout?: number\n /** Инстанс class-диспетчера. Финализируется сборщиком (имена экшенов из имён полей). */\n dispatcher?: TDispatcher\n /** Инстанс class-селекторов (уже материализованы конструктором). */\n selectors?: TSelectors\n /** Class-эффекты и/или legacy-функции вперемешку. */\n effects?: TEffects | Array<TEffects | Effect>\n /** Чужие диспетчеры, чьи экшены вливаются в `action$` (вариант коммуникации 3). */\n externalDispatchers?: TEffects extends Effects<any, any, infer TExt> ? TExt : Record<string, Dispatcher<any>>\n}\n\n/**\n * Готовый synapse — результат запуска фабрики (`SynapseModule.ready()`).\n */\nexport interface Synapse<TState extends Record<string, any>, TDispatcher, TSelectors> {\n storage: IStorage<TState>\n /** Поток состояния — присутствует ВСЕГДА, даже без эффектов. */\n state$: Observable<TState>\n /** Инстанс class-диспетчера (полный тип). `undefined`, если диспетчера нет. */\n dispatcher: TDispatcher\n /** Алиас диспетчера: его поля и есть dispatch-функции. */\n actions: TDispatcher\n /** Инстанс class-селекторов. `undefined`, если селекторов нет. */\n selectors: TSelectors\n destroy(): Promise<void>\n}\n\n/**\n * Ленивый синглтон-handle. Фабрика исполняется один раз при первом `await`/`ready()`,\n * а не на импорте — это поглощает userland-обёртку `createFeatureSynapse` и чинит\n * SSR-боль жадного запуска при импорте.\n *\n * Handle — пересоздаваемый: `destroy()` сбрасывает мемоизацию, следующий `ready()`\n * заново исполняет фабрику.\n */\nexport interface SynapseModule<TState extends Record<string, any>, TDispatcher, TSelectors> extends PromiseLike<Synapse<TState, TDispatcher, TSelectors>> {\n /**\n * Первый вызов запускает фабрику и весь пайплайн; повторные — отдают тот же промис.\n *\n * `withEffects` (по умолчанию `true`) — запускать ли RxJS-эффекты:\n * - `true` (клиент) — полноценный запуск со стартом эффектов;\n * - `false` (серверный прогрев дегидрации, см. {@link import('../dehydrateModule').dehydrateModule})\n * собирает стор целиком (storage/dispatcher/selectors/state$) для снапшота и SSR-seed,\n * но пропускает `effectsModule.start()`.\n *\n * Мемо-семантика: прогрев (`withEffects: false`) тоже мемоизируется, но последующий честный\n * `ready()` (с эффектами) пересоберёт стор и запустит эффекты — инвариант «клиентский\n * `ready()` обязан стартовать эффекты» соблюдён.\n */\n ready(options?: { withEffects?: boolean }): Promise<Synapse<TState, TDispatcher, TSelectors>>\n /** Запущена ли фабрика и успешно ли резолвился synapse. */\n isReady(): boolean\n /**\n * Синхронный доступ к уже собранному synapse (или `undefined`, если ещё не готов).\n * Нужен SSR-биндингу: позволяет отдать стор на первом синхронном рендере без `await`.\n */\n getSnapshot(): Synapse<TState, TDispatcher, TSelectors> | undefined\n /**\n * Создаёт независимый handle из той же фабрики. Каждый fork — со своим жизненным циклом\n * и состоянием (общего стора нет). Нужен для per-request изоляции на сервере (SSR):\n * `dehydrate` форкает модуль, чтобы параллельные запросы не делили состояние.\n */\n fork(): SynapseModule<TState, TDispatcher, TSelectors>\n /** Останавливает модуль (LIFO-teardown) и сбрасывает мемоизацию (пересоздаваемость). */\n destroy(): Promise<void>\n}\n"],"names":[],"mappings":"AAuDA;;;;;;;CAOC,GA+BA"}