synapse-storage 4.1.1 → 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 +9 -2
  96. package/dist/core/storage/utils/state-diff.util.js +30 -3
  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
@@ -26,4 +26,3 @@ export declare function buildRequestUrl(path: string, baseUrl: string): URL;
26
26
  * @returns Функция для выполнения запросов
27
27
  */
28
28
  export declare function fetchBaseQuery(options: Omit<FetchBaseQueryArgs, 'prepareHeaders'>): <RequestResult, RequestParams extends Record<string, any>, E extends Error = Error>(args: RequestDefinition<RequestParams>, queryOptions: QueryOptions | undefined, headers: Headers) => Promise<QueryResult<RequestResult, E>>;
29
- //# sourceMappingURL=fetch-base-query.d.ts.map
@@ -40,4 +40,3 @@ export declare function revokeBlobUrl(url: string): void;
40
40
  * @param filename Имя файла
41
41
  */
42
42
  export declare function downloadBlob(blob: Blob, filename: string): void;
43
- //# sourceMappingURL=file-utils.d.ts.map
@@ -5,4 +5,3 @@
5
5
  * @returns Объект с отфильтрованными заголовками
6
6
  */
7
7
  export declare function getCacheableHeaders(headers: Headers, cacheableHeaders?: string[]): Record<string, string>;
8
- //# sourceMappingURL=get-cacheable-headers.d.ts.map
@@ -1,3 +1,2 @@
1
1
  export * from './selector';
2
2
  export * from './storage';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,3 @@
1
1
  export type { ISelectorModule, SelectorAPI } from './selector.interface';
2
2
  export * from './selector.module';
3
- //# sourceMappingURL=index.d.ts.map
3
+ export * from './selectors.base';
@@ -1,4 +1,6 @@
1
1
  export * from "./selector.module.js";
2
+ export * from "./selectors.base.js";
3
+
2
4
 
3
5
 
4
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"core/selector/index.js","sources":["../../../src/core/selector/index.ts"],"sourcesContent":["export type { ISelectorModule, SelectorAPI } from './selector.interface'\nexport * from './selector.module'\n"],"names":[],"mappings":";AACiC"}
1
+ {"version":3,"file":"core/selector/index.js","sources":["../../../src/core/selector/index.ts"],"sourcesContent":["export type { ISelectorModule, SelectorAPI } from './selector.interface'\nexport * from './selector.module'\nexport * from './selectors.base'\n"],"names":[],"mappings":";;AACiC;AACD"}
@@ -1,3 +1,4 @@
1
+ import type { Observable } from 'rxjs';
1
2
  export interface Selector<T, R> {
2
3
  (state: T): R;
3
4
  }
@@ -13,6 +14,12 @@ export interface SelectorAPI<T> {
13
14
  selectSync: () => T;
14
15
  subscribe: (subscriber: Subscriber<T>) => VoidFunction;
15
16
  getId: () => string;
17
+ /**
18
+ * Observable-вид селектора: эмитит текущее значение при подписке и при каждом
19
+ * реальном изменении (та же семантика, что у `subscribe`). Позволяет реактивно
20
+ * трансформировать чтение прямо в компоненте — `selector.$.pipe(debounceTime(300))`.
21
+ */
22
+ readonly $: Observable<T>;
16
23
  /** @internal — проверка готовности источника данных */
17
24
  isSourceReady: () => boolean;
18
25
  /** @internal — подписка на изменение статуса источника */
@@ -60,37 +67,15 @@ export interface ISelectorModule<TStore extends Record<string, any>> {
60
67
  [K in keyof Deps]: SelectorAPI<Deps[K]>;
61
68
  }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>;
62
69
  /**
63
- * Освобождает ресурсы, связанные с модулем селекторов
70
+ * Точечно удаляет один селектор по его id (`SelectorAPI.getId()`): снимает подписки
71
+ * на хранилище и чистит кэш, не затрагивая остальные селекторы модуля. Нужен для
72
+ * keyed-кэша и для `destroy()` class-селекторов, владеющих общим модулем.
73
+ *
74
+ * @param id Идентификатор селектора (`selector.getId()`)
64
75
  */
65
- destroy(): void;
66
- }
67
- /**
68
- * Интерфейс для фабрики селекторов
69
- * Позволяет создавать набор связанных селекторов
70
- */
71
- export interface ISelectorCreator<TStore extends Record<string, any>, TSelectors, TExternalSelectors = Record<string, any>> {
76
+ removeSelector(id: string): void;
72
77
  /**
73
- * Создает набор селекторов
74
- *
75
- * @param selectorModule Модуль селекторов
76
- * @param externalSelectors Внешние селекторы (опционально)
77
- * @returns Объект с селекторами
78
- *
79
- * @example
80
- * const createUserSelectors: ISelectorCreator<UserStore, UserSelectors> =
81
- * (selectorModule, externalSelectors) => {
82
- * const isActive = selectorModule.createSelector(
83
- * (state) => state.user.isActive
84
- * );
85
- *
86
- * return { isActive };
87
- * };
78
+ * Освобождает ресурсы, связанные с модулем селекторов
88
79
  */
89
- (selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors): TSelectors;
80
+ destroy(): void;
90
81
  }
91
- /**
92
- * Тип для функции, создающей селекторы
93
- * Более простая версия ISelectorCreator, если не нужен полный интерфейс
94
- */
95
- export type SelectorCreatorFunction<TStore extends Record<string, any> = Record<string, any>, TSelectors = any, TExternalSelectors = Record<string, any>> = (selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors) => TSelectors;
96
- //# sourceMappingURL=selector.interface.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Тип для функции, создающей селекторы
3
- * Более простая версия ISelectorCreator, если не нужен полный интерфейс
2
+ * Интерфейс для модуля селекторов
3
+ * Определяет контракт для работы с селекторами, который должен реализовывать SelectorModule
4
4
  */
5
5
 
6
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"core/selector/selector.interface.js","sources":["../../../src/core/selector/selector.interface.ts"],"sourcesContent":["export interface Selector<T, R> {\n (state: T): R\n}\n\nexport interface SelectorOptions<T> {\n equals?: (a: T, b: T) => boolean\n name?: string\n}\n\nexport interface Subscriber<T> {\n notify: (value: T) => void | Promise<void>\n}\n\nexport interface SelectorAPI<T> {\n select: () => T\n selectSync: () => T\n subscribe: (subscriber: Subscriber<T>) => VoidFunction\n getId: () => string\n /** @internal — проверка готовности источника данных */\n isSourceReady: () => boolean\n /** @internal — подписка на изменение статуса источника */\n onSourceStatusChange: (callback: (isReady: boolean) => void) => VoidFunction\n}\n\n/**\n * Интерфейс для модуля селекторов\n * Определяет контракт для работы с селекторами, который должен реализовывать SelectorModule\n */\nexport interface ISelectorModule<TStore extends Record<string, any>> {\n /**\n * Имя связанного хранилища\n */\n readonly storageName: string\n\n /**\n * Создает простой селектор на основе функции выбора\n *\n * @param selector Функция, извлекающая данные из состояния\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const isActive = selectorModule.createSelector(\n * (state) => state.user.isActive,\n * { name: 'userIsActive' }\n * );\n */\n createSelector<T>(selector: Selector<TStore, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Создает комбинированный селектор на основе других селекторов\n *\n * @param dependencies Массив селекторов, от которых зависит новый селектор\n * @param resultFn Функция, комбинирующая результаты зависимостей\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const userWithStatus = selectorModule.createSelector(\n * [userSelector, statusSelector],\n * (user, status) => ({ ...user, status }),\n * { name: 'userWithStatus' }\n * );\n */\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Освобождает ресурсы, связанные с модулем селекторов\n */\n destroy(): void\n}\n\n/**\n * Интерфейс для фабрики селекторов\n * Позволяет создавать набор связанных селекторов\n */\nexport interface ISelectorCreator<TStore extends Record<string, any>, TSelectors, TExternalSelectors = Record<string, any>> {\n /**\n * Создает набор селекторов\n *\n * @param selectorModule Модуль селекторов\n * @param externalSelectors Внешние селекторы (опционально)\n * @returns Объект с селекторами\n *\n * @example\n * const createUserSelectors: ISelectorCreator<UserStore, UserSelectors> =\n * (selectorModule, externalSelectors) => {\n * const isActive = selectorModule.createSelector(\n * (state) => state.user.isActive\n * );\n *\n * return { isActive };\n * };\n */\n (selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors): TSelectors\n}\n\n/**\n * Тип для функции, создающей селекторы\n * Более простая версия ISelectorCreator, если не нужен полный интерфейс\n */\nexport type SelectorCreatorFunction<TStore extends Record<string, any> = Record<string, any>, TSelectors = any, TExternalSelectors = Record<string, any>> = (\n selectorModule: ISelectorModule<TStore>,\n externalSelectors?: TExternalSelectors,\n) => TSelectors\n"],"names":[],"mappings":"AAiGA;;;CAGC,GAIc"}
1
+ {"version":3,"file":"core/selector/selector.interface.js","sources":["../../../src/core/selector/selector.interface.ts"],"sourcesContent":["import type { Observable } from 'rxjs'\n\nexport interface Selector<T, R> {\n (state: T): R\n}\n\nexport interface SelectorOptions<T> {\n equals?: (a: T, b: T) => boolean\n name?: string\n}\n\nexport interface Subscriber<T> {\n notify: (value: T) => void | Promise<void>\n}\n\nexport interface SelectorAPI<T> {\n select: () => T\n selectSync: () => T\n subscribe: (subscriber: Subscriber<T>) => VoidFunction\n getId: () => string\n /**\n * Observable-вид селектора: эмитит текущее значение при подписке и при каждом\n * реальном изменении (та же семантика, что у `subscribe`). Позволяет реактивно\n * трансформировать чтение прямо в компоненте — `selector.$.pipe(debounceTime(300))`.\n */\n readonly $: Observable<T>\n /** @internal — проверка готовности источника данных */\n isSourceReady: () => boolean\n /** @internal — подписка на изменение статуса источника */\n onSourceStatusChange: (callback: (isReady: boolean) => void) => VoidFunction\n}\n\n/**\n * Интерфейс для модуля селекторов\n * Определяет контракт для работы с селекторами, который должен реализовывать SelectorModule\n */\nexport interface ISelectorModule<TStore extends Record<string, any>> {\n /**\n * Имя связанного хранилища\n */\n readonly storageName: string\n\n /**\n * Создает простой селектор на основе функции выбора\n *\n * @param selector Функция, извлекающая данные из состояния\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const isActive = selectorModule.createSelector(\n * (state) => state.user.isActive,\n * { name: 'userIsActive' }\n * );\n */\n createSelector<T>(selector: Selector<TStore, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Создает комбинированный селектор на основе других селекторов\n *\n * @param dependencies Массив селекторов, от которых зависит новый селектор\n * @param resultFn Функция, комбинирующая результаты зависимостей\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const userWithStatus = selectorModule.createSelector(\n * [userSelector, statusSelector],\n * (user, status) => ({ ...user, status }),\n * { name: 'userWithStatus' }\n * );\n */\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Точечно удаляет один селектор по его id (`SelectorAPI.getId()`): снимает подписки\n * на хранилище и чистит кэш, не затрагивая остальные селекторы модуля. Нужен для\n * keyed-кэша и для `destroy()` class-селекторов, владеющих общим модулем.\n *\n * @param id Идентификатор селектора (`selector.getId()`)\n */\n removeSelector(id: string): void\n\n /**\n * Освобождает ресурсы, связанные с модулем селекторов\n */\n destroy(): void\n}\n"],"names":[],"mappings":"AAgCA;;;CAGC,GAoDA"}
@@ -14,7 +14,17 @@ export declare class SelectorModule<S extends Record<string, any>> implements IS
14
14
  private localSelectorCache;
