synapse-storage 4.1.2 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/README.md +142 -12
  2. package/dist/_utils/chunk.util.d.ts +0 -1
  3. package/dist/_utils/deepMerge.util.d.ts +0 -1
  4. package/dist/_utils/error-handling.util.d.ts +0 -1
  5. package/dist/_utils/flatMap.util.d.ts +0 -1
  6. package/dist/_utils/index.d.ts +0 -1
  7. package/dist/_utils/logger-console.util.d.ts +0 -1
  8. package/dist/api/api.module.d.ts +0 -1
  9. package/dist/api/components/endpoint.d.ts +11 -12
  10. package/dist/api/components/endpoint.js.map +1 -1
  11. package/dist/api/components/query-storage.d.ts +0 -1
  12. package/dist/api/components/query-storage.js +1 -1
  13. package/dist/api/components/query-storage.js.map +1 -1
  14. package/dist/api/index.d.ts +0 -1
  15. package/dist/api/types/api.interface.d.ts +0 -1
  16. package/dist/api/types/endpoint.interface.d.ts +0 -1
  17. package/dist/api/types/query.interface.d.ts +0 -1
  18. package/dist/api/utils/api-helpers.d.ts +0 -1
  19. package/dist/{core/storage → api}/utils/cache.util.d.ts +3 -6
  20. package/dist/{core/storage → api}/utils/cache.util.js +4 -7
  21. package/dist/api/utils/cache.util.js.map +1 -0
  22. package/dist/api/utils/create-header-context.d.ts +0 -1
  23. package/dist/api/utils/endpoint-headers.d.ts +0 -1
  24. package/dist/api/utils/fetch-base-query.d.ts +0 -1
  25. package/dist/api/utils/file-utils.d.ts +0 -1
  26. package/dist/api/utils/get-cacheable-headers.d.ts +0 -1
  27. package/dist/core/index.d.ts +0 -1
  28. package/dist/core/selector/index.d.ts +1 -1
  29. package/dist/core/selector/index.js +2 -0
  30. package/dist/core/selector/index.js.map +1 -1
  31. package/dist/core/selector/selector.interface.d.ts +15 -30
  32. package/dist/core/selector/selector.interface.js +2 -2
  33. package/dist/core/selector/selector.interface.js.map +1 -1
  34. package/dist/core/selector/selector.module.d.ts +16 -1
  35. package/dist/core/selector/selector.module.js +82 -20
  36. package/dist/core/selector/selector.module.js.map +1 -1
  37. package/dist/core/selector/selectors.base.d.ts +56 -0
  38. package/dist/core/selector/selectors.base.js +118 -0
  39. package/dist/core/selector/selectors.base.js.map +1 -0
  40. package/dist/core/storage/adapters/async-base-storage.service.d.ts +15 -4
  41. package/dist/core/storage/adapters/async-base-storage.service.js +106 -36
  42. package/dist/core/storage/adapters/async-base-storage.service.js.map +1 -1
  43. package/dist/core/storage/adapters/indexed-DB.service.d.ts +4 -5
  44. package/dist/core/storage/adapters/indexed-DB.service.js +66 -14
  45. package/dist/core/storage/adapters/indexed-DB.service.js.map +1 -1
  46. package/dist/core/storage/adapters/local-storage.service.d.ts +9 -4
  47. package/dist/core/storage/adapters/local-storage.service.js +25 -5
  48. package/dist/core/storage/adapters/local-storage.service.js.map +1 -1
  49. package/dist/core/storage/adapters/memory-storage.service.d.ts +2 -4
  50. package/dist/core/storage/adapters/memory-storage.service.js +5 -5
  51. package/dist/core/storage/adapters/memory-storage.service.js.map +1 -1
  52. package/dist/core/storage/adapters/path.utils.d.ts +0 -1
  53. package/dist/core/storage/adapters/storage-core.d.ts +6 -2
  54. package/dist/core/storage/adapters/storage-core.js +6 -3
  55. package/dist/core/storage/adapters/storage-core.js.map +1 -1
  56. package/dist/core/storage/adapters/sync-base-storage.service.d.ts +20 -4
  57. package/dist/core/storage/adapters/sync-base-storage.service.js +110 -35
  58. package/dist/core/storage/adapters/sync-base-storage.service.js.map +1 -1
  59. package/dist/core/storage/index.d.ts +2 -5
  60. package/dist/core/storage/index.js +1 -5
  61. package/dist/core/storage/index.js.map +1 -1
  62. package/dist/core/storage/middlewares/broadcast.middleware.d.ts +0 -1
  63. package/dist/core/storage/middlewares/index.d.ts +3 -1
  64. package/dist/core/storage/middlewares/index.js +6 -0
  65. package/dist/core/storage/middlewares/index.js.map +1 -1
  66. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts +0 -1
  67. package/dist/core/storage/middlewares/storage-logger.middleware.d.ts +20 -0
  68. package/dist/core/storage/middlewares/storage-logger.middleware.js +53 -0
  69. package/dist/core/storage/middlewares/storage-logger.middleware.js.map +1 -0
  70. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts +0 -1
  71. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js +4 -10
  72. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js.map +1 -1
  73. package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts +0 -1
  74. package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts +0 -1
  75. package/dist/core/storage/middlewares/sync-storage-logger.middleware.d.ts +7 -0
  76. package/dist/core/storage/middlewares/sync-storage-logger.middleware.js +48 -0
  77. package/dist/core/storage/middlewares/sync-storage-logger.middleware.js.map +1 -0
  78. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts +0 -1
  79. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js +4 -10
  80. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js.map +1 -1
  81. package/dist/core/storage/modules/singleton/mixin.util.d.ts +0 -1
  82. package/dist/core/storage/modules/singleton/models.d.ts +0 -1
  83. package/dist/core/storage/modules/singleton/singleton.util.d.ts +0 -1
  84. package/dist/core/storage/storage.interface.d.ts +59 -4
  85. package/dist/core/storage/storage.interface.js +0 -2
  86. package/dist/core/storage/storage.interface.js.map +1 -1
  87. package/dist/core/storage/utils/broadcast.util.d.ts +0 -1
  88. package/dist/core/storage/utils/middleware-module.d.ts +0 -3
  89. package/dist/core/storage/utils/middleware-module.js +0 -8
  90. package/dist/core/storage/utils/middleware-module.js.map +1 -1
  91. package/dist/core/storage/utils/migration.util.d.ts +38 -0
  92. package/dist/core/storage/utils/migration.util.js +48 -0
  93. package/dist/core/storage/utils/migration.util.js.map +1 -0
  94. package/dist/core/storage/utils/path-selector.util.d.ts +0 -1
  95. package/dist/core/storage/utils/state-diff.util.d.ts +8 -1
  96. package/dist/core/storage/utils/state-diff.util.js +17 -1
  97. package/dist/core/storage/utils/state-diff.util.js.map +1 -1
  98. package/dist/core/storage/utils/storage-factory.util.d.ts +7 -9
  99. package/dist/core/storage/utils/storage-factory.util.js +10 -10
  100. package/dist/core/storage/utils/storage-factory.util.js.map +1 -1
  101. package/dist/core/storage/utils/storage-key.d.ts +0 -1
  102. package/dist/index.d.ts +0 -1
  103. package/dist/react/hooks/index.d.ts +2 -1
  104. package/dist/react/hooks/index.js +4 -0
  105. package/dist/react/hooks/index.js.map +1 -1
  106. package/dist/react/hooks/useCreateStorage.d.ts +5 -6
  107. package/dist/react/hooks/useCreateStorage.js +2 -2
  108. package/dist/react/hooks/useCreateStorage.js.map +1 -1
  109. package/dist/react/hooks/useObservable.d.ts +17 -0
  110. package/dist/react/hooks/useObservable.js +38 -0
  111. package/dist/react/hooks/useObservable.js.map +1 -0
  112. package/dist/react/hooks/useSelector.d.ts +0 -1
  113. package/dist/react/hooks/useSelector.js +5 -2
  114. package/dist/react/hooks/useSelector.js.map +1 -1
  115. package/dist/react/hooks/useStorage.d.ts +0 -1
  116. package/dist/react/hooks/useStorageSubscribe.d.ts +0 -1
  117. package/dist/react/hooks/useSubscription.d.ts +13 -0
  118. package/dist/react/hooks/useSubscription.js +23 -0
  119. package/dist/react/hooks/useSubscription.js.map +1 -0
  120. package/dist/react/index.d.ts +0 -1
  121. package/dist/react/utils/awaitSynapse.d.ts +9 -10
  122. package/dist/react/utils/awaitSynapse.js +3 -2
  123. package/dist/react/utils/awaitSynapse.js.map +1 -1
  124. package/dist/react/utils/createSynapseCtx.d.ts +18 -23
  125. package/dist/react/utils/createSynapseCtx.js +64 -39
  126. package/dist/react/utils/createSynapseCtx.js.map +1 -1
  127. package/dist/react/utils/index.d.ts +0 -1
  128. package/dist/reactive/dispatcher/dispatcher.base.d.ts +122 -0
  129. package/dist/reactive/dispatcher/dispatcher.base.js +294 -0
  130. package/dist/reactive/dispatcher/dispatcher.base.js.map +1 -0
  131. package/dist/reactive/dispatcher/dispatcher.module.d.ts +12 -67
  132. package/dist/reactive/dispatcher/dispatcher.module.js +13 -72
  133. package/dist/reactive/dispatcher/dispatcher.module.js.map +1 -1
  134. package/dist/reactive/dispatcher/index.d.ts +1 -1
  135. package/dist/reactive/dispatcher/index.js +2 -0
  136. package/dist/reactive/dispatcher/index.js.map +1 -1
  137. package/dist/reactive/dispatcher/middlewares/index.d.ts +0 -1
  138. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts +0 -1
  139. package/dist/reactive/dispatcher/path.util.d.ts +15 -0
  140. package/dist/reactive/dispatcher/path.util.js +34 -0
  141. package/dist/reactive/dispatcher/path.util.js.map +1 -0
  142. package/dist/reactive/dispatcher/standalone.d.ts +1 -150
  143. package/dist/reactive/dispatcher/standalone.js +6 -217
  144. package/dist/reactive/dispatcher/standalone.js.map +1 -1
  145. package/dist/reactive/effects/effects.base.d.ts +62 -0
  146. package/dist/reactive/effects/effects.base.js +90 -0
  147. package/dist/reactive/effects/effects.base.js.map +1 -0
  148. package/dist/reactive/effects/effects.module.d.ts +122 -11
  149. package/dist/reactive/effects/effects.module.js +129 -17
  150. package/dist/reactive/effects/effects.module.js.map +1 -1
  151. package/dist/reactive/effects/index.d.ts +1 -1
  152. package/dist/reactive/effects/index.js +2 -0
  153. package/dist/reactive/effects/index.js.map +1 -1
  154. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts +0 -1
  155. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts +0 -1
  156. package/dist/reactive/effects/utils/fromRequest.d.ts +0 -1
  157. package/dist/reactive/effects/utils/index.d.ts +0 -1
  158. package/dist/reactive/effects/utils/toObservable.d.ts +0 -1
  159. package/dist/reactive/index.d.ts +0 -1
  160. package/dist/utils/createEventBus.d.ts +47 -46
  161. package/dist/utils/createEventBus.js +152 -174
  162. package/dist/utils/createEventBus.js.map +1 -1
  163. package/dist/utils/createSynapse/createSynapse.d.ts +25 -7
  164. package/dist/utils/createSynapse/createSynapse.js +28 -98
  165. package/dist/utils/createSynapse/createSynapse.js.map +1 -1
  166. package/dist/utils/createSynapse/factory.d.ts +6 -0
  167. package/dist/utils/createSynapse/factory.js +256 -0
  168. package/dist/utils/createSynapse/factory.js.map +1 -0
  169. package/dist/utils/createSynapse/index.d.ts +2 -2
  170. package/dist/utils/createSynapse/index.js.map +1 -1
  171. package/dist/utils/createSynapse/synapse.types.d.ts +87 -0
  172. package/dist/utils/createSynapse/synapse.types.js +11 -0
  173. package/dist/utils/createSynapse/synapse.types.js.map +1 -0
  174. package/dist/utils/createSynapse/types.d.ts +6 -85
  175. package/dist/utils/createSynapse/types.js +2 -1
  176. package/dist/utils/createSynapse/types.js.map +1 -1
  177. package/dist/utils/createSynapse/waitForDependencies.d.ts +0 -1
  178. package/dist/utils/createSynapse/waitForDependencies.js +1 -1
  179. package/dist/utils/createSynapse/waitForDependencies.js.map +1 -1
  180. package/dist/utils/createSynapseAwaiter.d.ts +13 -10
  181. package/dist/utils/createSynapseAwaiter.js +30 -3
  182. package/dist/utils/createSynapseAwaiter.js.map +1 -1
  183. package/dist/utils/dehydrateModule.d.ts +6 -0
  184. package/dist/utils/dehydrateModule.js +43 -0
  185. package/dist/utils/dehydrateModule.js.map +1 -0
  186. package/dist/utils/index.d.ts +3 -3
  187. package/dist/utils/index.js +3 -0
  188. package/dist/utils/index.js.map +1 -1
  189. package/package.json +12 -2
  190. package/dist/_utils/chunk.util.d.ts.map +0 -1
  191. package/dist/_utils/deepMerge.util.d.ts.map +0 -1
  192. package/dist/_utils/error-handling.util.d.ts.map +0 -1
  193. package/dist/_utils/flatMap.util.d.ts.map +0 -1
  194. package/dist/_utils/index.d.ts.map +0 -1
  195. package/dist/_utils/logger-console.util.d.ts.map +0 -1
  196. package/dist/api/api.module.d.ts.map +0 -1
  197. package/dist/api/components/endpoint.d.ts.map +0 -1
  198. package/dist/api/components/query-storage.d.ts.map +0 -1
  199. package/dist/api/example.d.ts +0 -83
  200. package/dist/api/example.d.ts.map +0 -1
  201. package/dist/api/example.js +0 -90
  202. package/dist/api/example.js.map +0 -1
  203. package/dist/api/index.d.ts.map +0 -1
  204. package/dist/api/types/api.interface.d.ts.map +0 -1
  205. package/dist/api/types/endpoint.interface.d.ts.map +0 -1
  206. package/dist/api/types/query.interface.d.ts.map +0 -1
  207. package/dist/api/utils/api-helpers.d.ts.map +0 -1
  208. package/dist/api/utils/create-header-context.d.ts.map +0 -1
  209. package/dist/api/utils/endpoint-headers.d.ts.map +0 -1
  210. package/dist/api/utils/fetch-base-query.d.ts.map +0 -1
  211. package/dist/api/utils/file-utils.d.ts.map +0 -1
  212. package/dist/api/utils/get-cacheable-headers.d.ts.map +0 -1
  213. package/dist/core/index.d.ts.map +0 -1
  214. package/dist/core/selector/index.d.ts.map +0 -1
  215. package/dist/core/selector/selector.interface.d.ts.map +0 -1
  216. package/dist/core/selector/selector.module.d.ts.map +0 -1
  217. package/dist/core/storage/adapters/async-base-storage.service.d.ts.map +0 -1
  218. package/dist/core/storage/adapters/indexed-DB.service.d.ts.map +0 -1
  219. package/dist/core/storage/adapters/local-storage.service.d.ts.map +0 -1
  220. package/dist/core/storage/adapters/memory-storage.service.d.ts.map +0 -1
  221. package/dist/core/storage/adapters/path.utils.d.ts.map +0 -1
  222. package/dist/core/storage/adapters/storage-core.d.ts.map +0 -1
  223. package/dist/core/storage/adapters/sync-base-storage.service.d.ts.map +0 -1
  224. package/dist/core/storage/index.d.ts.map +0 -1
  225. package/dist/core/storage/middlewares/broadcast.middleware.d.ts.map +0 -1
  226. package/dist/core/storage/middlewares/index.d.ts.map +0 -1
  227. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts.map +0 -1
  228. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts.map +0 -1
  229. package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts.map +0 -1
  230. package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts.map +0 -1
  231. package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts.map +0 -1
  232. package/dist/core/storage/modules/plugin/plugin.interface.d.ts +0 -101
  233. package/dist/core/storage/modules/plugin/plugin.interface.d.ts.map +0 -1
  234. package/dist/core/storage/modules/plugin/plugin.interface.js +0 -8
  235. package/dist/core/storage/modules/plugin/plugin.interface.js.map +0 -1
  236. package/dist/core/storage/modules/plugin/plugin.service.d.ts +0 -49
  237. package/dist/core/storage/modules/plugin/plugin.service.d.ts.map +0 -1
  238. package/dist/core/storage/modules/plugin/plugin.service.js +0 -406
  239. package/dist/core/storage/modules/plugin/plugin.service.js.map +0 -1
  240. package/dist/core/storage/modules/singleton/mixin.util.d.ts.map +0 -1
  241. package/dist/core/storage/modules/singleton/models.d.ts.map +0 -1
  242. package/dist/core/storage/modules/singleton/singleton.util.d.ts.map +0 -1
  243. package/dist/core/storage/storage.interface.d.ts.map +0 -1
  244. package/dist/core/storage/utils/broadcast.util.d.ts.map +0 -1
  245. package/dist/core/storage/utils/cache.util.d.ts.map +0 -1
  246. package/dist/core/storage/utils/cache.util.js.map +0 -1
  247. package/dist/core/storage/utils/middleware-module.d.ts.map +0 -1
  248. package/dist/core/storage/utils/path-selector.util.d.ts.map +0 -1
  249. package/dist/core/storage/utils/state-diff.util.d.ts.map +0 -1
  250. package/dist/core/storage/utils/storage-factory.util.d.ts.map +0 -1
  251. package/dist/core/storage/utils/storage-key.d.ts.map +0 -1
  252. package/dist/core/storage/utils/storage.utils.d.ts +0 -17
  253. package/dist/core/storage/utils/storage.utils.d.ts.map +0 -1
  254. package/dist/core/storage/utils/storage.utils.js +0 -57
  255. package/dist/core/storage/utils/storage.utils.js.map +0 -1
  256. package/dist/index.d.ts.map +0 -1
  257. package/dist/react/hooks/index.d.ts.map +0 -1
  258. package/dist/react/hooks/useCreateStorage.d.ts.map +0 -1
  259. package/dist/react/hooks/useSelector.d.ts.map +0 -1
  260. package/dist/react/hooks/useStorage.d.ts.map +0 -1
  261. package/dist/react/hooks/useStorageSubscribe.d.ts.map +0 -1
  262. package/dist/react/index.d.ts.map +0 -1
  263. package/dist/react/utils/awaitSynapse.d.ts.map +0 -1
  264. package/dist/react/utils/createSynapseCtx.d.ts.map +0 -1
  265. package/dist/react/utils/index.d.ts.map +0 -1
  266. package/dist/reactive/dispatcher/dispatcher.module.d.ts.map +0 -1
  267. package/dist/reactive/dispatcher/index.d.ts.map +0 -1
  268. package/dist/reactive/dispatcher/middlewares/index.d.ts.map +0 -1
  269. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts.map +0 -1
  270. package/dist/reactive/dispatcher/standalone.d.ts.map +0 -1
  271. package/dist/reactive/effects/effects.module.d.ts.map +0 -1
  272. package/dist/reactive/effects/index.d.ts.map +0 -1
  273. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts.map +0 -1
  274. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts.map +0 -1
  275. package/dist/reactive/effects/utils/fromRequest.d.ts.map +0 -1
  276. package/dist/reactive/effects/utils/index.d.ts.map +0 -1
  277. package/dist/reactive/effects/utils/toObservable.d.ts.map +0 -1
  278. package/dist/reactive/index.d.ts.map +0 -1
  279. package/dist/utils/createEventBus.d.ts.map +0 -1
  280. package/dist/utils/createSynapse/createSynapse.d.ts.map +0 -1
  281. package/dist/utils/createSynapse/index.d.ts.map +0 -1
  282. package/dist/utils/createSynapse/types.d.ts.map +0 -1
  283. package/dist/utils/createSynapse/validate.d.ts +0 -2
  284. package/dist/utils/createSynapse/validate.d.ts.map +0 -1
  285. package/dist/utils/createSynapse/validate.js +0 -76
  286. package/dist/utils/createSynapse/validate.js.map +0 -1
  287. package/dist/utils/createSynapse/waitForDependencies.d.ts.map +0 -1
  288. package/dist/utils/createSynapseAwaiter.d.ts.map +0 -1
  289. package/dist/utils/index.d.ts.map +0 -1