15
15
  private batchUpdateInProgress;
16
16
  private pendingUpdates;
17
+ private readonly disposeStatusListener;
17
18
  constructor(source: IStorage<S>, logger?: ILogger | undefined);
19
+ /**
20
+ * Собирает публичный `SelectorAPI` поверх подписки. `$` — Observable-вид с той же
21
+ * семантикой, что у `subscribe`: синхронный снапшот при подписке + emit на изменение.
22
+ *
23
+ * `sourceReadiness` переопределяет дефолтную (локальную) готовность источника: для
24
+ * combined-селекторов туда передаётся агрегированная готовность по всем источникам
25
+ * зависимостей (см. {@link createCombinedSelector}).
26
+ */
27
+ private buildSelectorApi;
18
28
  private isSourceReady;
19
29
  private onSourceStatusChange;
20
30
  /**
@@ -31,6 +41,11 @@ export declare class SelectorModule<S extends Record<string, any>> implements IS
31
41
  }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>;
32
42
  private createSimpleSelector;
33
43
  private createCombinedSelector;
44
+ /**
45
+ * Точечно удаляет селектор по id: снимает его подписки на хранилище, чистит подписку
46
+ * и кэш. Остальные селекторы модуля не затрагиваются. Имя кэша совпадает с id подписки
47
+ * (`generateName()`/`options.name`), поэтому достаточно одного ключа.
48
+ */
49
+ removeSelector(id: string): void;
34
50
  destroy(): void;
35
51
  }
36
- //# sourceMappingURL=selector.module.d.ts.map
@@ -1,7 +1,10 @@
1
+ import { Observable } from "rxjs";
1
2
  import { StorageStatus } from "../storage/index.js";
2
3
 
3
4
 
4
5
 