@@ -0,0 +1,118 @@
1
+ import { SynapseError } from "../../_utils/error-handling.util.js";
2
+ import { SelectorModule, deepEquals } from "./selector.module.js";
3
+
4
+
5
+
6
+
7
+
8
+ /**
9
+ * Определяет, передан ли в конструктор готовый модуль селекторов или storage.
10
+ * Модуль распознаётся по методу `createSelector` (у `IStorage` его нет).
11
+ */ function isSelectorModule(source) {
12
+ return typeof source.createSelector === 'function';
13
+ }
14
+ /**
15
+ * Публичный class-based слой селекторов. Селекторы объявляются как поля класса через
16
+ * фабрики `this.select` / `this.combine` / `this.keyed` — поля сразу настоящие
17
+ * `SelectorAPI` (eager-материализация, никаких рецептов).
18
+ *
19
+ * Внешние селекторы (cross-store) передаются параметрами конструктора подкласса:
20
+ * parameter properties присваиваются ДО инициализаторов полей, поэтому `this.core`
21
+ * в полях доступен корректно.
22
+ *
23
+ * Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном
24
+ * namespace и НЕ конфликтуют с полями-селекторами подкласса (можно объявить селектор
25
+ * `track`, `module` и т.п.). Зарезервированы лишь `protected`/публичные члены
26
+ * (`select`/`combine`/`keyed`/`destroy`) — их именами селекторы называть нельзя.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * class PostsSelectors extends Selectors<PostsState> {
31
+ * constructor(storage: IStorage<PostsState>, private readonly core: CoreSelectors) {
32
+ * super(storage)
33
+ * }
34
+ *
35
+ * private readonly api = this.select((s) => s.api)
36
+ * readonly list = this.select((s) => s.list)
37
+ * readonly isPostsLoading = this.combine([this.api], (a) => a.postsRequest.status === 'loading')
38
+ * // cross-store: пересчитывается при изменении чужого стора
39
+ * readonly currentUserId = this.combine([this.core.profile], (p) => p?.user_info?.id ?? null)
40
+ * }
41
+ * ```
42
+ */ class Selectors {
43
+ /** Модуль, поверх которого работает class-слой. */ #module;
44
+ /** Владеем ли мы модулем (создали из storage) — только тогда destroy уничтожает его целиком. */ #ownsModule;
45
+ /** id всех созданных нами селекторов — для точечной очистки общего (чужого) модуля. */ #ownSelectorIds = [];
46
+ /** Кэши keyed-фабрик — очищаются при destroy. */ #keyedCaches = [];
47
+ /** Принимает `storage` (создаёт и владеет своим `SelectorModule`) либо готовый модуль. */ constructor(source){
48
+ if (isSelectorModule(source)) {
49
+ this.#module = source;
50
+ this.#ownsModule = false;
51
+ } else {
52
+ this.#module = new SelectorModule(source);
53
+ this.#ownsModule = true;
54
+ }
55
+ }
56
+ /** Простой селектор: мемоизация по ссылке стейта + трекинг затронутых ключей. */ select(selector, options) {
57
+ return this.#track(this.#module.createSelector(selector, options));
58
+ }
59
+ /** Combined-селектор; зависимости — любые `SelectorAPI`, в т.ч. из других сторов. */ combine(deps, fn, options) {
60
+ if (process.env.NODE_ENV !== 'production') this.#assertDepsDefined(deps);
61
+ return this.#track(this.#module.createSelector(deps, fn, options));
62
+ }
63
+ /**
64
+ * Dev-проверка зависимостей `combine`. Ловит частую ловушку: cross-store eager-селектор
65
+ * (`this.combine([this.core.x], …)`, где `core` — parameter property конструктора) при
66
+ * `useDefineForClassFields: true` (дефолт target ES2022) видит `this.core === undefined`
67
+ * на момент инициализатора поля — зависимость молча оказывается `undefined`, селектор не
68
+ * пересчитывается и тихо отдаёт мусор. Бросаем понятную ошибку вместо тихого сбоя.
69
+ */ #assertDepsDefined(deps) {
70
+ const badIndex = deps.findIndex((dep)=>dep == null || typeof dep.subscribe !== 'function');
71
+ if (badIndex !== -1) {
72
+ throw new SynapseError(`combine(): зависимость #${badIndex} === ${String(deps[badIndex])} (не SelectorAPI). ` + 'Похоже, cross-store селектор инициализируется ДО присваивания parameter property ' + '(`this.<dep>` ещё undefined в момент инициализатора поля). Включите ' + '`"useDefineForClassFields": false` в tsconfig, либо создавайте такие селекторы ' + 'в теле конструктора после `super()`.', 'Selectors.combine');
73
+ }
74
+ }
75
+ /**
76
+ * Параметрический (keyed) селектор: один `SelectorAPI` на ключ (кэш по ключу).
77
+ *
78
+ * Слайсы соседних ключей живут под общим родителем (`s.byTarget[key]`), а storage при
79
+ * обновлении пере-клонирует всю ветку — поэтому ссылка соседнего ключа не сохраняется.
80
+ * Чтобы обновление ключа A не уведомляло подписчиков ключа B, keyed-селекторы по
81
+ * умолчанию сравнивают значения структурно (`deepEquals`). Опции можно переопределить.
82
+ */ keyed(fn, options) {
83
+ const cache = new Map();
84
+ this.#keyedCaches.push(cache);
85
+ return (key)=>{
86
+ let api = cache.get(key);
87
+ if (!api) {
88
+ api = this.#track(this.#module.createSelector(fn(key), {
89
+ equals: deepEquals,
90
+ ...options
91
+ }));
92
+ cache.set(key, api);
93
+ }
94
+ return api;
95
+ };
96
+ }
97
+ /**
98
+ * Уничтожает свой модуль (только если владеет им). Если модуль передан снаружи —
99
+ * удаляет из него лишь свои селекторы, чужие не трогает.
100
+ */ destroy() {
101
+ if (this.#ownsModule) {
102
+ this.#module.destroy();
103
+ } else {
104
+ for (const id of this.#ownSelectorIds){
105
+ this.#module.removeSelector(id);
106
+ }
107
+ }
108
+ this.#keyedCaches.forEach((cache)=>cache.clear());
109
+ }
110
+ /** Регистрирует id селектора для последующей точечной очистки общего модуля. */ #track(api) {
111
+ this.#ownSelectorIds.push(api.getId());
112
+ return api;
113
+ }
114
+ }
115
+
116
+ export { Selectors };
117
+
118
+ //# sourceMappingURL=selectors.base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core/selector/selectors.base.js","sources":["../../../src/core/selector/selectors.base.ts"],"sourcesContent":["import { SynapseError } from '../../_utils/error-handling.util'\nimport type { IStorage } from '../storage'\nimport type { ISelectorModule, SelectorAPI, SelectorOptions } from './selector.interface'\nimport { deepEquals, SelectorModule } from './selector.module'\n\n/**\n * Определяет, передан ли в конструктор готовый модуль селекторов или storage.\n * Модуль распознаётся по методу `createSelector` (у `IStorage` его нет).\n */\nfunction isSelectorModule<TState extends Record<string, any>>(source: IStorage<TState> | ISelectorModule<TState>): source is ISelectorModule<TState> {\n return typeof (source as ISelectorModule<TState>).createSelector === 'function'\n}\n\n/**\n * Публичный class-based слой селекторов. Селекторы объявляются как поля класса через\n * фабрики `this.select` / `this.combine` / `this.keyed` — поля сразу настоящие\n * `SelectorAPI` (eager-материализация, никаких рецептов).\n *\n * Внешние селекторы (cross-store) передаются параметрами конструктора подкласса:\n * parameter properties присваиваются ДО инициализаторов полей, поэтому `this.core`\n * в полях доступен корректно.\n *\n * Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном\n * namespace и НЕ конфликтуют с полями-селекторами подкласса (можно объявить селектор\n * `track`, `module` и т.п.). Зарезервированы лишь `protected`/публичные члены\n * (`select`/`combine`/`keyed`/`destroy`) — их именами селекторы называть нельзя.\n *\n * @example\n * ```ts\n * class PostsSelectors extends Selectors<PostsState> {\n * constructor(storage: IStorage<PostsState>, private readonly core: CoreSelectors) {\n * super(storage)\n * }\n *\n * private readonly api = this.select((s) => s.api)\n * readonly list = this.select((s) => s.list)\n * readonly isPostsLoading = this.combine([this.api], (a) => a.postsRequest.status === 'loading')\n * // cross-store: пересчитывается при изменении чужого стора\n * readonly currentUserId = this.combine([this.core.profile], (p) => p?.user_info?.id ?? null)\n * }\n * ```\n */\nexport abstract class Selectors<TState extends Record<string, any>> {\n /** Модуль, поверх которого работает class-слой. */\n readonly #module: ISelectorModule<TState>\n\n /** Владеем ли мы модулем (создали из storage) — только тогда destroy уничтожает его целиком. */\n readonly #ownsModule: boolean\n\n /** id всех созданных нами селекторов — для точечной очистки общего (чужого) модуля. */\n readonly #ownSelectorIds: string[] = []\n\n /** Кэши keyed-фабрик — очищаются при destroy. */\n readonly #keyedCaches: Array<Map<any, SelectorAPI<any>>> = []\n\n /** Принимает `storage` (создаёт и владеет своим `SelectorModule`) либо готовый модуль. */\n constructor(source: IStorage<TState> | ISelectorModule<TState>) {\n if (isSelectorModule<TState>(source)) {\n this.#module = source\n this.#ownsModule = false\n } else {\n this.#module = new SelectorModule<TState>(source)\n this.#ownsModule = true\n }\n }\n\n /** Простой селектор: мемоизация по ссылке стейта + трекинг затронутых ключей. */\n protected select<R>(selector: (state: TState) => R, options?: SelectorOptions<R>): SelectorAPI<R> {\n return this.#track(this.#module.createSelector(selector, options))\n }\n\n /** Combined-селектор; зависимости — любые `SelectorAPI`, в т.ч. из других сторов. */\n protected combine<Deps extends unknown[], R>(deps: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, fn: (...args: Deps) => R, options?: SelectorOptions<R>): SelectorAPI<R> {\n if (process.env.NODE_ENV !== 'production') this.#assertDepsDefined(deps)\n return this.#track(this.#module.createSelector(deps, fn, options))\n }\n\n /**\n * Dev-проверка зависимостей `combine`. Ловит частую ловушку: cross-store eager-селектор\n * (`this.combine([this.core.x], …)`, где `core` — parameter property конструктора) при\n * `useDefineForClassFields: true` (дефолт target ES2022) видит `this.core === undefined`\n * на момент инициализатора поля — зависимость молча оказывается `undefined`, селектор не\n * пересчитывается и тихо отдаёт мусор. Бросаем понятную ошибку вместо тихого сбоя.\n */\n #assertDepsDefined(deps: ReadonlyArray<SelectorAPI<any>>): void {\n const badIndex = deps.findIndex((dep) => dep == null || typeof dep.subscribe !== 'function')\n if (badIndex !== -1) {\n throw new SynapseError(\n `combine(): зависимость #${badIndex} === ${String(deps[badIndex])} (не SelectorAPI). ` +\n 'Похоже, cross-store селектор инициализируется ДО присваивания parameter property ' +\n '(`this.<dep>` ещё undefined в момент инициализатора поля). Включите ' +\n '`\"useDefineForClassFields\": false` в tsconfig, либо создавайте такие селекторы ' +\n 'в теле конструктора после `super()`.',\n 'Selectors.combine',\n )\n }\n }\n\n /**\n * Параметрический (keyed) селектор: один `SelectorAPI` на ключ (кэш по ключу).\n *\n * Слайсы соседних ключей живут под общим родителем (`s.byTarget[key]`), а storage при\n * обновлении пере-клонирует всю ветку — поэтому ссылка соседнего ключа не сохраняется.\n * Чтобы обновление ключа A не уведомляло подписчиков ключа B, keyed-селекторы по\n * умолчанию сравнивают значения структурно (`deepEquals`). Опции можно переопределить.\n */\n protected keyed<K extends string | number, R>(fn: (key: K) => (state: TState) => R, options?: SelectorOptions<R>): (key: K) => SelectorAPI<R> {\n const cache = new Map<K, SelectorAPI<R>>()\n this.#keyedCaches.push(cache)\n\n return (key: K): SelectorAPI<R> => {\n let api = cache.get(key)\n if (!api) {\n api = this.#track(this.#module.createSelector(fn(key), { equals: deepEquals, ...options }))\n cache.set(key, api)\n }\n return api\n }\n }\n\n /**\n * Уничтожает свой модуль (только если владеет им). Если модуль передан снаружи —\n * удаляет из него лишь свои селекторы, чужие не трогает.\n */\n destroy(): void {\n if (this.#ownsModule) {\n this.#module.destroy()\n } else {\n for (const id of this.#ownSelectorIds) {\n this.#module.removeSelector(id)\n }\n }\n this.#keyedCaches.forEach((cache) => cache.clear())\n }\n\n /** Регистрирует id селектора для последующей точечной очистки общего модуля. */\n #track<R>(api: SelectorAPI<R>): SelectorAPI<R> {\n this.#ownSelectorIds.push(api.getId())\n return api\n }\n}\n"],"names":["SynapseError","deepEquals","SelectorModule","isSelectorModule","source","Selectors","selector","options","deps","fn","process","badIndex","dep","String","cache","Map","key","api","id"],"mappings":";;;;;AAA+D;AAGD;AAE9D;;;CAGC,GACD,SAASG,gBAAgBA,CAAqCC,MAAkD;IAC9G,OAAO,OAAQA,OAAmC,cAAc,KAAK;AACvE;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC,GACM,MAAeC,SAASA;IAC7B,iDAAiD,GACxC,OAAO,CAAyB;IAEzC,8FAA8F,GACrF,WAAW,CAAS;IAE7B,qFAAqF,GAC5E,eAAe,GAAa,EAAE;IAEvC,+CAA+C,GACtC,YAAY,GAAsC,EAAE;IAE7D,wFAAwF,GACxF,YAAYD,MAAkD,CAAE;QAC9D,IAAID,gBAAgBA,CAASC,SAAS;YACpC,IAAI,CAAC,OAAO,GAAGA;YACf,IAAI,CAAC,WAAW,GAAG;QACrB,OAAO;YACL,IAAI,CAAC,OAAO,GAAG,IAAIF,cAAcA,CAASE;YAC1C,IAAI,CAAC,WAAW,GAAG;QACrB;IACF;IAEA,+EAA+E,GACrE,OAAUE,QAA8B,EAAEC,OAA4B,EAAkB;QAChG,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAACD,UAAUC;IAC3D;IAEA,mFAAmF,GACzE,QAAmCC,IAAiD,EAAEC,EAAwB,EAAEF,OAA4B,EAAkB;QACtK,IAAIG,QAAQ,GAAG,CAAC,QAAQ,KAAK,cAAc,IAAI,CAAC,kBAAkB,CAACF;QACnE,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAACA,MAAMC,IAAIF;IAC3D;IAEA;;;;;;GAMC,GACD,kBAAkB,CAACC,IAAqC;QACtD,MAAMG,WAAWH,KAAK,SAAS,CAAC,CAACI,MAAQA,OAAO,QAAQ,OAAOA,IAAI,SAAS,KAAK;QACjF,IAAID,aAAa,CAAC,GAAG;YACnB,MAAM,IAAIX,YAAYA,CACpB,CAAC,wBAAwB,EAAEW,SAAS,KAAK,EAAEE,OAAOL,IAAI,CAACG,SAAS,EAAE,mBAAmB,CAAC,GACpF,sFACA,yEACA,oFACA,wCACF;QAEJ;IACF;IAEA;;;;;;;GAOC,GACS,MAAoCF,EAAoC,EAAEF,OAA4B,EAA8B;QAC5I,MAAMO,QAAQ,IAAIC;QAClB,IAAI,CAAC,YAAY,CAAC,IAAI,CAACD;QAEvB,OAAO,CAACE;YACN,IAAIC,MAAMH,MAAM,GAAG,CAACE;YACpB,IAAI,CAACC,KAAK;gBACRA,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAACR,GAAGO,MAAM;oBAAE,QAAQf,UAAUA;oBAAE,GAAGM,OAAO;gBAAC;gBACxFO,MAAM,GAAG,CAACE,KAAKC;YACjB;YACA,OAAOA;QACT;IACF;IAEA;;;GAGC,GACD,UAAgB;QACd,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,IAAI,CAAC,OAAO,CAAC,OAAO;QACtB,OAAO;YACL,KAAK,MAAMC,MAAM,IAAI,CAAC,eAAe,CAAE;gBACrC,IAAI,CAAC,OAAO,CAAC,cAAc,CAACA;YAC9B;QACF;QACA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAACJ,QAAUA,MAAM,KAAK;IAClD;IAEA,8EAA8E,GAC9E,MAAM,CAAIG,GAAmB;QAC3B,IAAI,CAAC,eAAe,CAAC,IAAI,CAACA,IAAI,KAAK;QACnC,OAAOA;IACT;AACF"}
@@ -1,4 +1,3 @@
1
- import { IAsyncPluginExecutor } from '../modules/plugin/plugin.interface';
2
1
  import { AsyncDefaultMiddlewares, AsyncStorageConfig, IAsyncStorage, IEventEmitter, ILogger, StorageType } from '../storage.interface';