6
+
7
+
5
8
  /**
6
9
  * Reference equality (===) — поведение по умолчанию
7
10
  */ function defaultEquals(a, b) {
@@ -174,10 +177,54 @@ class SelectorModule {
174
177
  // Флаг для батчинга обновлений
175
178
  batchUpdateInProgress = false;
176
179
  pendingUpdates = new Set();
180
+ // Снятие подписки на статус источника (см. конструктор) — вызывается в destroy().
181
+ disposeStatusListener;
177
182
  constructor(source, logger){
178
183
  this.source = source;
179
184
  this.logger = logger;
180
185
  this.storageName = source.name;
186
+ // Селекторы конструируются ДО storage.initialize() (так устроен пайплайн createSynapse:
187
+ // фабрика создаёт селекторы, и только потом buildSynapse зовёт initialize()). На этот
188
+ // момент getStateSync() === {}. combine-селектор при создании эагерно подписывается на
189
+ // зависимости и СИНХРОННО вычисляет их (SelectorSubscription.subscribe при !hasValue),
190
+ // т.е. кеширует значение от пустого стора. А performInitialize наполняет _stateCache
191
+ // молча, без storage:update, — значит этот кеш сам по себе уже не обновится.
192
+ // Поэтому на переходе источника в READY принудительно пересчитываем все подписки.
193
+ // Порядок Map = порядок создания, а зависимость всегда создаётся раньше зависимого
194
+ // (combine([this.api]) невозможен до this.api) → пересчёт идёт «снизу вверх» корректно.
195
+ this.disposeStatusListener = this.source.onStatusChange((status)=>{
196
+ if (status.status === StorageStatus.READY) {
197
+ this.subscriptions.forEach((sub)=>{
198
+ try {
199
+ sub.notify();
200
+ } catch (error) {
201
+ this.logger?.error(`[${sub.getId()}] Ошибка пересчёта на READY`, {
202
+ error
203
+ });
204
+ }
205
+ });
206
+ }
207
+ });
208
+ }
209
+ /**
210
+ * Собирает публичный `SelectorAPI` поверх подписки. `$` — Observable-вид с той же
211
+ * семантикой, что у `subscribe`: синхронный снапшот при подписке + emit на изменение.
212
+ *
213
+ * `sourceReadiness` переопределяет дефолтную (локальную) готовность источника: для
214
+ * combined-селекторов туда передаётся агрегированная готовность по всем источникам
215
+ * зависимостей (см. {@link createCombinedSelector}).
216
+ */ buildSelectorApi(id, subscription, getState, sourceReadiness) {
217
+ return {
218
+ select: ()=>getState(),
219
+ selectSync: ()=>subscription.getValue(),
220
+ subscribe: (subscriber)=>subscription.subscribe(subscriber),
221
+ getId: ()=>id,
222
+ $: new Observable((observer)=>subscription.subscribe({
223
+ notify: (value)=>observer.next(value)
224
+ })),
225
+ isSourceReady: sourceReadiness?.isSourceReady ?? this.isSourceReady,
226
+ onSourceStatusChange: sourceReadiness?.onSourceStatusChange ?? this.onSourceStatusChange
227
+ };
181
228
  }
182
229
  isSourceReady = ()=>{
183
230
  return this.source.initStatus.status === StorageStatus.READY;
@@ -303,16 +350,7 @@ class SelectorModule {
303
350
  unsubscribeFromStorage
304
351
  ];
305
352
  return {
306
- api: {
307
- select: ()=>getState(),
308
- selectSync: ()=>subscription.getValue(),
309
- subscribe: (subscriber)=>{
310
- return subscription.subscribe(subscriber);
311
- },
312
- getId: ()=>id,
313
- isSourceReady: this.isSourceReady,
314
- onSourceStatusChange: this.onSourceStatusChange
315
- },
353
+ api: this.buildSelectorApi(id, subscription, getState),
316
354
  unsubscribeFunctions
317
355
  };
318
356
  }
@@ -379,21 +417,45 @@ class SelectorModule {
379
417
  unsubscribeFunctions.push(()=>{
380
418
  destroyed = true;
381
419
  });
420
+ // Агрегированная готовность источников: combined-селектор «готов», только когда готов
421
+ // ЛОКАЛЬНЫЙ источник И все источники зависимостей (важно для cross-store combine, где
422
+ // зависимости приходят из других сторов с собственным lifecycle).
423
+ const aggregatedSourceReadiness = {
424
+ isSourceReady: ()=>this.isSourceReady() && selectors.every((dep)=>dep.isSourceReady()),
425
+ onSourceStatusChange: (callback)=>{
426
+ const emit = ()=>callback(aggregatedSourceReadiness.isSourceReady());
427
+ const disposers = [
428
+ this.onSourceStatusChange(emit),
429
+ ...selectors.map((dep)=>dep.onSourceStatusChange(emit))
430
+ ];
431
+ return ()=>disposers.forEach((dispose)=>dispose());
432
+ }
433
+ };
382
434
  return {
383
- api: {
384
- select: ()=>getState(),
385
- selectSync: ()=>subscription.getValue(),
386
- subscribe: (subscriber)=>{
387
- return subscription.subscribe(subscriber);
388
- },
389
- getId: ()=>id,
390
- isSourceReady: this.isSourceReady,
391
- onSourceStatusChange: this.onSourceStatusChange
392
- },
435
+ api: this.buildSelectorApi(id, subscription, getState, aggregatedSourceReadiness),
393
436
  unsubscribeFunctions
394
437
  };
395
438
  }
439
+ /**
440
+ * Точечно удаляет селектор по id: снимает его подписки на хранилище, чистит подписку
441
+ * и кэш. Остальные селекторы модуля не затрагиваются. Имя кэша совпадает с id подписки
442
+ * (`generateName()`/`options.name`), поэтому достаточно одного ключа.
443
+ */ removeSelector(id) {
444
+ const subscription = this.subscriptions.get(id);
445
+ if (subscription) {
446
+ subscription.cleanup();
447
+ this.subscriptions.delete(id);
448
+ }
449
+ this.pendingUpdates.delete(id);
450
+ const cached = this.localSelectorCache.get(id);
451
+ if (cached) {
452
+ cached.unsubscribeFunctions.forEach((unsub)=>unsub());
453
+ this.localSelectorCache.delete(id);
454
+ }
455
+ }
396
456
  destroy() {
457
+ // Снимаем подписку на статус источника
458
+ this.disposeStatusListener();
397
459
  // Очищаем все подписки
398
460
  this.subscriptions.forEach((sub)=>sub.cleanup());
399
461
  this.subscriptions.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"core/selector/selector.module.js","sources":["../../../src/core/selector/selector.module.ts"],"sourcesContent":["import type { ILogger, IStorage, StorageInitStatus } from '../storage'\nimport { StorageStatus } from '../storage'\nimport type { ISelectorModule, Selector, SelectorAPI, SelectorOptions, Subscriber } from './selector.interface'\n\n/**\n * Reference equality (===) — поведение по умолчанию\n */\nfunction defaultEquals<T>(a: T, b: T): boolean {\n return a === b\n}\n\nconst MAX_DEEP_EQUAL_DEPTH = 10\n\n/**\n * Глубокое сравнение объектов по структуре с защитой от циклических ссылок и лимитом глубины.\n * Используется только при явной передаче через options.equals.\n */\nexport function deepEquals<T>(a: T, b: T, depth = 0, visited = new WeakSet()): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n if (depth > MAX_DEEP_EQUAL_DEPTH) return false\n\n if (typeof a !== 'object') return a === b\n\n // Защита от циклических ссылок\n if (visited.has(a as object)) return false\n visited.add(a as object)\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!deepEquals(a[i], b[i], depth + 1, visited)) return false\n }\n return true\n }\n\n if (Array.isArray(a) || Array.isArray(b)) return false\n\n const keysA = Object.keys(a as object)\n const keysB = Object.keys(b as object)\n\n if (keysA.length !== keysB.length) return false\n\n return keysA.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n return deepEquals((a as any)[key], (b as any)[key], depth + 1, visited)\n })\n}\n\n/**\n * Оборачивает state в Proxy для отслеживания обращений к ключам верхнего уровня.\n * Возвращает проксированный state и Set с именами ключей, к которым обратился селектор.\n */\nfunction trackDependencies<S extends Record<string, any>>(state: S): { proxy: S; accessedKeys: Set<string> } {\n const accessedKeys = new Set<string>()\n\n const proxy = new Proxy(state, {\n get(target, prop, receiver) {\n if (typeof prop === 'string') {\n accessedKeys.add(prop)\n }\n return Reflect.get(target, prop, receiver)\n },\n })\n\n return { proxy, accessedKeys }\n}\n\n// Мемоизирует функцию селектора для оптимизации + трекинг зависимостей через Proxy\nfunction memoizeSelector<S extends Record<string, any>, R>(\n selectorFn: (state: S) => R,\n equals: (a: R, b: R) => boolean = defaultEquals,\n): { memoized: (state: S) => R; getTrackedKeys: () => Set<string> | null } {\n let lastState: S | undefined\n let lastResult: R | undefined\n let hasResult = false\n let trackedKeys: Set<string> | null = null\n\n const memoized = function (state: S): R {\n // Если это первый вызов или состояние изменилось\n if (!hasResult || lastState !== state) {\n // Трекаем зависимости через Proxy при каждом реальном пересчёте\n const { proxy, accessedKeys } = trackDependencies(state)\n const newResult = selectorFn(proxy)\n trackedKeys = accessedKeys\n\n // Проверяем, изменился ли результат\n if (!hasResult || !equals(newResult, lastResult as R)) {\n lastResult = newResult\n }\n\n lastState = state\n hasResult = true\n }\n\n return lastResult as R\n }\n\n return { memoized, getTrackedKeys: () => trackedKeys }\n}\n\nclass SelectorSubscription<T> {\n private readonly id: string\n readonly subscribers = new Set<Subscriber<T>>()\n private lastValue?: T\n private hasValue = false\n\n constructor(\n private readonly name: string,\n private readonly getState: () => T,\n private readonly equals: (a: T, b: T) => boolean = defaultEquals,\n private readonly logger?: ILogger,\n ) {\n this.id = name\n this.logger?.debug(`[${this.id}] SelectorSubscription created`)\n }\n\n notify(): void {\n try {\n const newValue = this.getState()\n\n // Проверка на изменение значения с использованием функции сравнения\n if (!this.hasValue || !this.equals(newValue, this.lastValue as T)) {\n this.logger?.debug(`[${this.id}] Value changed, notify()`)\n\n this.lastValue = newValue\n this.hasValue = true\n\n for (const subscriber of this.subscribers) {\n try {\n subscriber.notify(newValue)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, { error })\n }\n }\n }\n } catch (error: any) {\n this.logger?.error(`[${this.id}] Ошибка в notify()`, { error })\n throw error\n }\n }\n\n subscribe(subscriber: Subscriber<T>): VoidFunction {\n this.subscribers.add(subscriber)\n\n // Отправляем текущее значение синхронно\n if (this.hasValue) {\n try {\n subscriber.notify(this.lastValue as T)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n }\n } else {\n // Вычисляем значение синхронно\n this.notify()\n }\n\n return () => {\n this.subscribers.delete(subscriber)\n }\n }\n\n cleanup(): void {\n this.subscribers.clear()\n this.lastValue = undefined\n this.hasValue = false\n }\n\n getLastValue(): T | undefined {\n return this.lastValue\n }\n\n getValue(): T {\n if (!this.hasValue) {\n this.lastValue = this.getState()\n this.hasValue = true\n }\n return this.lastValue as T\n }\n\n getId(): string {\n return this.id\n }\n}\n\nexport class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {\n storageName: string\n\n private selectorIdCounter = 0\n private subscriptions = new Map<string, SelectorSubscription<any>>()\n\n private localSelectorCache = new Map<\n string,\n {\n api: SelectorAPI<any>\n dependencies?: SelectorAPI<any>[]\n unsubscribeFunctions: Array<() => void>\n }\n >()\n\n // Флаг для батчинга обновлений\n private batchUpdateInProgress = false\n private pendingUpdates = new Set<string>()\n\n constructor(\n private readonly source: IStorage<S>,\n private readonly logger?: ILogger,\n ) {\n this.storageName = source.name\n }\n\n private isSourceReady = (): boolean => {\n return this.source.initStatus.status === StorageStatus.READY\n }\n\n private onSourceStatusChange = (callback: (isReady: boolean) => void): VoidFunction => {\n return this.source.onStatusChange((status: StorageInitStatus) => {\n callback(status.status === StorageStatus.READY)\n })\n }\n\n /**\n * Генерирует уникальное имя для селектора через автоинкрементный счётчик\n */\n private generateName(): string {\n return `${this.storageName}_selector_${this.selectorIdCounter++}`\n }\n\n /**\n * Обрабатывает отложенные обновления синхронно\n */\n private processPendingUpdates(): void {\n if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return\n\n this.batchUpdateInProgress = true\n\n try {\n // Копируем список селекторов для обновления\n const subscriptionsToUpdate = Array.from(this.pendingUpdates)\n this.pendingUpdates.clear()\n\n // Обновляем все ожидающие селекторы синхронно\n for (const id of subscriptionsToUpdate) {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`Ошибка уведомления подписчика ${id}`, { error })\n }\n }\n }\n } catch (error) {\n this.logger?.error('Ошибка обработки ожидающих обновлений', { error })\n } finally {\n this.batchUpdateInProgress = false\n\n // Если появились новые обновления во время обработки, запускаем процесс снова\n if (this.pendingUpdates.size > 0) {\n this.processPendingUpdates()\n }\n }\n }\n\n createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n createSelector<T>(\n selectorOrDeps: Selector<S, T> | SelectorAPI<any>[],\n resultFnOrOptions?: ((...args: any[]) => T) | SelectorOptions<T>,\n optionsArg?: SelectorOptions<T>,\n ): SelectorAPI<T> {\n // Определяем, какую перегрузку используем\n const isSimpleSelector = !Array.isArray(selectorOrDeps)\n\n // Извлекаем options\n const options = isSimpleSelector ? (resultFnOrOptions as SelectorOptions<T>) || {} : optionsArg || {}\n\n const hasExplicitName = !!options.name\n\n // Используем предоставленное имя или генерируем уникальный ID\n const selectorId = options.name || this.generateName()\n\n // Кеширование по имени — только для явно именованных селекторов\n if (hasExplicitName && this.localSelectorCache.has(selectorId)) {\n return this.localSelectorCache.get(selectorId)!.api\n }\n\n // Создаем новый селектор\n let result: SelectorAPI<T>\n let dependencies: SelectorAPI<any>[] | undefined\n let unsubscribeFunctions: VoidFunction[] = []\n\n if (isSimpleSelector) {\n // Простой селектор с мемоизацией и трекингом зависимостей\n const { memoized, getTrackedKeys } = memoizeSelector(selectorOrDeps as Selector<S, T>, options.equals || defaultEquals)\n\n const created = this.createSimpleSelector(memoized, getTrackedKeys, { ...options, name: selectorId, equals: options.equals || defaultEquals })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n } else {\n // Комбинированный селектор\n dependencies = selectorOrDeps as SelectorAPI<any>[]\n\n const created = this.createCombinedSelector(dependencies, resultFnOrOptions as (...args: any[]) => T, {\n ...options,\n name: selectorId,\n equals: options.equals || defaultEquals,\n })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n }\n\n // Сохраняем в кеши\n this.localSelectorCache.set(selectorId, {\n api: result,\n dependencies,\n unsubscribeFunctions,\n })\n\n return result\n }\n\n private createSimpleSelector<T>(\n selector: Selector<S, T>,\n getTrackedKeys: () => Set<string> | null,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: VoidFunction[]\n } {\n // Синхронное получение состояния из кеша\n const getState = (): T => {\n const state = this.source.getStateSync()\n return selector(state as S)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Подписка на обновления хранилища с фильтрацией по changedPaths\n const unsubscribeFromStorage = this.source.subscribeToAll((event: any) => {\n if (event?.type === 'storage:update') {\n // Фильтруем по changedPaths: если зависимости известны и нет пересечения — пропускаем\n const changedPaths: string[] | undefined = event?.changedPaths\n const deps = getTrackedKeys()\n\n if (changedPaths && deps && deps.size > 0) {\n const hasRelevantChange = changedPaths.some((path) => {\n // changedPaths может содержать вложенные пути (\"users.0.name\")\n // берём ключ верхнего уровня для сравнения с deps\n const topLevelKey = path.split('.')[0]\n return deps.has(topLevelKey)\n })\n if (!hasRelevantChange) return\n }\n\n this.pendingUpdates.add(id)\n this.processPendingUpdates()\n }\n })\n\n const unsubscribeFunctions = [unsubscribeFromStorage]\n\n return {\n api: {\n select: () => getState(),\n selectSync: () => subscription.getValue(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n isSourceReady: this.isSourceReady,\n onSourceStatusChange: this.onSourceStatusChange,\n },\n unsubscribeFunctions,\n }\n }\n\n private createCombinedSelector<Deps extends unknown[], T>(\n selectors: { [K in keyof Deps]: SelectorAPI<Deps[K]> },\n resultFn: (...args: Deps) => T,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: Array<VoidFunction>\n } {\n // Мемоизация для combined selectors: поэлементное сравнение аргументов по ссылке (как reselect)\n let lastArgs: Deps | undefined\n let lastResult: T | undefined\n let hasResult = false\n const equals = options.equals || defaultEquals\n\n const memoizedResultFn = (args: Deps): T => {\n // Проверяем, изменился ли хотя бы один аргумент\n if (hasResult && lastArgs && lastArgs.length === args.length) {\n let argsEqual = true\n for (let i = 0; i < args.length; i++) {\n if (lastArgs[i] !== args[i]) {\n argsEqual = false\n break\n }\n }\n if (argsEqual) return lastResult as T\n }\n\n const newResult = resultFn(...args)\n\n // Сохраняем аргументы без создания нового массива — переиспользуем переданный\n lastArgs = args\n\n if (!hasResult || !equals(newResult, lastResult as T)) {\n lastResult = newResult\n }\n\n hasResult = true\n return lastResult as T\n }\n\n const getState = (): T => {\n const values = selectors.map((s) => s.selectSync()) as Deps\n return memoizedResultFn(values)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Батчинг обновлений через microtask — без искусственной задержки\n let pendingNotify = false\n let destroyed = false\n\n const triggerUpdate = () => {\n if (!pendingNotify) {\n pendingNotify = true\n queueMicrotask(() => {\n pendingNotify = false\n if (!destroyed) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, { error })\n }\n }\n })\n }\n }\n\n const unsubscribeFunctions: Array<VoidFunction> = selectors.map((selector) =>\n selector.subscribe({\n notify: () => {\n triggerUpdate()\n },\n }),\n )\n\n // При уничтожении предотвращаем выполнение отложенного microtask\n unsubscribeFunctions.push(() => {\n destroyed = true\n })\n\n return {\n api: {\n select: () => getState(),\n selectSync: () => subscription.getValue(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n isSourceReady: this.isSourceReady,\n onSourceStatusChange: this.onSourceStatusChange,\n },\n unsubscribeFunctions,\n }\n }\n\n destroy(): void {\n // Очищаем все подписки\n this.subscriptions.forEach((sub) => sub.cleanup())\n this.subscriptions.clear()\n\n // Очищаем список ожидающих обновлений\n this.pendingUpdates.clear()\n\n // Очищаем подписки из локального кеша\n this.localSelectorCache.forEach((cached) => {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n })\n this.localSelectorCache.clear()\n }\n}\n"],"names":["StorageStatus","defaultEquals","a","b","MAX_DEEP_EQUAL_DEPTH","deepEquals","depth","visited","WeakSet","Date","Array","i","keysA","Object","keysB","key","trackDependencies","state","accessedKeys","Set","proxy","Proxy","target","prop","receiver","Reflect","memoizeSelector","selectorFn","equals","lastState","lastResult","hasResult","trackedKeys","memoized","newResult","SelectorSubscription","name","getState","logger","newValue","subscriber","error","undefined","SelectorModule","Map","source","callback","status","subscriptionsToUpdate","id","subscription","selectorOrDeps","resultFnOrOptions","optionsArg","isSimpleSelector","options","hasExplicitName","selectorId","result","dependencies","unsubscribeFunctions","getTrackedKeys","created","selector","unsubscribeFromStorage","event","changedPaths","deps","hasRelevantChange","path","topLevelKey","selectors","resultFn","lastArgs","memoizedResultFn","args","argsEqual","values","s","pendingNotify","destroyed","triggerUpdate","queueMicrotask","sub","cached","unsub"],"mappings":"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"}
1
+ {"version":3,"file":"core/selector/selector.module.js","sources":["../../../src/core/selector/selector.module.ts"],"sourcesContent":["import { Observable } from 'rxjs'\n\nimport type { ILogger, IStorage, StorageInitStatus } from '../storage'\nimport { StorageStatus } from '../storage'\nimport type { ISelectorModule, Selector, SelectorAPI, SelectorOptions, Subscriber } from './selector.interface'\n\n/**\n * Reference equality (===) — поведение по умолчанию\n */\nfunction defaultEquals<T>(a: T, b: T): boolean {\n return a === b\n}\n\nconst MAX_DEEP_EQUAL_DEPTH = 10\n\n/**\n * Глубокое сравнение объектов по структуре с защитой от циклических ссылок и лимитом глубины.\n * Используется только при явной передаче через options.equals.\n */\nexport function deepEquals<T>(a: T, b: T, depth = 0, visited = new WeakSet()): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n if (depth > MAX_DEEP_EQUAL_DEPTH) return false\n\n if (typeof a !== 'object') return a === b\n\n // Защита от циклических ссылок\n if (visited.has(a as object)) return false\n visited.add(a as object)\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!deepEquals(a[i], b[i], depth + 1, visited)) return false\n }\n return true\n }\n\n if (Array.isArray(a) || Array.isArray(b)) return false\n\n const keysA = Object.keys(a as object)\n const keysB = Object.keys(b as object)\n\n if (keysA.length !== keysB.length) return false\n\n return keysA.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n return deepEquals((a as any)[key], (b as any)[key], depth + 1, visited)\n })\n}\n\n/**\n * Оборачивает state в Proxy для отслеживания обращений к ключам верхнего уровня.\n * Возвращает проксированный state и Set с именами ключей, к которым обратился селектор.\n */\nfunction trackDependencies<S extends Record<string, any>>(state: S): { proxy: S; accessedKeys: Set<string> } {\n const accessedKeys = new Set<string>()\n\n const proxy = new Proxy(state, {\n get(target, prop, receiver) {\n if (typeof prop === 'string') {\n accessedKeys.add(prop)\n }\n return Reflect.get(target, prop, receiver)\n },\n })\n\n return { proxy, accessedKeys }\n}\n\n// Мемоизирует функцию селектора для оптимизации + трекинг зависимостей через Proxy\nfunction memoizeSelector<S extends Record<string, any>, R>(\n selectorFn: (state: S) => R,\n equals: (a: R, b: R) => boolean = defaultEquals,\n): { memoized: (state: S) => R; getTrackedKeys: () => Set<string> | null } {\n let lastState: S | undefined\n let lastResult: R | undefined\n let hasResult = false\n let trackedKeys: Set<string> | null = null\n\n const memoized = function (state: S): R {\n // Если это первый вызов или состояние изменилось\n if (!hasResult || lastState !== state) {\n // Трекаем зависимости через Proxy при каждом реальном пересчёте\n const { proxy, accessedKeys } = trackDependencies(state)\n const newResult = selectorFn(proxy)\n trackedKeys = accessedKeys\n\n // Проверяем, изменился ли результат\n if (!hasResult || !equals(newResult, lastResult as R)) {\n lastResult = newResult\n }\n\n lastState = state\n hasResult = true\n }\n\n return lastResult as R\n }\n\n return { memoized, getTrackedKeys: () => trackedKeys }\n}\n\nclass SelectorSubscription<T> {\n private readonly id: string\n readonly subscribers = new Set<Subscriber<T>>()\n private lastValue?: T\n private hasValue = false\n\n constructor(\n private readonly name: string,\n private readonly getState: () => T,\n private readonly equals: (a: T, b: T) => boolean = defaultEquals,\n private readonly logger?: ILogger,\n ) {\n this.id = name\n this.logger?.debug(`[${this.id}] SelectorSubscription created`)\n }\n\n notify(): void {\n try {\n const newValue = this.getState()\n\n // Проверка на изменение значения с использованием функции сравнения\n if (!this.hasValue || !this.equals(newValue, this.lastValue as T)) {\n this.logger?.debug(`[${this.id}] Value changed, notify()`)\n\n this.lastValue = newValue\n this.hasValue = true\n\n for (const subscriber of this.subscribers) {\n try {\n subscriber.notify(newValue)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, { error })\n }\n }\n }\n } catch (error: any) {\n this.logger?.error(`[${this.id}] Ошибка в notify()`, { error })\n throw error\n }\n }\n\n subscribe(subscriber: Subscriber<T>): VoidFunction {\n this.subscribers.add(subscriber)\n\n // Отправляем текущее значение синхронно\n if (this.hasValue) {\n try {\n subscriber.notify(this.lastValue as T)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n }\n } else {\n // Вычисляем значение синхронно\n this.notify()\n }\n\n return () => {\n this.subscribers.delete(subscriber)\n }\n }\n\n cleanup(): void {\n this.subscribers.clear()\n this.lastValue = undefined\n this.hasValue = false\n }\n\n getLastValue(): T | undefined {\n return this.lastValue\n }\n\n getValue(): T {\n if (!this.hasValue) {\n this.lastValue = this.getState()\n this.hasValue = true\n }\n return this.lastValue as T\n }\n\n getId(): string {\n return this.id\n }\n}\n\nexport class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {\n storageName: string\n\n private selectorIdCounter = 0\n private subscriptions = new Map<string, SelectorSubscription<any>>()\n\n private localSelectorCache = new Map<\n string,\n {\n api: SelectorAPI<any>\n dependencies?: SelectorAPI<any>[]\n unsubscribeFunctions: Array<() => void>\n }\n >()\n\n // Флаг для батчинга обновлений\n private batchUpdateInProgress = false\n private pendingUpdates = new Set<string>()\n\n // Снятие подписки на статус источника (см. конструктор) — вызывается в destroy().\n private readonly disposeStatusListener: VoidFunction\n\n constructor(\n private readonly source: IStorage<S>,\n private readonly logger?: ILogger,\n ) {\n this.storageName = source.name\n\n // Селекторы конструируются ДО storage.initialize() (так устроен пайплайн createSynapse:\n // фабрика создаёт селекторы, и только потом buildSynapse зовёт initialize()). На этот\n // момент getStateSync() === {}. combine-селектор при создании эагерно подписывается на\n // зависимости и СИНХРОННО вычисляет их (SelectorSubscription.subscribe при !hasValue),\n // т.е. кеширует значение от пустого стора. А performInitialize наполняет _stateCache\n // молча, без storage:update, — значит этот кеш сам по себе уже не обновится.\n // Поэтому на переходе источника в READY принудительно пересчитываем все подписки.\n // Порядок Map = порядок создания, а зависимость всегда создаётся раньше зависимого\n // (combine([this.api]) невозможен до this.api) → пересчёт идёт «снизу вверх» корректно.\n this.disposeStatusListener = this.source.onStatusChange((status) => {\n if (status.status === StorageStatus.READY) {\n this.subscriptions.forEach((sub) => {\n try {\n sub.notify()\n } catch (error) {\n this.logger?.error(`[${sub.getId()}] Ошибка пересчёта на READY`, { error })\n }\n })\n }\n })\n }\n\n /**\n * Собирает публичный `SelectorAPI` поверх подписки. `$` — Observable-вид с той же\n * семантикой, что у `subscribe`: синхронный снапшот при подписке + emit на изменение.\n *\n * `sourceReadiness` переопределяет дефолтную (локальную) готовность источника: для\n * combined-селекторов туда передаётся агрегированная готовность по всем источникам\n * зависимостей (см. {@link createCombinedSelector}).\n */\n private buildSelectorApi<T>(\n id: string,\n subscription: SelectorSubscription<T>,\n getState: () => T,\n sourceReadiness?: { isSourceReady: () => boolean; onSourceStatusChange: (callback: (isReady: boolean) => void) => VoidFunction },\n ): SelectorAPI<T> {\n return {\n select: () => getState(),\n selectSync: () => subscription.getValue(),\n subscribe: (subscriber) => subscription.subscribe(subscriber),\n getId: () => id,\n $: new Observable<T>((observer) => subscription.subscribe({ notify: (value) => observer.next(value) })),\n isSourceReady: sourceReadiness?.isSourceReady ?? this.isSourceReady,\n onSourceStatusChange: sourceReadiness?.onSourceStatusChange ?? this.onSourceStatusChange,\n }\n }\n\n private isSourceReady = (): boolean => {\n return this.source.initStatus.status === StorageStatus.READY\n }\n\n private onSourceStatusChange = (callback: (isReady: boolean) => void): VoidFunction => {\n return this.source.onStatusChange((status: StorageInitStatus) => {\n callback(status.status === StorageStatus.READY)\n })\n }\n\n /**\n * Генерирует уникальное имя для селектора через автоинкрементный счётчик\n */\n private generateName(): string {\n return `${this.storageName}_selector_${this.selectorIdCounter++}`\n }\n\n /**\n * Обрабатывает отложенные обновления синхронно\n */\n private processPendingUpdates(): void {\n if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return\n\n this.batchUpdateInProgress = true\n\n try {\n // Копируем список селекторов для обновления\n const subscriptionsToUpdate = Array.from(this.pendingUpdates)\n this.pendingUpdates.clear()\n\n // Обновляем все ожидающие селекторы синхронно\n for (const id of subscriptionsToUpdate) {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`Ошибка уведомления подписчика ${id}`, { error })\n }\n }\n }\n } catch (error) {\n this.logger?.error('Ошибка обработки ожидающих обновлений', { error })\n } finally {\n this.batchUpdateInProgress = false\n\n // Если появились новые обновления во время обработки, запускаем процесс снова\n if (this.pendingUpdates.size > 0) {\n this.processPendingUpdates()\n }\n }\n }\n\n createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n createSelector<T>(\n selectorOrDeps: Selector<S, T> | SelectorAPI<any>[],\n resultFnOrOptions?: ((...args: any[]) => T) | SelectorOptions<T>,\n optionsArg?: SelectorOptions<T>,\n ): SelectorAPI<T> {\n // Определяем, какую перегрузку используем\n const isSimpleSelector = !Array.isArray(selectorOrDeps)\n\n // Извлекаем options\n const options = isSimpleSelector ? (resultFnOrOptions as SelectorOptions<T>) || {} : optionsArg || {}\n\n const hasExplicitName = !!options.name\n\n // Используем предоставленное имя или генерируем уникальный ID\n const selectorId = options.name || this.generateName()\n\n // Кеширование по имени — только для явно именованных селекторов\n if (hasExplicitName && this.localSelectorCache.has(selectorId)) {\n return this.localSelectorCache.get(selectorId)!.api\n }\n\n // Создаем новый селектор\n let result: SelectorAPI<T>\n let dependencies: SelectorAPI<any>[] | undefined\n let unsubscribeFunctions: VoidFunction[] = []\n\n if (isSimpleSelector) {\n // Простой селектор с мемоизацией и трекингом зависимостей\n const { memoized, getTrackedKeys } = memoizeSelector(selectorOrDeps as Selector<S, T>, options.equals || defaultEquals)\n\n const created = this.createSimpleSelector(memoized, getTrackedKeys, { ...options, name: selectorId, equals: options.equals || defaultEquals })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n } else {\n // Комбинированный селектор\n dependencies = selectorOrDeps as SelectorAPI<any>[]\n\n const created = this.createCombinedSelector(dependencies, resultFnOrOptions as (...args: any[]) => T, {\n ...options,\n name: selectorId,\n equals: options.equals || defaultEquals,\n })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n }\n\n // Сохраняем в кеши\n this.localSelectorCache.set(selectorId, {\n api: result,\n dependencies,\n unsubscribeFunctions,\n })\n\n return result\n }\n\n private createSimpleSelector<T>(\n selector: Selector<S, T>,\n getTrackedKeys: () => Set<string> | null,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: VoidFunction[]\n } {\n // Синхронное получение состояния из кеша\n const getState = (): T => {\n const state = this.source.getStateSync()\n return selector(state as S)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Подписка на обновления хранилища с фильтрацией по changedPaths\n const unsubscribeFromStorage = this.source.subscribeToAll((event: any) => {\n if (event?.type === 'storage:update') {\n // Фильтруем по changedPaths: если зависимости известны и нет пересечения — пропускаем\n const changedPaths: string[] | undefined = event?.changedPaths\n const deps = getTrackedKeys()\n\n if (changedPaths && deps && deps.size > 0) {\n const hasRelevantChange = changedPaths.some((path) => {\n // changedPaths может содержать вложенные пути (\"users.0.name\")\n // берём ключ верхнего уровня для сравнения с deps\n const topLevelKey = path.split('.')[0]\n return deps.has(topLevelKey)\n })\n if (!hasRelevantChange) return\n }\n\n this.pendingUpdates.add(id)\n this.processPendingUpdates()\n }\n })\n\n const unsubscribeFunctions = [unsubscribeFromStorage]\n\n return {\n api: this.buildSelectorApi(id, subscription, getState),\n unsubscribeFunctions,\n }\n }\n\n private createCombinedSelector<Deps extends unknown[], T>(\n selectors: { [K in keyof Deps]: SelectorAPI<Deps[K]> },\n resultFn: (...args: Deps) => T,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: Array<VoidFunction>\n } {\n // Мемоизация для combined selectors: поэлементное сравнение аргументов по ссылке (как reselect)\n let lastArgs: Deps | undefined\n let lastResult: T | undefined\n let hasResult = false\n const equals = options.equals || defaultEquals\n\n const memoizedResultFn = (args: Deps): T => {\n // Проверяем, изменился ли хотя бы один аргумент\n if (hasResult && lastArgs && lastArgs.length === args.length) {\n let argsEqual = true\n for (let i = 0; i < args.length; i++) {\n if (lastArgs[i] !== args[i]) {\n argsEqual = false\n break\n }\n }\n if (argsEqual) return lastResult as T\n }\n\n const newResult = resultFn(...args)\n\n // Сохраняем аргументы без создания нового массива — переиспользуем переданный\n lastArgs = args\n\n if (!hasResult || !equals(newResult, lastResult as T)) {\n lastResult = newResult\n }\n\n hasResult = true\n return lastResult as T\n }\n\n const getState = (): T => {\n const values = selectors.map((s) => s.selectSync()) as Deps\n return memoizedResultFn(values)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Батчинг обновлений через microtask — без искусственной задержки\n let pendingNotify = false\n let destroyed = false\n\n const triggerUpdate = () => {\n if (!pendingNotify) {\n pendingNotify = true\n queueMicrotask(() => {\n pendingNotify = false\n if (!destroyed) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, { error })\n }\n }\n })\n }\n }\n\n const unsubscribeFunctions: Array<VoidFunction> = selectors.map((selector) =>\n selector.subscribe({\n notify: () => {\n triggerUpdate()\n },\n }),\n )\n\n // При уничтожении предотвращаем выполнение отложенного microtask\n unsubscribeFunctions.push(() => {\n destroyed = true\n })\n\n // Агрегированная готовность источников: combined-селектор «готов», только когда готов\n // ЛОКАЛЬНЫЙ источник И все источники зависимостей (важно для cross-store combine, где\n // зависимости приходят из других сторов с собственным lifecycle).\n const aggregatedSourceReadiness = {\n isSourceReady: (): boolean => this.isSourceReady() && selectors.every((dep) => dep.isSourceReady()),\n onSourceStatusChange: (callback: (isReady: boolean) => void): VoidFunction => {\n const emit = () => callback(aggregatedSourceReadiness.isSourceReady())\n const disposers = [this.onSourceStatusChange(emit), ...selectors.map((dep) => dep.onSourceStatusChange(emit))]\n return () => disposers.forEach((dispose) => dispose())\n },\n }\n\n return {\n api: this.buildSelectorApi(id, subscription, getState, aggregatedSourceReadiness),\n unsubscribeFunctions,\n }\n }\n\n /**\n * Точечно удаляет селектор по id: снимает его подписки на хранилище, чистит подписку\n * и кэш. Остальные селекторы модуля не затрагиваются. Имя кэша совпадает с id подписки\n * (`generateName()`/`options.name`), поэтому достаточно одного ключа.\n */\n removeSelector(id: string): void {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n subscription.cleanup()\n this.subscriptions.delete(id)\n }\n\n this.pendingUpdates.delete(id)\n\n const cached = this.localSelectorCache.get(id)\n if (cached) {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n this.localSelectorCache.delete(id)\n }\n }\n\n destroy(): void {\n // Снимаем подписку на статус источника\n this.disposeStatusListener()\n\n // Очищаем все подписки\n this.subscriptions.forEach((sub) => sub.cleanup())\n this.subscriptions.clear()\n\n // Очищаем список ожидающих обновлений\n this.pendingUpdates.clear()\n\n // Очищаем подписки из локального кеша\n this.localSelectorCache.forEach((cached) => {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n })\n this.localSelectorCache.clear()\n }\n}\n"],"names":["Observable","StorageStatus","defaultEquals","a","b","MAX_DEEP_EQUAL_DEPTH","deepEquals","depth","visited","WeakSet","Date","Array","i","keysA","Object","keysB","key","trackDependencies","state","accessedKeys","Set","proxy","Proxy","target","prop","receiver","Reflect","memoizeSelector","selectorFn","equals","lastState","lastResult","hasResult","trackedKeys","memoized","newResult","SelectorSubscription","name","getState","logger","newValue","subscriber","error","undefined","SelectorModule","Map","source","status","sub","id","subscription","sourceReadiness","observer","value","callback","subscriptionsToUpdate","selectorOrDeps","resultFnOrOptions","optionsArg","isSimpleSelector","options","hasExplicitName","selectorId","result","dependencies","unsubscribeFunctions","getTrackedKeys","created","selector","unsubscribeFromStorage","event","changedPaths","deps","hasRelevantChange","path","topLevelKey","selectors","resultFn","lastArgs","memoizedResultFn","args","argsEqual","values","s","pendingNotify","destroyed","triggerUpdate","queueMicrotask","aggregatedSourceReadiness","dep","emit","disposers","dispose","cached","unsub"],"mappings":";;;;;AAAiC;AAGS;AAG1C;;CAEC,GACD,SAASE,aAAaA,CAAIC,CAAI,EAAEC,CAAI;IAClC,OAAOD,MAAMC;AACf;AAEA,MAAMC,oBAAoBA,GAAG;AAE7B;;;CAGC,GACM,SAASC,UAAUA,CAAIH,CAAI,EAAEC,CAAI,EAAEG,QAAQ,CAAC,EAAEC,UAAU,IAAIC,SAAS;IAC1E,IAAIN,MAAMC,GAAG,OAAO;IACpB,IAAID,KAAK,QAAQC,KAAK,MAAM,OAAO;IACnC,IAAI,OAAOD,MAAM,OAAOC,GAAG,OAAO;IAClC,IAAIG,QAAQF,oBAAoBA,EAAE,OAAO;IAEzC,IAAI,OAAOF,MAAM,UAAU,OAAOA,MAAMC;IAExC,+BAA+B;IAC/B,IAAII,QAAQ,GAAG,CAACL,IAAc,OAAO;IACrCK,QAAQ,GAAG,CAACL;IAEZ,IAAIA,aAAaO,QAAQN,aAAaM,MAAM;QAC1C,OAAOP,EAAE,OAAO,OAAOC,EAAE,OAAO;IAClC;IAEA,IAAIO,MAAM,OAAO,CAACR,MAAMQ,MAAM,OAAO,CAACP,IAAI;QACxC,IAAID,EAAE,MAAM,KAAKC,EAAE,MAAM,EAAE,OAAO;QAClC,IAAK,IAAIQ,IAAI,GAAGA,IAAIT,EAAE,MAAM,EAAES,IAAK;YACjC,IAAI,CAACN,UAAUA,CAACH,CAAC,CAACS,EAAE,EAAER,CAAC,CAACQ,EAAE,EAAEL,QAAQ,GAAGC,UAAU,OAAO;QAC1D;QACA,OAAO;IACT;IAEA,IAAIG,MAAM,OAAO,CAACR,MAAMQ,MAAM,OAAO,CAACP,IAAI,OAAO;IAEjD,MAAMS,QAAQC,OAAO,IAAI,CAACX;IAC1B,MAAMY,QAAQD,OAAO,IAAI,CAACV;IAE1B,IAAIS,MAAM,MAAM,KAAKE,MAAM,MAAM,EAAE,OAAO;IAE1C,OAAOF,MAAM,KAAK,CAAC,CAACG;QAClB,IAAI,CAACF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACV,GAAGY,MAAM,OAAO;QAC1D,OAAOV,UAAUA,CAAEH,CAAS,CAACa,IAAI,EAAGZ,CAAS,CAACY,IAAI,EAAET,QAAQ,GAAGC;IACjE;AACF;AAEA;;;CAGC,GACD,SAASS,iBAAiBA,CAAgCC,KAAQ;IAChE,MAAMC,eAAe,IAAIC;IAEzB,MAAMC,QAAQ,IAAIC,MAAMJ,OAAO;QAC7B,KAAIK,MAAM,EAAEC,IAAI,EAAEC,QAAQ;YACxB,IAAI,OAAOD,SAAS,UAAU;gBAC5BL,aAAa,GAAG,CAACK;YACnB;YACA,OAAOE,QAAQ,GAAG,CAACH,QAAQC,MAAMC;QACnC;IACF;IAEA,OAAO;QAAEJ;QAAOF;IAAa;AAC/B;AAEA,mFAAmF;AACnF,SAASQ,eAAeA,CACtBC,UAA2B,EAC3BC,SAAkC3B,aAAa;IAE/C,IAAI4B;IACJ,IAAIC;IACJ,IAAIC,YAAY;IAChB,IAAIC,cAAkC;IAEtC,MAAMC,WAAW,SAAUhB,KAAQ;QACjC,iDAAiD;QACjD,IAAI,CAACc,aAAaF,cAAcZ,OAAO;YACrC,gEAAgE;YAChE,MAAM,EAAEG,KAAK,EAAEF,YAAY,EAAE,GAAGF,iBAAiBA,CAACC;YAClD,MAAMiB,YAAYP,WAAWP;YAC7BY,cAAcd;YAEd,oCAAoC;YACpC,IAAI,CAACa,aAAa,CAACH,OAAOM,WAAWJ,aAAkB;gBACrDA,aAAaI;YACf;YAEAL,YAAYZ;YACZc,YAAY;QACd;QAEA,OAAOD;IACT;IAEA,OAAO;QAAEG;QAAU,gBAAgB,IAAMD;IAAY;AACvD;AAEA,MAAMG,oBAAoBA;;;;;IACP,GAAU;IAClB,cAAc,IAAIhB,MAAoB;IACvC,UAAa;IACb,WAAW,MAAK;IAExB,YACmBiB,IAAY,EACZC,QAAiB,EACjBT,SAAkC3B,aAAa,EAC/CqC,MAAgB,CACjC;aAJiBF,OAAAA;aACAC,WAAAA;aACAT,SAAAA;aACAU,SAAAA;QAEjB,IAAI,CAAC,EAAE,GAAGF;QACV,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,8BAA8B,CAAC;IAChE;IAEA,SAAe;QACb,IAAI;YACF,MAAMG,WAAW,IAAI,CAAC,QAAQ;YAE9B,oEAAoE;YACpE,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAACA,UAAU,IAAI,CAAC,SAAS,GAAQ;gBACjE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAAC;gBAEzD,IAAI,CAAC,SAAS,GAAGA;gBACjB,IAAI,CAAC,QAAQ,GAAG;gBAEhB,KAAK,MAAMC,cAAc,IAAI,CAAC,WAAW,CAAE;oBACzC,IAAI;wBACFA,WAAW,MAAM,CAACD;oBACpB,EAAE,OAAOE,OAAO;wBACd,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,iCAAiC,CAAC,EAAE;4BAAEA;wBAAM;oBAC7E;gBACF;YACF;QACF,EAAE,OAAOA,OAAY;YACnB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE;gBAAEA;YAAM;YAC7D,MAAMA;QACR;IACF;IAEA,UAAUD,UAAyB,EAAgB;QACjD,IAAI,CAAC,WAAW,CAAC,GAAG,CAACA;QAErB,wCAAwC;QACxC,IAAI,IAAI,CAAC,QAAQ,EAAE;YACjB,IAAI;gBACFA,WAAW,MAAM,CAAC,IAAI,CAAC,SAAS;YAClC,EAAE,OAAOC,OAAO;gBACd,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,qCAAqC,CAAC,EAAE;oBAAEA;gBAAM;YACjF;QACF,OAAO;YACL,+BAA+B;YAC/B,IAAI,CAAC,MAAM;QACb;QAEA,OAAO;YACL,IAAI,CAAC,WAAW,CAAC,MAAM,CAACD;QAC1B;IACF;IAEA,UAAgB;QACd,IAAI,CAAC,WAAW,CAAC,KAAK;QACtB,IAAI,CAAC,SAAS,GAAGE;QACjB,IAAI,CAAC,QAAQ,GAAG;IAClB;IAEA,eAA8B;QAC5B,OAAO,IAAI,CAAC,SAAS;IACvB;IAEA,WAAc;QACZ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ;YAC9B,IAAI,CAAC,QAAQ,GAAG;QAClB;QACA,OAAO,IAAI,CAAC,SAAS;IACvB;IAEA,QAAgB;QACd,OAAO,IAAI,CAAC,EAAE;IAChB;AACF;AAEO,MAAMC,cAAcA;;;IACzB,YAAmB;IAEX,oBAAoB,EAAC;IACrB,gBAAgB,IAAIC,MAAwC;IAE5D,qBAAqB,IAAIA,MAO9B;IAEH,+BAA+B;IACvB,wBAAwB,MAAK;IAC7B,iBAAiB,IAAIzB,MAAa;IAE1C,kFAAkF;IACjE,sBAAmC;IAEpD,YACmB0B,MAAmB,EACnBP,MAAgB,CACjC;aAFiBO,SAAAA;aACAP,SAAAA;QAEjB,IAAI,CAAC,WAAW,GAAGO,OAAO,IAAI;QAE9B,wFAAwF;QACxF,sFAAsF;QACtF,uFAAuF;QACvF,uFAAuF;QACvF,qFAAqF;QACrF,6EAA6E;QAC7E,kFAAkF;QAClF,mFAAmF;QACnF,wFAAwF;QACxF,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAACC;YACvD,IAAIA,OAAO,MAAM,KAAK9C,mBAAmB,EAAE;gBACzC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC+C;oBAC1B,IAAI;wBACFA,IAAI,MAAM;oBACZ,EAAE,OAAON,OAAO;wBACd,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAEM,IAAI,KAAK,GAAG,2BAA2B,CAAC,EAAE;4BAAEN;wBAAM;oBAC3E;gBACF;YACF;QACF;IACF;IAEA;;;;;;;GAOC,GACO,iBACNO,EAAU,EACVC,YAAqC,EACrCZ,QAAiB,EACjBa,eAAgI,EAChH;QAChB,OAAO;YACL,QAAQ,IAAMb;YACd,YAAY,IAAMY,aAAa,QAAQ;YACvC,WAAW,CAACT,aAAeS,aAAa,SAAS,CAACT;YAClD,OAAO,IAAMQ;YACb,GAAG,IAAIjD,UAAUA,CAAI,CAACoD,WAAaF,aAAa,SAAS,CAAC;oBAAE,QAAQ,CAACG,QAAUD,SAAS,IAAI,CAACC;gBAAO;YACpG,eAAeF,iBAAiB,iBAAiB,IAAI,CAAC,aAAa;YACnE,sBAAsBA,iBAAiB,wBAAwB,IAAI,CAAC,oBAAoB;QAC1F;IACF;IAEQ,gBAAgB;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAKlD,mBAAmB;IAC9D,EAAC;IAEO,uBAAuB,CAACqD;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAACP;YACjCO,SAASP,OAAO,MAAM,KAAK9C,mBAAmB;QAChD;IACF,EAAC;IAED;;GAEC,GACO,eAAuB;QAC7B,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,iBAAiB,IAAI;IACnE;IAEA;;GAEC,GACO,wBAA8B;QACpC,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,qBAAqB,EAAE;QAElE,IAAI,CAAC,qBAAqB,GAAG;QAE7B,IAAI;YACF,4CAA4C;YAC5C,MAAMsD,wBAAwB5C,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc;YAC5D,IAAI,CAAC,cAAc,CAAC,KAAK;YAEzB,8CAA8C;YAC9C,KAAK,MAAMsC,MAAMM,sBAAuB;gBACtC,MAAML,eAAe,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD;gBAC5C,IAAIC,cAAc;oBAChB,IAAI;wBACFA,aAAa,MAAM;oBACrB,EAAE,OAAOR,OAAO;wBACd,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,8BAA8B,EAAEO,IAAI,EAAE;4BAAEP;wBAAM;oBACpE;gBACF;YACF;QACF,EAAE,OAAOA,OAAO;YACd,IAAI,CAAC,MAAM,EAAE,MAAM,yCAAyC;gBAAEA;YAAM;QACtE,SAAU;YACR,IAAI,CAAC,qBAAqB,GAAG;YAE7B,8EAA8E;YAC9E,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,GAAG;gBAChC,IAAI,CAAC,qBAAqB;YAC5B;QACF;IACF;IAKA,eACEc,cAAmD,EACnDC,iBAAgE,EAChEC,UAA+B,EACf;QAChB,0CAA0C;QAC1C,MAAMC,mBAAmB,CAAChD,MAAM,OAAO,CAAC6C;QAExC,oBAAoB;QACpB,MAAMI,UAAUD,mBAAoBF,qBAA4C,CAAC,IAAIC,cAAc,CAAC;QAEpG,MAAMG,kBAAkB,CAAC,CAACD,QAAQ,IAAI;QAEtC,8DAA8D;QAC9D,MAAME,aAAaF,QAAQ,IAAI,IAAI,IAAI,CAAC,YAAY;QAEpD,gEAAgE;QAChE,IAAIC,mBAAmB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAACC,aAAa;YAC9D,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAACA,YAAa,GAAG;QACrD;QAEA,yBAAyB;QACzB,IAAIC;QACJ,IAAIC;QACJ,IAAIC,uBAAuC,EAAE;QAE7C,IAAIN,kBAAkB;YACpB,0DAA0D;YAC1D,MAAM,EAAEzB,QAAQ,EAAEgC,cAAc,EAAE,GAAGvC,eAAeA,CAAC6B,gBAAkCI,QAAQ,MAAM,IAAI1D,aAAaA;YAEtH,MAAMiE,UAAU,IAAI,CAAC,oBAAoB,CAACjC,UAAUgC,gBAAgB;gBAAE,GAAGN,OAAO;gBAAE,MAAME;gBAAY,QAAQF,QAAQ,MAAM,IAAI1D,aAAaA;YAAC;YAE5I6D,SAASI,QAAQ,GAAG;YACpBF,uBAAuBE,QAAQ,oBAAoB;QACrD,OAAO;YACL,2BAA2B;YAC3BH,eAAeR;YAEf,MAAMW,UAAU,IAAI,CAAC,sBAAsB,CAACH,cAAcP,mBAA4C;gBACpG,GAAGG,OAAO;gBACV,MAAME;gBACN,QAAQF,QAAQ,MAAM,IAAI1D,aAAaA;YACzC;YAEA6D,SAASI,QAAQ,GAAG;YACpBF,uBAAuBE,QAAQ,oBAAoB;QACrD;QAEA,mBAAmB;QACnB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAACL,YAAY;YACtC,KAAKC;YACLC;YACAC;QACF;QAEA,OAAOF;IACT;IAEQ,qBACNK,QAAwB,EACxBF,cAAwC,EACxCN,OAA8C,EAI9C;QACA,yCAAyC;QACzC,MAAMtB,WAAW;YACf,MAAMpB,QAAQ,IAAI,CAAC,MAAM,CAAC,YAAY;YACtC,OAAOkD,SAASlD;QAClB;QAEA,MAAMgC,eAAe,IAAId,oBAAoBA,CAACwB,QAAQ,IAAI,EAAEtB,UAAUsB,QAAQ,MAAM,IAAI1D,aAAaA,EAAE,IAAI,CAAC,MAAM;QAElH,MAAM+C,KAAKC,aAAa,KAAK;QAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD,IAAIC;QAE3B,iEAAiE;QACjE,MAAMmB,yBAAyB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAACC;YACzD,IAAIA,OAAO,SAAS,kBAAkB;gBACpC,sFAAsF;gBACtF,MAAMC,eAAqCD,OAAO;gBAClD,MAAME,OAAON;gBAEb,IAAIK,gBAAgBC,QAAQA,KAAK,IAAI,GAAG,GAAG;oBACzC,MAAMC,oBAAoBF,aAAa,IAAI,CAAC,CAACG;wBAC3C,+DAA+D;wBAC/D,kDAAkD;wBAClD,MAAMC,cAAcD,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE;wBACtC,OAAOF,KAAK,GAAG,CAACG;oBAClB;oBACA,IAAI,CAACF,mBAAmB;gBAC1B;gBAEA,IAAI,CAAC,cAAc,CAAC,GAAG,CAACxB;gBACxB,IAAI,CAAC,qBAAqB;YAC5B;QACF;QAEA,MAAMgB,uBAAuB;YAACI;SAAuB;QAErD,OAAO;YACL,KAAK,IAAI,CAAC,gBAAgB,CAACpB,IAAIC,cAAcZ;YAC7C2B;QACF;IACF;IAEQ,uBACNW,SAAsD,EACtDC,QAA8B,EAC9BjB,OAA8C,EAI9C;QACA,gGAAgG;QAChG,IAAIkB;QACJ,IAAI/C;QACJ,IAAIC,YAAY;QAChB,MAAMH,SAAS+B,QAAQ,MAAM,IAAI1D,aAAaA;QAE9C,MAAM6E,mBAAmB,CAACC;YACxB,gDAAgD;YAChD,IAAIhD,aAAa8C,YAAYA,SAAS,MAAM,KAAKE,KAAK,MAAM,EAAE;gBAC5D,IAAIC,YAAY;gBAChB,IAAK,IAAIrE,IAAI,GAAGA,IAAIoE,KAAK,MAAM,EAAEpE,IAAK;oBACpC,IAAIkE,QAAQ,CAAClE,EAAE,KAAKoE,IAAI,CAACpE,EAAE,EAAE;wBAC3BqE,YAAY;wBACZ;oBACF;gBACF;gBACA,IAAIA,WAAW,OAAOlD;YACxB;YAEA,MAAMI,YAAY0C,YAAYG;YAE9B,8EAA8E;YAC9EF,WAAWE;YAEX,IAAI,CAAChD,aAAa,CAACH,OAAOM,WAAWJ,aAAkB;gBACrDA,aAAaI;YACf;YAEAH,YAAY;YACZ,OAAOD;QACT;QAEA,MAAMO,WAAW;YACf,MAAM4C,SAASN,UAAU,GAAG,CAAC,CAACO,IAAMA,EAAE,UAAU;YAChD,OAAOJ,iBAAiBG;QAC1B;QAEA,MAAMhC,eAAe,IAAId,oBAAoBA,CAACwB,QAAQ,IAAI,EAAEtB,UAAUsB,QAAQ,MAAM,IAAI1D,aAAaA,EAAE,IAAI,CAAC,MAAM;QAElH,MAAM+C,KAAKC,aAAa,KAAK;QAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD,IAAIC;QAE3B,kEAAkE;QAClE,IAAIkC,gBAAgB;QACpB,IAAIC,YAAY;QAEhB,MAAMC,gBAAgB;YACpB,IAAI,CAACF,eAAe;gBAClBA,gBAAgB;gBAChBG,eAAe;oBACbH,gBAAgB;oBAChB,IAAI,CAACC,WAAW;wBACd,IAAI;4BACFnC,aAAa,MAAM;wBACrB,EAAE,OAAOR,OAAO;4BACd,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAEO,GAAG,oCAAoC,CAAC,EAAE;gCAAEP;4BAAM;wBAC3E;oBACF;gBACF;YACF;QACF;QAEA,MAAMuB,uBAA4CW,UAAU,GAAG,CAAC,CAACR,WAC/DA,SAAS,SAAS,CAAC;gBACjB,QAAQ;oBACNkB;gBACF;YACF;QAGF,iEAAiE;QACjErB,qBAAqB,IAAI,CAAC;YACxBoB,YAAY;QACd;QAEA,sFAAsF;QACtF,sFAAsF;QACtF,kEAAkE;QAClE,MAAMG,4BAA4B;YAChC,eAAe,IAAe,IAAI,CAAC,aAAa,MAAMZ,UAAU,KAAK,CAAC,CAACa,MAAQA,IAAI,aAAa;YAChG,sBAAsB,CAACnC;gBACrB,MAAMoC,OAAO,IAAMpC,SAASkC,0BAA0B,aAAa;gBACnE,MAAMG,YAAY;oBAAC,IAAI,CAAC,oBAAoB,CAACD;uBAAUd,UAAU,GAAG,CAAC,CAACa,MAAQA,IAAI,oBAAoB,CAACC;iBAAO;gBAC9G,OAAO,IAAMC,UAAU,OAAO,CAAC,CAACC,UAAYA;YAC9C;QACF;QAEA,OAAO;YACL,KAAK,IAAI,CAAC,gBAAgB,CAAC3C,IAAIC,cAAcZ,UAAUkD;YACvDvB;QACF;IACF;IAEA;;;;GAIC,GACD,eAAehB,EAAU,EAAQ;QAC/B,MAAMC,eAAe,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD;QAC5C,IAAIC,cAAc;YAChBA,aAAa,OAAO;YACpB,IAAI,CAAC,aAAa,CAAC,MAAM,CAACD;QAC5B;QAEA,IAAI,CAAC,cAAc,CAAC,MAAM,CAACA;QAE3B,MAAM4C,SAAS,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC5C;QAC3C,IAAI4C,QAAQ;YACVA,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAACC,QAAUA;YAC/C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC7C;QACjC;IACF;IAEA,UAAgB;QACd,uCAAuC;QACvC,IAAI,CAAC,qBAAqB;QAE1B,uBAAuB;QACvB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAACD,MAAQA,IAAI,OAAO;QAC/C,IAAI,CAAC,aAAa,CAAC,KAAK;QAExB,sCAAsC;QACtC,IAAI,CAAC,cAAc,CAAC,KAAK;QAEzB,sCAAsC;QACtC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC6C;YAC/BA,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAACC,QAAUA;QACjD;QACA,IAAI,CAAC,kBAAkB,CAAC,KAAK;IAC/B;AACF"}
@@ -0,0 +1,56 @@
1
+ import type { IStorage } from '../storage';
2
+ import type { ISelectorModule, SelectorAPI, SelectorOptions } from './selector.interface';
3
+ /**
4
+ * Публичный class-based слой селекторов. Селекторы объявляются как поля класса через
5
+ * фабрики `this.select` / `this.combine` / `this.keyed` — поля сразу настоящие
6
+ * `SelectorAPI` (eager-материализация, никаких рецептов).
7
+ *
8
+ * Внешние селекторы (cross-store) передаются параметрами конструктора подкласса:
9
+ * parameter properties присваиваются ДО инициализаторов полей, поэтому `this.core`
10
+ * в полях доступен корректно.
11
+ *
12
+ * Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном
13
+ * namespace и НЕ конфликтуют с полями-селекторами подкласса (можно объявить селектор
14
+ * `track`, `module` и т.п.). Зарезервированы лишь `protected`/публичные члены
15
+ * (`select`/`combine`/`keyed`/`destroy`) — их именами селекторы называть нельзя.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * class PostsSelectors extends Selectors<PostsState> {
20
+ * constructor(storage: IStorage<PostsState>, private readonly core: CoreSelectors) {
21
+ * super(storage)
22
+ * }
23
+ *
24
+ * private readonly api = this.select((s) => s.api)
25
+ * readonly list = this.select((s) => s.list)
26
+ * readonly isPostsLoading = this.combine([this.api], (a) => a.postsRequest.status === 'loading')
27
+ * // cross-store: пересчитывается при изменении чужого стора
28
+ * readonly currentUserId = this.combine([this.core.profile], (p) => p?.user_info?.id ?? null)
29
+ * }
30
+ * ```
31
+ */
32
+ export declare abstract class Selectors<TState extends Record<string, any>> {
33
+ #private;
34
+ /** Принимает `storage` (создаёт и владеет своим `SelectorModule`) либо готовый модуль. */
35
+ constructor(source: IStorage<TState> | ISelectorModule<TState>);
36
+ /** Простой селектор: мемоизация по ссылке стейта + трекинг затронутых ключей. */
37
+ protected select<R>(selector: (state: TState) => R, options?: SelectorOptions<R>): SelectorAPI<R>;
38
+ /** Combined-селектор; зависимости — любые `SelectorAPI`, в т.ч. из других сторов. */
39
+ protected combine<Deps extends unknown[], R>(deps: {
40
+ [K in keyof Deps]: SelectorAPI<Deps[K]>;
41
+ }, fn: (...args: Deps) => R, options?: SelectorOptions<R>): SelectorAPI<R>;
42
+ /**
43
+ * Параметрический (keyed) селектор: один `SelectorAPI` на ключ (кэш по ключу).
44
+ *
45
+ * Слайсы соседних ключей живут под общим родителем (`s.byTarget[key]`), а storage при
46
+ * обновлении пере-клонирует всю ветку — поэтому ссылка соседнего ключа не сохраняется.
47
+ * Чтобы обновление ключа A не уведомляло подписчиков ключа B, keyed-селекторы по
48
+ * умолчанию сравнивают значения структурно (`deepEquals`). Опции можно переопределить.
49
+ */
50
+ protected keyed<K extends string | number, R>(fn: (key: K) => (state: TState) => R, options?: SelectorOptions<R>): (key: K) => SelectorAPI<R>;
51
+ /**
52
+ * Уничтожает свой модуль (только если владеет им). Если модуль передан снаружи —
53
+ * удаляет из него лишь свои селекторы, чужие не трогает.
54
+ */
55
+ destroy(): void;
56
+ }