3
2
  import { StorageKeyType } from '../utils/storage-key';
4
3
  import { PathSelector, StorageCore } from './storage-core';
@@ -10,12 +9,15 @@ import { PathSelector, StorageCore } from './storage-core';
10
9
  */
11
10
  export declare abstract class AsyncBaseStorage<T extends Record<string, any>> extends StorageCore<T> implements IAsyncStorage<T> {
12
11
  protected readonly config: AsyncStorageConfig<T>;
13
- protected readonly pluginExecutor?: IAsyncPluginExecutor | undefined;
14
12
  abstract readonly type: StorageType;
15
13
  private middlewareModule;
16
14
  private initializedMiddlewares;
17
15
  private selectorPathCache;
18
- constructor(config: AsyncStorageConfig<T>, pluginExecutor?: IAsyncPluginExecutor | undefined, eventEmitter?: IEventEmitter, logger?: ILogger);
16
+ /** Версии ключей для защиты от race condition в subscribeByKey (async get). */
17
+ private keyVersions;
18
+ /** Инкремент версии ключа при каждом изменении — читается в subscribeByKey. */
19
+ protected trackKeyVersion(keyStr: string): void;
20
+ constructor(config: AsyncStorageConfig<T>, eventEmitter?: IEventEmitter, logger?: ILogger);
19
21
  protected abstract doGet(key: StorageKeyType): Promise<any>;
20
22
  protected abstract doSet(key: StorageKeyType, value: any): Promise<void>;
21
23
  protected abstract doUpdate(updates: Array<{
@@ -33,6 +35,10 @@ export declare abstract class AsyncBaseStorage<T extends Record<string, any>> ex
33
35
  protected initializeMiddlewares(): void;
34
36
  protected getDefaultMiddleware(): AsyncDefaultMiddlewares;
35
37
  protected initializeWithMiddlewares(): Promise<void>;
38
+ /** Читает сохранённую версию схемы. По умолчанию `undefined` (нет персистентности). */
39
+ protected readPersistedVersion(): Promise<number | undefined>;
40
+ /** Сохраняет версию схемы рядом с данными. По умолчанию no-op. */
41
+ protected writePersistedVersion(_version: number): Promise<void>;
36
42
  private getRawState;
37
43
  get<R>(key: StorageKeyType): Promise<R | undefined>;
38
44
  set<R>(key: StorageKeyType, value: R): Promise<void>;
@@ -40,10 +46,15 @@ export declare abstract class AsyncBaseStorage<T extends Record<string, any>> ex
40
46
  remove(key: StorageKeyType): Promise<void>;
41
47
  clear(): Promise<void>;
42
48
  reset(): Promise<void>;
49
+ /**
50
+ * SSR-гидрация: заменяет всё состояние переданным снапшотом. Намеренно НЕ требует
51
+ * `ready()` — типичный сценарий вызвать её до `initialize()`, чтобы инициализация
52
+ * не перезатёрла серверное состояние `initialState`-ом (см. `initializeWithMiddlewares`).
53
+ */
54
+ hydrate(state: T): Promise<void>;
43
55
  keys(): Promise<string[]>;
44
56
  has(key: StorageKeyType): Promise<boolean>;
45
57
  getState(): Promise<T>;
46
58
  protected subscribeByKey(key: string, callback: (value: any) => void): VoidFunction;
47
59
  protected subscribeBySelector<R>(pathSelector: PathSelector<T, R>, callback: (value: R) => void): VoidFunction;
48
60
  }
49
- //# sourceMappingURL=async-base-storage.service.d.ts.map
@@ -1,7 +1,9 @@
1
1
  import { batchingMiddleware } from "../middlewares/storage-batching.middleware.js";
2
+ import { loggerMiddleware } from "../middlewares/storage-logger.middleware.js";
2
3
  import { shallowCompareMiddleware } from "../middlewares/storage-shallow-compare.middleware.js";
3
4
  import { StorageEvents } from "../storage.interface.js";
4
5
  import { AsyncMiddlewareModule, VALUE_NOT_CHANGED } from "../utils/middleware-module.js";
6
+ import { decideMigration } from "../utils/migration.util.js";
5
7
  import { createDummyState, extractPath } from "../utils/path-selector.util.js";
6
8
  import { createLazyClone, findChangedPaths, isEqual } from "../utils/state-diff.util.js";
7
9
  import { getValueByPath } from "./path.utils.js";
@@ -22,6 +24,10 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
22
24
 
23
25
 
24
26
 
27
+
28
+
29
+
30
+
25
31
 
26
32
  /**
27
33
  * Базовый класс для асинхронных хранилищ (IndexedDB).
@@ -30,12 +36,15 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
30
36
  * Совместим с текущим API (переименован из BaseStorage).
31
37
  */ class AsyncBaseStorage extends StorageCore {
32
38
  config;
33
- pluginExecutor;
34
39
  middlewareModule;
35
40
  initializedMiddlewares = null;
36
41
  selectorPathCache = new WeakMap();
37
- constructor(config, pluginExecutor, eventEmitter, logger){
38
- super(config, eventEmitter, logger), this.config = config, this.pluginExecutor = pluginExecutor;
42
+ /** Версии ключей для защиты от race condition в subscribeByKey (async get). */ keyVersions = new Map();
43
+ /** Инкремент версии ключа при каждом изменении — читается в subscribeByKey. */ trackKeyVersion(keyStr) {
44
+ this.keyVersions.set(keyStr, (this.keyVersions.get(keyStr) ?? 0) + 1);
45
+ }
46
+ constructor(config, eventEmitter, logger){
47
+ super(config, eventEmitter, logger), this.config = config;
39
48
  this.middlewareModule = new AsyncMiddlewareModule({
40
49
  getState: ()=>this.getRawState(),
41
50
  doGet: this.doGet.bind(this),
@@ -54,7 +63,6 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
54
63
  }
55
64
  async performCleanup() {
56
65
  // Обходим публичный clear() (избегая ensureReady после _isDestroyed = true)
57
- await this.pluginExecutor?.executeOnClear();
58
66
  await this.doClear();
59
67
  await this.doDestroy();
60
68
  if (this.initializedMiddlewares) {
@@ -76,18 +84,59 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
76
84
  getDefaultMiddleware() {
77
85
  return {
78
86
  batching: (options = {})=>batchingMiddleware(options),
79
- shallowCompare: (options = {})=>shallowCompareMiddleware(options)
87
+ shallowCompare: (options = {})=>shallowCompareMiddleware(options),
88
+ logger: (options = {})=>loggerMiddleware(options)
80
89
  };
81
90
  }
82
91
  async initializeWithMiddlewares() {
83
92
  try {
84
93
  const state = await this.getRawState();
85
94
  const hasExistingState = Object.keys(state).length > 0;
86
- if (!hasExistingState && this.config.initialState) {
87
- await this.middlewareModule.dispatch({
88
- type: 'init',
89
- value: this.config.initialState
90
- });
95
+ // Миграция выключена (version не задан) — прежнее поведение: засеять initialState на пустом.
96
+ if (this.config.version === undefined) {
97
+ if (!hasExistingState && this.config.initialState) {
98
+ await this.middlewareModule.dispatch({
99
+ type: 'init',
100
+ value: this.config.initialState
101
+ });
102
+ }
103
+ return;
104
+ }
105
+ const decision = decideMigration({
106
+ hasExisting: hasExistingState,
107
+ existingState: state,
108
+ persistedVersion: await this.readPersistedVersion(),
109
+ targetVersion: this.config.version,
110
+ migrate: this.config.migrate
111
+ });
112
+ switch(decision.kind){
113
+ case 'seed':
114
+ {
115
+ if (this.config.initialState) {
116
+ await this.middlewareModule.dispatch({
117
+ type: 'init',
118
+ value: this.config.initialState
119
+ });
120
+ }
121
+ await this.writePersistedVersion(this.config.version);
122
+ break;
123
+ }
124
+ case 'migrate':
125
+ {
126
+ await this.middlewareModule.dispatch({
127
+ type: 'reset',
128
+ value: decision.state
129
+ });
130
+ await this.writePersistedVersion(this.config.version);
131
+ break;
132
+ }
133
+ case 'bump':
134
+ {
135
+ await this.writePersistedVersion(this.config.version);
136
+ break;
137
+ }
138
+ case 'none':
139
+ break;
91
140
  }
92
141
  } catch (error) {
93
142
  this.logger?.error('Ошибка инициализации хранилища', {
@@ -96,6 +145,11 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
96
145
  throw error;
97
146
  }
98
147
  }
148
+ // ─── Persisted schema version (persist-migration) ───────────────────────────
149
+ /** Читает сохранённую версию схемы. По умолчанию `undefined` (нет персистентности). */ async readPersistedVersion() {
150
+ return undefined;
151
+ }
152
+ /** Сохраняет версию схемы рядом с данными. По умолчанию no-op. */ async writePersistedVersion(_version) {}
99
153
  // ─── Internal state access ──────────────────────────────────────────────────
100
154
  async getRawState() {
101
155
  try {
@@ -117,19 +171,12 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
117
171
  timestamp: Date.now(),
118
172
  key
119
173
  };
120
- const middlewareResult = await this.middlewareModule.dispatch({
174
+ const finalResult = await this.middlewareModule.dispatch({
121
175
  type: 'get',
122
176
  key,
123
177
  metadata
124
178
  });
125
- const finalResult = await this.pluginExecutor?.executeAfterGet(key, middlewareResult, metadata) ?? middlewareResult;
126
- await this.emitEvent({
127
- type: StorageEvents.STORAGE_SELECT,
128
- payload: {
129
- key,
130
- value: finalResult
131
- }
132
- });
179
+ // Чтения не эмитят событий это горячий путь, а STORAGE_SELECT нигде не потребляется.
133
180
  return finalResult;
134
181
  } catch (error) {
135
182
  this.logger?.error('Error getting value', {
@@ -147,15 +194,13 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
147
194
  timestamp: Date.now(),
148
195
  key
149
196
  };
150
- const processedValue = await this.pluginExecutor?.executeBeforeSet(value, metadata) ?? value;
151
- const middlewareResult = await this.middlewareModule.dispatch({
197
+ const finalResult = await this.middlewareModule.dispatch({
152
198
  type: 'set',
153
199
  key,
154
- value: processedValue,
200
+ value,
155
201
  metadata
156
202
  });
157
- if (middlewareResult === VALUE_NOT_CHANGED) return;
158
- const finalResult = await this.pluginExecutor?.executeAfterSet(key, middlewareResult, metadata) ?? middlewareResult;
203
+ if (finalResult === VALUE_NOT_CHANGED) return;
159
204
  this._stateCache = await this.getRawState();
160
205
  const keyStr = key.toString();
161
206
  const changedPaths = [
@@ -210,17 +255,12 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
210
255
  for (const path of changedPaths){
211
256
  changedTopLevelKeys.add(path.split('.')[0]);
212
257
  }
213
- const updates = await Promise.all(Array.from(changedTopLevelKeys).map(async (key)=>{
214
- const keyMetadata = {
215
- ...metadata,
216
- key
217
- };
218
- const processedValue = await this.pluginExecutor?.executeBeforeSet(newState[key], keyMetadata) ?? newState[key];
258
+ const updates = Array.from(changedTopLevelKeys).map((key)=>{
219
259
  return {
220
260
  key,
221
- value: processedValue
261
+ value: newState[key]
222
262
  };
223
- }));
263
+ });
224
264
  const result = await this.middlewareModule.dispatch({
225
265
  type: 'update',
226
266
  value: updates,
@@ -313,15 +353,12 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
313
353
  timestamp: Date.now(),
314
354
  key
315
355
  };
316
- const preventDeletion = await this.pluginExecutor?.executeBeforeDelete(key, metadata);
317
- if (preventDeletion === false) return;
318
356
  const middlewareResult = await this.middlewareModule.dispatch({
319
357
  type: 'delete',
320
358
  key,
321
359
  metadata
322
360
  });
323
361
  if (middlewareResult === false) return;
324
- await this.pluginExecutor?.executeAfterDelete(key, metadata);
325
362
  this._stateCache = await this.getRawState();
326
363
  const keyStr = key.toString();
327
364
  const changedPaths = [
@@ -335,6 +372,8 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
335
372
  result: middlewareResult,
336
373
  changedPaths
337
374
  });
375
+ // Ключ удалён — освобождаем слот версии, чтобы Map не рос на динамических ключах.
376
+ this.keyVersions.delete(keyStr);
338
377
  await this.emitEvent({
339
378
  type: StorageEvents.STORAGE_UPDATE,
340
379
  payload: {
@@ -355,11 +394,11 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
355
394
  async clear() {
356
395
  this.ensureReady();
357
396
  try {
358
- await this.pluginExecutor?.executeOnClear();
359
397
  await this.middlewareModule.dispatch({
360
398
  type: 'clear'
361
399
  });
362
400
  this._stateCache = {};
401
+ this.keyVersions.clear();
363
402
  } catch (error) {
364
403
  this.logger?.error('Error clearing storage', {
365
404
  error
@@ -378,6 +417,7 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
378
417
  this._stateCache = initialState ? {
379
418
  ...initialState
380
419
  } : {};
420
+ this.keyVersions.clear();
381
421
  const changedPaths = Object.keys(this._stateCache);
382
422
  this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {
383
423
  type: StorageEvents.STORAGE_CLEAR,
@@ -396,6 +436,36 @@ import { GLOBAL_SUBSCRIPTION_KEY, StorageCore } from "./storage-core.js";
396
436
  throw error;
397
437
  }
398
438
  }
439
+ /**
440
+ * SSR-гидрация: заменяет всё состояние переданным снапшотом. Намеренно НЕ требует
441
+ * `ready()` — типичный сценарий вызвать её до `initialize()`, чтобы инициализация
442
+ * не перезатёрла серверное состояние `initialState`-ом (см. `initializeWithMiddlewares`).
443
+ */ async hydrate(state) {
444
+ try {
445
+ await this.doSet('', state);
446
+ this._stateCache = await this.getRawState();
447
+ // Если включён persist-migration — фиксируем текущую версию: серверный снапшот
448
+ // уже в актуальной схеме, миграцию на нём запускать не нужно.
449
+ if (this.config.version !== undefined) {
450
+ await this.writePersistedVersion(this.config.version);
451
+ }
452
+ const changedPaths = Object.keys(this._stateCache);
453
+ for (const key of changedPaths){
454
+ this.notifySubscribers(key, this._stateCache[key]);
455
+ }
456
+ this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {
457
+ type: StorageEvents.STORAGE_UPDATE,
458
+ key: changedPaths,
459
+ value: this._stateCache,
460
+ changedPaths
461
+ });
462
+ } catch (error) {
463
+ this.logger?.error('Error hydrating storage', {
464
+ error
465
+ });
466
+ throw error;
467
+ }
468
+ }
399
469
  async keys() {
400
470
  this.ensureReady();
401
471
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"core/storage/adapters/async-base-storage.service.js","sources":["../../../../src/core/storage/adapters/async-base-storage.service.ts"],"sourcesContent":["import { batchingMiddleware } from '../middlewares/storage-batching.middleware'\nimport { shallowCompareMiddleware } from '../middlewares/storage-shallow-compare.middleware'\nimport { IAsyncPluginExecutor } from '../modules/plugin/plugin.interface'\nimport { AsyncDefaultMiddlewares, AsyncStorageConfig, IAsyncStorage, IEventEmitter, ILogger, StorageEvents, StorageType } from '../storage.interface'\nimport { AsyncMiddlewareModule, Middleware, VALUE_NOT_CHANGED } from '../utils/middleware-module'\nimport { createDummyState, extractPath } from '../utils/path-selector.util'\nimport { createLazyClone, findChangedPaths, isEqual } from '../utils/state-diff.util'\nimport { StorageKeyType } from '../utils/storage-key'\nimport { getValueByPath } from './path.utils'\nimport { GLOBAL_SUBSCRIPTION_KEY, PathSelector, StorageCore } from './storage-core'\n\n/**\n * Базовый класс для асинхронных хранилищ (IndexedDB).\n *\n * Все CRUD-операции возвращают Promise.\n * Совместим с текущим API (переименован из BaseStorage).\n */\nexport abstract class AsyncBaseStorage<T extends Record<string, any>> extends StorageCore<T> implements IAsyncStorage<T> {\n abstract readonly type: StorageType\n\n private middlewareModule: AsyncMiddlewareModule\n private initializedMiddlewares: Middleware[] | null = null\n private selectorPathCache = new WeakMap<PathSelector<any, any>, string>()\n\n constructor(\n protected readonly config: AsyncStorageConfig<T>,\n protected readonly pluginExecutor?: IAsyncPluginExecutor,\n eventEmitter?: IEventEmitter,\n logger?: ILogger,\n ) {\n super(config, eventEmitter, logger)\n this.middlewareModule = new AsyncMiddlewareModule({\n getState: () => this.getRawState(),\n doGet: this.doGet.bind(this),\n doSet: this.doSet.bind(this),\n doUpdate: this.doUpdate.bind(this),\n doDelete: this.doDelete.bind(this),\n doClear: this.doClear.bind(this),\n doKeys: this.doKeys.bind(this),\n notifySubscribers: this.notifySubscribers.bind(this),\n })\n }\n\n // ─── Abstract async do* methods ─────────────────────────────────────────────\n\n protected abstract doGet(key: StorageKeyType): Promise<any>\n protected abstract doSet(key: StorageKeyType, value: any): Promise<void>\n protected abstract doUpdate(updates: Array<{ key: StorageKeyType; value: any }>): Promise<void>\n protected abstract doDelete(key: StorageKeyType): Promise<boolean>\n protected abstract doClear(): Promise<void>\n protected abstract doKeys(): Promise<string[]>\n protected abstract doHas(key: StorageKeyType): Promise<boolean>\n protected abstract doInitialize(): Promise<this>\n protected abstract doDestroy(): Promise<void>\n\n // ─── Lifecycle hooks ────────────────────────────────────────────────────────\n\n protected async performInitialize(): Promise<void> {\n await this.doInitialize()\n this._stateCache = await this.getRawState()\n }\n\n protected async performCleanup(): Promise<void> {\n // Обходим публичный clear() (избегая ensureReady после _isDestroyed = true)\n await this.pluginExecutor?.executeOnClear()\n await this.doClear()\n\n await this.doDestroy()\n\n if (this.initializedMiddlewares) {\n await Promise.all(\n this.initializedMiddlewares.map(async (middleware) => {\n if ('cleanup' in middleware) {\n await middleware.cleanup?.()\n }\n }),\n )\n this.initializedMiddlewares = null\n }\n }\n\n // ─── Middleware initialization ──────────────────────────────────────────────\n\n protected initializeMiddlewares(): void {\n if (this.config.middlewares && !this.initializedMiddlewares) {\n this.initializedMiddlewares = this.config.middlewares(() => this.getDefaultMiddleware())\n this.initializedMiddlewares.forEach((middleware) => this.middlewareModule.use(middleware))\n }\n }\n\n protected getDefaultMiddleware(): AsyncDefaultMiddlewares {\n return {\n batching: (options = {}) => batchingMiddleware(options),\n shallowCompare: (options = {}) => shallowCompareMiddleware(options),\n }\n }\n\n protected async initializeWithMiddlewares(): Promise<void> {\n try {\n const state = await this.getRawState()\n const hasExistingState = Object.keys(state).length > 0\n\n if (!hasExistingState && this.config.initialState) {\n await this.middlewareModule.dispatch({\n type: 'init',\n value: this.config.initialState,\n })\n }\n } catch (error) {\n this.logger?.error('Ошибка инициализации хранилища', { error })\n throw error\n }\n }\n\n // ─── Internal state access ──────────────────────────────────────────────────\n\n private async getRawState(): Promise<T> {\n try {\n const value = await this.doGet('')\n return value || {}\n } catch (error) {\n this.logger?.error('Error getting state', { error })\n throw error\n }\n }\n\n // ─── Public async API ───────────────────────────────────────────────────────\n\n public async get<R>(key: StorageKeyType): Promise<R | undefined> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'get', timestamp: Date.now(), key }\n\n const middlewareResult = await this.middlewareModule.dispatch({\n type: 'get',\n key,\n metadata,\n })\n\n const finalResult = (await this.pluginExecutor?.executeAfterGet(key, middlewareResult, metadata)) ?? middlewareResult\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_SELECT,\n payload: { key, value: finalResult },\n })\n\n return finalResult\n } catch (error) {\n this.logger?.error('Error getting value', { key, error })\n throw error\n }\n }\n\n public async set<R>(key: StorageKeyType, value: R): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'set', timestamp: Date.now(), key }\n\n const processedValue = (await this.pluginExecutor?.executeBeforeSet(value, metadata)) ?? value\n\n const middlewareResult = await this.middlewareModule.dispatch({\n type: 'set',\n key,\n value: processedValue,\n metadata,\n })\n\n if (middlewareResult === VALUE_NOT_CHANGED) return\n\n const finalResult = (await this.pluginExecutor?.executeAfterSet(key, middlewareResult, metadata)) ?? middlewareResult\n\n this._stateCache = await this.getRawState()\n\n const keyStr = key.toString()\n const changedPaths = [keyStr]\n\n this.notifySubscribers(key, finalResult)\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key,\n value: finalResult,\n changedPaths,\n })\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: { key, value: finalResult, changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error setting value', { key, error })\n throw error\n }\n }\n\n public async update(updater: (state: T) => void): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'update', timestamp: Date.now() }\n\n const currentState = (await this.getState()) as T\n const newState = createLazyClone(currentState)\n updater(newState)\n\n const changedPaths = findChangedPaths(currentState, newState)\n\n if (changedPaths.size === 0) {\n if (this.logger?.debug) {\n this.logger.debug('No changes detected in update')\n }\n return\n }\n\n if (this.logger?.debug) {\n this.logger.debug('Changed paths:', { paths: Array.from(changedPaths) })\n }\n\n const changedTopLevelKeys = new Set<string>()\n for (const path of changedPaths) {\n changedTopLevelKeys.add(path.split('.')[0])\n }\n\n const updates = await Promise.all(\n Array.from(changedTopLevelKeys).map(async (key: string) => {\n const keyMetadata = { ...metadata, key }\n const processedValue = (await this.pluginExecutor?.executeBeforeSet(newState[key], keyMetadata)) ?? newState[key]\n return { key, value: processedValue }\n }),\n )\n\n const result = await this.middlewareModule.dispatch({\n type: 'update',\n value: updates,\n metadata: {\n ...metadata,\n batchUpdate: true,\n changedPaths: Array.from(changedPaths),\n },\n })\n\n let updatedValues: Record<string, any> = {}\n if (Array.isArray(result)) {\n result.forEach((update: any) => {\n if (update && typeof update === 'object' && 'key' in update && 'value' in update) {\n updatedValues[update.key as string] = update.value\n }\n })\n } else if (result && typeof result === 'object') {\n updatedValues = { ...result }\n }\n\n const actuallyChangedKeys = Object.keys(updatedValues).filter((key) => !isEqual(currentState[key], updatedValues[key]))\n\n if (actuallyChangedKeys.length === 0) {\n if (this.logger?.debug) {\n this.logger.debug('No actual changes after middleware processing')\n }\n return\n }\n\n const finalUpdates: Record<string, any> = {}\n actuallyChangedKeys.forEach((key) => {\n finalUpdates[key] = updatedValues[key]\n })\n\n if (this.logger?.debug) {\n this.logger.debug('Notifying subscribers about changes:', { keys: actuallyChangedKeys })\n }\n\n this._stateCache = { ...currentState, ...finalUpdates } as T\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key: actuallyChangedKeys,\n value: finalUpdates,\n changedPaths: Array.from(changedPaths),\n })\n\n for (const path of changedPaths) {\n try {\n const topLevelKey = path.split('.')[0]\n if (topLevelKey in finalUpdates) {\n let value\n if (path === topLevelKey) {\n value = finalUpdates[topLevelKey]\n } else {\n const restPath = path.substring(topLevelKey.length + 1)\n value = getValueByPath(finalUpdates[topLevelKey], restPath)\n }\n if (value !== undefined) {\n this.notifySubscribers(path, value)\n }\n }\n } catch (error) {\n this.logger?.error('Error notifying path subscribers', { path, error })\n }\n }\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: {\n state: finalUpdates,\n key: actuallyChangedKeys,\n changedPaths: Array.from(changedPaths),\n },\n })\n } catch (error) {\n this.logger?.error('Error updating state', { error })\n throw error\n }\n }\n\n public async remove(key: StorageKeyType): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'delete', timestamp: Date.now(), key }\n\n const preventDeletion = await this.pluginExecutor?.executeBeforeDelete(key, metadata)\n if (preventDeletion === false) return\n\n const middlewareResult = await this.middlewareModule.dispatch({\n type: 'delete',\n key,\n metadata,\n })\n\n if (middlewareResult === false) return\n\n await this.pluginExecutor?.executeAfterDelete(key, metadata)\n\n this._stateCache = await this.getRawState()\n\n const keyStr = key.toString()\n const changedPaths = [keyStr]\n\n this.notifySubscribers(key, undefined)\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key,\n value: undefined,\n result: middlewareResult,\n changedPaths,\n })\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: { key, value: undefined, result: middlewareResult, changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error deleting value', { key, error })\n throw error\n }\n }\n\n public async clear(): Promise<void> {\n this.ensureReady()\n\n try {\n await this.pluginExecutor?.executeOnClear()\n\n await this.middlewareModule.dispatch({ type: 'clear' })\n\n this._stateCache = {} as T\n } catch (error) {\n this.logger?.error('Error clearing storage', { error })\n throw error\n }\n }\n\n public async reset(): Promise<void> {\n this.ensureReady()\n\n try {\n const initialState = this.config.initialState\n\n await this.middlewareModule.dispatch({\n type: 'reset',\n value: initialState,\n })\n\n this._stateCache = initialState ? ({ ...initialState } as T) : ({} as T)\n\n const changedPaths = Object.keys(this._stateCache)\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_CLEAR,\n changedPaths,\n })\n\n this.emitEvent({\n type: StorageEvents.STORAGE_CLEAR,\n payload: { changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error resetting storage', { error })\n throw error\n }\n }\n\n public async keys(): Promise<string[]> {\n this.ensureReady()\n\n try {\n return await this.middlewareModule.dispatch({ type: 'keys' })\n } catch (error) {\n this.logger?.error('Error getting keys', { error })\n throw error\n }\n }\n\n public async has(key: StorageKeyType): Promise<boolean> {\n this.ensureReady()\n try {\n return await this.doHas(key)\n } catch (error) {\n this.logger?.error('Error checking value existence', { key, error })\n throw error\n }\n }\n\n public async getState(): Promise<T> {\n this.ensureReady()\n return this.getRawState()\n }\n\n // ─── Subscriptions (async — with race condition protection) ────────────────\n\n protected subscribeByKey(key: string, callback: (value: any) => void): VoidFunction {\n if (!this.subscribers.has(key)) {\n this.subscribers.set(key, new Set())\n }\n this.subscribers.get(key)!.add(callback)\n\n // Запоминаем версию ключа до асинхронного get().\n // Если между вызовом get() и его разрешением произойдёт set(),\n // версия увеличится и мы не отправим устаревшее начальное значение.\n const versionAtSubscribe = this.keyVersions.get(key) ?? 0\n\n this.get(key).then((value) => {\n try {\n const currentVersion = this.keyVersions.get(key) ?? 0\n if (currentVersion === versionAtSubscribe) {\n callback(value)\n }\n } catch (error) {\n this.logger?.error('Error in initial callback', { key, error })\n }\n })\n\n return () => {\n const subscribers = this.subscribers.get(key)\n if (subscribers) {\n subscribers.delete(callback)\n if (subscribers.size === 0) {\n this.subscribers.delete(key)\n }\n }\n }\n }\n\n protected subscribeBySelector<R>(pathSelector: PathSelector<T, R>, callback: (value: R) => void): VoidFunction {\n const dummyState = createDummyState<T>()\n const fullPath = extractPath(pathSelector, dummyState, this.selectorPathCache)\n\n if (this.logger?.debug) {\n this.logger.debug('Subscribing to path:', { path: fullPath })\n }\n\n const wrappedCallback = async (value: any) => {\n try {\n if (value === undefined || value === null) {\n const currentState = (await this.getState()) as T\n const selectedValue = pathSelector(currentState)\n callback(selectedValue as R)\n return\n }\n\n if (typeof value !== 'object' || value === null) {\n callback(value as R)\n return\n }\n\n const currentState = (await this.getState()) as T\n const selectedValue = pathSelector(currentState)\n callback(selectedValue as R)\n } catch (error) {\n this.logger?.error('Error in selector callback', { path: fullPath, error })\n callback(value as R)\n }\n }\n\n if (!fullPath) {\n return this.subscribeToAll(() => {\n this.getState().then((state) => {\n callback(pathSelector(state as T))\n })\n })\n }\n\n return this.subscribeByKey(fullPath, wrappedCallback)\n }\n}\n"],"names":["batchingMiddleware","shallowCompareMiddleware","StorageEvents","AsyncMiddlewareModule","VALUE_NOT_CHANGED","createDummyState","extractPath","createLazyClone","findChangedPaths","isEqual","getValueByPath","GLOBAL_SUBSCRIPTION_KEY","StorageCore","AsyncBaseStorage","WeakMap","config","pluginExecutor","eventEmitter","logger","Promise","middleware","options","state","hasExistingState","Object","error","value","key","metadata","Date","middlewareResult","finalResult","processedValue","keyStr","changedPaths","updater","currentState","newState","Array","changedTopLevelKeys","Set","path","updates","keyMetadata","result","updatedValues","update","actuallyChangedKeys","finalUpdates","topLevelKey","restPath","undefined","preventDeletion","initialState","callback","versionAtSubscribe","currentVersion","subscribers","pathSelector","dummyState","fullPath","wrappedCallback","selectedValue"],"mappings":"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"}
1
+ {"version":3,"file":"core/storage/adapters/async-base-storage.service.js","sources":["../../../../src/core/storage/adapters/async-base-storage.service.ts"],"sourcesContent":["import { batchingMiddleware } from '../middlewares/storage-batching.middleware'\nimport { loggerMiddleware } from '../middlewares/storage-logger.middleware'\nimport { shallowCompareMiddleware } from '../middlewares/storage-shallow-compare.middleware'\nimport { AsyncDefaultMiddlewares, AsyncStorageConfig, IAsyncStorage, IEventEmitter, ILogger, StorageEvents, StorageType } from '../storage.interface'\nimport { AsyncMiddlewareModule, Middleware, VALUE_NOT_CHANGED } from '../utils/middleware-module'\nimport { decideMigration } from '../utils/migration.util'\nimport { createDummyState, extractPath } from '../utils/path-selector.util'\nimport { createLazyClone, findChangedPaths, isEqual } from '../utils/state-diff.util'\nimport { StorageKeyType } from '../utils/storage-key'\nimport { getValueByPath } from './path.utils'\nimport { GLOBAL_SUBSCRIPTION_KEY, PathSelector, StorageCore } from './storage-core'\n\n/**\n * Базовый класс для асинхронных хранилищ (IndexedDB).\n *\n * Все CRUD-операции возвращают Promise.\n * Совместим с текущим API (переименован из BaseStorage).\n */\nexport abstract class AsyncBaseStorage<T extends Record<string, any>> extends StorageCore<T> implements IAsyncStorage<T> {\n abstract readonly type: StorageType\n\n private middlewareModule: AsyncMiddlewareModule\n private initializedMiddlewares: Middleware[] | null = null\n private selectorPathCache = new WeakMap<PathSelector<any, any>, string>()\n\n /** Версии ключей для защиты от race condition в subscribeByKey (async get). */\n private keyVersions = new Map<string, number>()\n\n /** Инкремент версии ключа при каждом изменении — читается в subscribeByKey. */\n protected trackKeyVersion(keyStr: string): void {\n this.keyVersions.set(keyStr, (this.keyVersions.get(keyStr) ?? 0) + 1)\n }\n\n constructor(\n protected readonly config: AsyncStorageConfig<T>,\n eventEmitter?: IEventEmitter,\n logger?: ILogger,\n ) {\n super(config, eventEmitter, logger)\n this.middlewareModule = new AsyncMiddlewareModule({\n getState: () => this.getRawState(),\n doGet: this.doGet.bind(this),\n doSet: this.doSet.bind(this),\n doUpdate: this.doUpdate.bind(this),\n doDelete: this.doDelete.bind(this),\n doClear: this.doClear.bind(this),\n doKeys: this.doKeys.bind(this),\n notifySubscribers: this.notifySubscribers.bind(this),\n })\n }\n\n // ─── Abstract async do* methods ─────────────────────────────────────────────\n\n protected abstract doGet(key: StorageKeyType): Promise<any>\n protected abstract doSet(key: StorageKeyType, value: any): Promise<void>\n protected abstract doUpdate(updates: Array<{ key: StorageKeyType; value: any }>): Promise<void>\n protected abstract doDelete(key: StorageKeyType): Promise<boolean>\n protected abstract doClear(): Promise<void>\n protected abstract doKeys(): Promise<string[]>\n protected abstract doHas(key: StorageKeyType): Promise<boolean>\n protected abstract doInitialize(): Promise<this>\n protected abstract doDestroy(): Promise<void>\n\n // ─── Lifecycle hooks ────────────────────────────────────────────────────────\n\n protected async performInitialize(): Promise<void> {\n await this.doInitialize()\n this._stateCache = await this.getRawState()\n }\n\n protected async performCleanup(): Promise<void> {\n // Обходим публичный clear() (избегая ensureReady после _isDestroyed = true)\n await this.doClear()\n\n await this.doDestroy()\n\n if (this.initializedMiddlewares) {\n await Promise.all(\n this.initializedMiddlewares.map(async (middleware) => {\n if ('cleanup' in middleware) {\n await middleware.cleanup?.()\n }\n }),\n )\n this.initializedMiddlewares = null\n }\n }\n\n // ─── Middleware initialization ──────────────────────────────────────────────\n\n protected initializeMiddlewares(): void {\n if (this.config.middlewares && !this.initializedMiddlewares) {\n this.initializedMiddlewares = this.config.middlewares(() => this.getDefaultMiddleware())\n this.initializedMiddlewares.forEach((middleware) => this.middlewareModule.use(middleware))\n }\n }\n\n protected getDefaultMiddleware(): AsyncDefaultMiddlewares {\n return {\n batching: (options = {}) => batchingMiddleware(options),\n shallowCompare: (options = {}) => shallowCompareMiddleware(options),\n logger: (options = {}) => loggerMiddleware(options),\n }\n }\n\n protected async initializeWithMiddlewares(): Promise<void> {\n try {\n const state = await this.getRawState()\n const hasExistingState = Object.keys(state).length > 0\n\n // Миграция выключена (version не задан) — прежнее поведение: засеять initialState на пустом.\n if (this.config.version === undefined) {\n if (!hasExistingState && this.config.initialState) {\n await this.middlewareModule.dispatch({ type: 'init', value: this.config.initialState })\n }\n return\n }\n\n const decision = decideMigration({\n hasExisting: hasExistingState,\n existingState: state,\n persistedVersion: await this.readPersistedVersion(),\n targetVersion: this.config.version,\n migrate: this.config.migrate,\n })\n\n switch (decision.kind) {\n case 'seed': {\n if (this.config.initialState) {\n await this.middlewareModule.dispatch({ type: 'init', value: this.config.initialState })\n }\n await this.writePersistedVersion(this.config.version)\n break\n }\n case 'migrate': {\n await this.middlewareModule.dispatch({ type: 'reset', value: decision.state })\n await this.writePersistedVersion(this.config.version)\n break\n }\n case 'bump': {\n await this.writePersistedVersion(this.config.version)\n break\n }\n case 'none':\n break\n }\n } catch (error) {\n this.logger?.error('Ошибка инициализации хранилища', { error })\n throw error\n }\n }\n\n // ─── Persisted schema version (persist-migration) ───────────────────────────\n\n /** Читает сохранённую версию схемы. По умолчанию `undefined` (нет персистентности). */\n protected async readPersistedVersion(): Promise<number | undefined> {\n return undefined\n }\n\n /** Сохраняет версию схемы рядом с данными. По умолчанию no-op. */\n protected async writePersistedVersion(_version: number): Promise<void> {}\n\n // ─── Internal state access ──────────────────────────────────────────────────\n\n private async getRawState(): Promise<T> {\n try {\n const value = await this.doGet('')\n return value || {}\n } catch (error) {\n this.logger?.error('Error getting state', { error })\n throw error\n }\n }\n\n // ─── Public async API ───────────────────────────────────────────────────────\n\n public async get<R>(key: StorageKeyType): Promise<R | undefined> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'get', timestamp: Date.now(), key }\n\n const finalResult = await this.middlewareModule.dispatch({\n type: 'get',\n key,\n metadata,\n })\n\n // Чтения не эмитят событий — это горячий путь, а STORAGE_SELECT нигде не потребляется.\n return finalResult\n } catch (error) {\n this.logger?.error('Error getting value', { key, error })\n throw error\n }\n }\n\n public async set<R>(key: StorageKeyType, value: R): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'set', timestamp: Date.now(), key }\n\n const finalResult = await this.middlewareModule.dispatch({\n type: 'set',\n key,\n value,\n metadata,\n })\n\n if (finalResult === VALUE_NOT_CHANGED) return\n\n this._stateCache = await this.getRawState()\n\n const keyStr = key.toString()\n const changedPaths = [keyStr]\n\n this.notifySubscribers(key, finalResult)\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key,\n value: finalResult,\n changedPaths,\n })\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: { key, value: finalResult, changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error setting value', { key, error })\n throw error\n }\n }\n\n public async update(updater: (state: T) => void): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'update', timestamp: Date.now() }\n\n const currentState = (await this.getState()) as T\n const newState = createLazyClone(currentState)\n updater(newState)\n\n const changedPaths = findChangedPaths(currentState, newState)\n\n if (changedPaths.size === 0) {\n if (this.logger?.debug) {\n this.logger.debug('No changes detected in update')\n }\n return\n }\n\n if (this.logger?.debug) {\n this.logger.debug('Changed paths:', { paths: Array.from(changedPaths) })\n }\n\n const changedTopLevelKeys = new Set<string>()\n for (const path of changedPaths) {\n changedTopLevelKeys.add(path.split('.')[0])\n }\n\n const updates = Array.from(changedTopLevelKeys).map((key: string) => {\n return { key, value: newState[key] }\n })\n\n const result = await this.middlewareModule.dispatch({\n type: 'update',\n value: updates,\n metadata: {\n ...metadata,\n batchUpdate: true,\n changedPaths: Array.from(changedPaths),\n },\n })\n\n let updatedValues: Record<string, any> = {}\n if (Array.isArray(result)) {\n result.forEach((update: any) => {\n if (update && typeof update === 'object' && 'key' in update && 'value' in update) {\n updatedValues[update.key as string] = update.value\n }\n })\n } else if (result && typeof result === 'object') {\n updatedValues = { ...result }\n }\n\n const actuallyChangedKeys = Object.keys(updatedValues).filter((key) => !isEqual(currentState[key], updatedValues[key]))\n\n if (actuallyChangedKeys.length === 0) {\n if (this.logger?.debug) {\n this.logger.debug('No actual changes after middleware processing')\n }\n return\n }\n\n const finalUpdates: Record<string, any> = {}\n actuallyChangedKeys.forEach((key) => {\n finalUpdates[key] = updatedValues[key]\n })\n\n if (this.logger?.debug) {\n this.logger.debug('Notifying subscribers about changes:', { keys: actuallyChangedKeys })\n }\n\n this._stateCache = { ...currentState, ...finalUpdates } as T\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key: actuallyChangedKeys,\n value: finalUpdates,\n changedPaths: Array.from(changedPaths),\n })\n\n for (const path of changedPaths) {\n try {\n const topLevelKey = path.split('.')[0]\n if (topLevelKey in finalUpdates) {\n let value\n if (path === topLevelKey) {\n value = finalUpdates[topLevelKey]\n } else {\n const restPath = path.substring(topLevelKey.length + 1)\n value = getValueByPath(finalUpdates[topLevelKey], restPath)\n }\n if (value !== undefined) {\n this.notifySubscribers(path, value)\n }\n }\n } catch (error) {\n this.logger?.error('Error notifying path subscribers', { path, error })\n }\n }\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: {\n state: finalUpdates,\n key: actuallyChangedKeys,\n changedPaths: Array.from(changedPaths),\n },\n })\n } catch (error) {\n this.logger?.error('Error updating state', { error })\n throw error\n }\n }\n\n public async remove(key: StorageKeyType): Promise<void> {\n this.ensureReady()\n\n try {\n const metadata = { operation: 'delete', timestamp: Date.now(), key }\n\n const middlewareResult = await this.middlewareModule.dispatch({\n type: 'delete',\n key,\n metadata,\n })\n\n if (middlewareResult === false) return\n\n this._stateCache = await this.getRawState()\n\n const keyStr = key.toString()\n const changedPaths = [keyStr]\n\n this.notifySubscribers(key, undefined)\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key,\n value: undefined,\n result: middlewareResult,\n changedPaths,\n })\n\n // Ключ удалён — освобождаем слот версии, чтобы Map не рос на динамических ключах.\n this.keyVersions.delete(keyStr)\n\n await this.emitEvent({\n type: StorageEvents.STORAGE_UPDATE,\n payload: { key, value: undefined, result: middlewareResult, changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error deleting value', { key, error })\n throw error\n }\n }\n\n public async clear(): Promise<void> {\n this.ensureReady()\n\n try {\n await this.middlewareModule.dispatch({ type: 'clear' })\n\n this._stateCache = {} as T\n this.keyVersions.clear()\n } catch (error) {\n this.logger?.error('Error clearing storage', { error })\n throw error\n }\n }\n\n public async reset(): Promise<void> {\n this.ensureReady()\n\n try {\n const initialState = this.config.initialState\n\n await this.middlewareModule.dispatch({\n type: 'reset',\n value: initialState,\n })\n\n this._stateCache = initialState ? ({ ...initialState } as T) : ({} as T)\n this.keyVersions.clear()\n\n const changedPaths = Object.keys(this._stateCache)\n\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_CLEAR,\n changedPaths,\n })\n\n this.emitEvent({\n type: StorageEvents.STORAGE_CLEAR,\n payload: { changedPaths },\n })\n } catch (error) {\n this.logger?.error('Error resetting storage', { error })\n throw error\n }\n }\n\n /**\n * SSR-гидрация: заменяет всё состояние переданным снапшотом. Намеренно НЕ требует\n * `ready()` — типичный сценарий вызвать её до `initialize()`, чтобы инициализация\n * не перезатёрла серверное состояние `initialState`-ом (см. `initializeWithMiddlewares`).\n */\n public async hydrate(state: T): Promise<void> {\n try {\n await this.doSet('', state)\n this._stateCache = await this.getRawState()\n\n // Если включён persist-migration — фиксируем текущую версию: серверный снапшот\n // уже в актуальной схеме, миграцию на нём запускать не нужно.\n if (this.config.version !== undefined) {\n await this.writePersistedVersion(this.config.version)\n }\n\n const changedPaths = Object.keys(this._stateCache)\n for (const key of changedPaths) {\n this.notifySubscribers(key, (this._stateCache as Record<string, any>)[key])\n }\n this.notifySubscribers(GLOBAL_SUBSCRIPTION_KEY, {\n type: StorageEvents.STORAGE_UPDATE,\n key: changedPaths,\n value: this._stateCache,\n changedPaths,\n })\n } catch (error) {\n this.logger?.error('Error hydrating storage', { error })\n throw error\n }\n }\n\n public async keys(): Promise<string[]> {\n this.ensureReady()\n\n try {\n return await this.middlewareModule.dispatch({ type: 'keys' })\n } catch (error) {\n this.logger?.error('Error getting keys', { error })\n throw error\n }\n }\n\n public async has(key: StorageKeyType): Promise<boolean> {\n this.ensureReady()\n try {\n return await this.doHas(key)\n } catch (error) {\n this.logger?.error('Error checking value existence', { key, error })\n throw error\n }\n }\n\n public async getState(): Promise<T> {\n this.ensureReady()\n return this.getRawState()\n }\n\n // ─── Subscriptions (async — with race condition protection) ────────────────\n\n protected subscribeByKey(key: string, callback: (value: any) => void): VoidFunction {\n if (!this.subscribers.has(key)) {\n this.subscribers.set(key, new Set())\n }\n this.subscribers.get(key)!.add(callback)\n\n // Запоминаем версию ключа до асинхронного get().\n // Если между вызовом get() и его разрешением произойдёт set(),\n // версия увеличится и мы не отправим устаревшее начальное значение.\n const versionAtSubscribe = this.keyVersions.get(key) ?? 0\n\n this.get(key).then((value) => {\n try {\n const currentVersion = this.keyVersions.get(key) ?? 0\n if (currentVersion === versionAtSubscribe) {\n callback(value)\n }\n } catch (error) {\n this.logger?.error('Error in initial callback', { key, error })\n }\n })\n\n return () => {\n const subscribers = this.subscribers.get(key)\n if (subscribers) {\n subscribers.delete(callback)\n if (subscribers.size === 0) {\n this.subscribers.delete(key)\n }\n }\n }\n }\n\n protected subscribeBySelector<R>(pathSelector: PathSelector<T, R>, callback: (value: R) => void): VoidFunction {\n const dummyState = createDummyState<T>()\n const fullPath = extractPath(pathSelector, dummyState, this.selectorPathCache)\n\n if (this.logger?.debug) {\n this.logger.debug('Subscribing to path:', { path: fullPath })\n }\n\n const wrappedCallback = async (value: any) => {\n try {\n if (value === undefined || value === null) {\n const currentState = (await this.getState()) as T\n const selectedValue = pathSelector(currentState)\n callback(selectedValue as R)\n return\n }\n\n if (typeof value !== 'object' || value === null) {\n callback(value as R)\n return\n }\n\n const currentState = (await this.getState()) as T\n const selectedValue = pathSelector(currentState)\n callback(selectedValue as R)\n } catch (error) {\n this.logger?.error('Error in selector callback', { path: fullPath, error })\n callback(value as R)\n }\n }\n\n if (!fullPath) {\n return this.subscribeToAll(() => {\n this.getState().then((state) => {\n callback(pathSelector(state as T))\n })\n })\n }\n\n return this.subscribeByKey(fullPath, wrappedCallback)\n }\n}\n"],"names":["batchingMiddleware","loggerMiddleware","shallowCompareMiddleware","StorageEvents","AsyncMiddlewareModule","VALUE_NOT_CHANGED","decideMigration","createDummyState","extractPath","createLazyClone","findChangedPaths","isEqual","getValueByPath","GLOBAL_SUBSCRIPTION_KEY","StorageCore","AsyncBaseStorage","WeakMap","Map","keyStr","config","eventEmitter","logger","Promise","middleware","options","state","hasExistingState","Object","undefined","decision","error","_version","value","key","metadata","Date","finalResult","changedPaths","updater","currentState","newState","Array","changedTopLevelKeys","Set","path","updates","result","updatedValues","update","actuallyChangedKeys","finalUpdates","topLevelKey","restPath","middlewareResult","initialState","callback","versionAtSubscribe","currentVersion","subscribers","pathSelector","dummyState","fullPath","wrappedCallback","selectedValue"],"mappings":"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"}