synapse-storage 2.1.0

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 (448) hide show
  1. package/README.md +1038 -0
  2. package/dist/_examples/_example5.d.ts +1 -0
  3. package/dist/_examples/_example5.d.ts.map +1 -0
  4. package/dist/_examples/_example5.js +184 -0
  5. package/dist/_examples/_example5.js.map +1 -0
  6. package/dist/_examples/_example6.d.ts +1 -0
  7. package/dist/_examples/_example6.d.ts.map +1 -0
  8. package/dist/_examples/_example6.js +168 -0
  9. package/dist/_examples/_example6.js.map +1 -0
  10. package/dist/_examples/example1.d.ts +1 -0
  11. package/dist/_examples/example1.d.ts.map +1 -0
  12. package/dist/_examples/example1.js +240 -0
  13. package/dist/_examples/example1.js.map +1 -0
  14. package/dist/_examples/example2.d.ts +1 -0
  15. package/dist/_examples/example2.d.ts.map +1 -0
  16. package/dist/_examples/example2.js +81 -0
  17. package/dist/_examples/example2.js.map +1 -0
  18. package/dist/_examples/example3.d.ts +1 -0
  19. package/dist/_examples/example3.d.ts.map +1 -0
  20. package/dist/_examples/example3.js +99 -0
  21. package/dist/_examples/example3.js.map +1 -0
  22. package/dist/_examples/example4.d.ts +1 -0
  23. package/dist/_examples/example4.d.ts.map +1 -0
  24. package/dist/_examples/example4.js +172 -0
  25. package/dist/_examples/example4.js.map +1 -0
  26. package/dist/_examples/example5.d.ts +1 -0
  27. package/dist/_examples/example5.d.ts.map +1 -0
  28. package/dist/_examples/example5.js +184 -0
  29. package/dist/_examples/example5.js.map +1 -0
  30. package/dist/_examples/example6.d.ts +1 -0
  31. package/dist/_examples/example6.d.ts.map +1 -0
  32. package/dist/_examples/example6.js +168 -0
  33. package/dist/_examples/example6.js.map +1 -0
  34. package/dist/_examples/plugins.d.ts +1 -0
  35. package/dist/_examples/plugins.d.ts.map +1 -0
  36. package/dist/_examples/plugins.js +176 -0
  37. package/dist/_examples/plugins.js.map +1 -0
  38. package/dist/_examples/pokemons/PokemonList.d.ts +5 -0
  39. package/dist/_examples/pokemons/PokemonList.d.ts.map +1 -0
  40. package/dist/_examples/pokemons/PokemonList.js +166 -0
  41. package/dist/_examples/pokemons/PokemonList.js.map +1 -0
  42. package/dist/_examples/pokemons/api.d.ts +8 -0
  43. package/dist/_examples/pokemons/api.d.ts.map +1 -0
  44. package/dist/_examples/pokemons/api.js +45 -0
  45. package/dist/_examples/pokemons/api.js.map +1 -0
  46. package/dist/_examples/pokemons/app.config.d.ts +15 -0
  47. package/dist/_examples/pokemons/app.config.d.ts.map +1 -0
  48. package/dist/_examples/pokemons/app.config.js +15 -0
  49. package/dist/_examples/pokemons/app.config.js.map +1 -0
  50. package/dist/_examples/pokemons/dispatchers/pokemon.dispatcher.d.ts +9 -0
  51. package/dist/_examples/pokemons/dispatchers/pokemon.dispatcher.d.ts.map +1 -0
  52. package/dist/_examples/pokemons/dispatchers/pokemon.dispatcher.js +122 -0
  53. package/dist/_examples/pokemons/dispatchers/pokemon.dispatcher.js.map +1 -0
  54. package/dist/_examples/pokemons/effects/pokemon.effects.d.ts +16 -0
  55. package/dist/_examples/pokemons/effects/pokemon.effects.d.ts.map +1 -0
  56. package/dist/_examples/pokemons/effects/pokemon.effects.js +39 -0
  57. package/dist/_examples/pokemons/effects/pokemon.effects.js.map +1 -0
  58. package/dist/_examples/pokemons/middlewares/pokenon.middlewares.d.ts +4 -0
  59. package/dist/_examples/pokemons/middlewares/pokenon.middlewares.d.ts.map +1 -0
  60. package/dist/_examples/pokemons/middlewares/pokenon.middlewares.js +27 -0
  61. package/dist/_examples/pokemons/middlewares/pokenon.middlewares.js.map +1 -0
  62. package/dist/_examples/pokemons/pokemon.dispatcher.d.ts +9 -0
  63. package/dist/_examples/pokemons/pokemon.dispatcher.d.ts.map +1 -0
  64. package/dist/_examples/pokemons/pokemon.dispatcher.js +122 -0
  65. package/dist/_examples/pokemons/pokemon.dispatcher.js.map +1 -0
  66. package/dist/_examples/pokemons/pokemon.effects.d.ts +5 -0
  67. package/dist/_examples/pokemons/pokemon.effects.d.ts.map +1 -0
  68. package/dist/_examples/pokemons/pokemon.effects.js +39 -0
  69. package/dist/_examples/pokemons/pokemon.effects.js.map +1 -0
  70. package/dist/_examples/pokemons/pokemon.selectors.d.ts +5 -0
  71. package/dist/_examples/pokemons/pokemon.selectors.d.ts.map +1 -0
  72. package/dist/_examples/pokemons/pokemon.selectors.js +10 -0
  73. package/dist/_examples/pokemons/pokemon.selectors.js.map +1 -0
  74. package/dist/_examples/pokemons/pokemon.storage.d.ts +3 -0
  75. package/dist/_examples/pokemons/pokemon.storage.d.ts.map +1 -0
  76. package/dist/_examples/pokemons/pokemon.storage.js +14 -0
  77. package/dist/_examples/pokemons/pokemon.storage.js.map +1 -0
  78. package/dist/_examples/pokemons/pokemon1.selectors.d.ts +5 -0
  79. package/dist/_examples/pokemons/pokemon1.selectors.d.ts.map +1 -0
  80. package/dist/_examples/pokemons/pokemon1.selectors.js +8 -0
  81. package/dist/_examples/pokemons/pokemon1.selectors.js.map +1 -0
  82. package/dist/_examples/pokemons/pokenon.middlewares.d.ts +4 -0
  83. package/dist/_examples/pokemons/pokenon.middlewares.d.ts.map +1 -0
  84. package/dist/_examples/pokemons/pokenon.middlewares.js +27 -0
  85. package/dist/_examples/pokemons/pokenon.middlewares.js.map +1 -0
  86. package/dist/_examples/pokemons/selectors/pokemon.selectors.d.ts +5 -0
  87. package/dist/_examples/pokemons/selectors/pokemon.selectors.d.ts.map +1 -0
  88. package/dist/_examples/pokemons/selectors/pokemon.selectors.js +10 -0
  89. package/dist/_examples/pokemons/selectors/pokemon.selectors.js.map +1 -0
  90. package/dist/_examples/pokemons/selectors/pokemon1.selectors.d.ts +5 -0
  91. package/dist/_examples/pokemons/selectors/pokemon1.selectors.d.ts.map +1 -0
  92. package/dist/_examples/pokemons/selectors/pokemon1.selectors.js +8 -0
  93. package/dist/_examples/pokemons/selectors/pokemon1.selectors.js.map +1 -0
  94. package/dist/_examples/pokemons/storages/pokemon.storage.d.ts +3 -0
  95. package/dist/_examples/pokemons/storages/pokemon.storage.d.ts.map +1 -0
  96. package/dist/_examples/pokemons/storages/pokemon.storage.js +14 -0
  97. package/dist/_examples/pokemons/storages/pokemon.storage.js.map +1 -0
  98. package/dist/_examples/pokemons/store.d.ts +1 -0
  99. package/dist/_examples/pokemons/store.d.ts.map +1 -0
  100. package/dist/_examples/pokemons/store.js +2 -0
  101. package/dist/_examples/pokemons/store.js.map +1 -0
  102. package/dist/_examples/pokemons/store1.d.ts +23 -0
  103. package/dist/_examples/pokemons/store1.d.ts.map +1 -0
  104. package/dist/_examples/pokemons/store1.js +35 -0
  105. package/dist/_examples/pokemons/store1.js.map +1 -0
  106. package/dist/_examples/pokemons/store2.d.ts +23 -0
  107. package/dist/_examples/pokemons/store2.d.ts.map +1 -0
  108. package/dist/_examples/pokemons/store2.js +34 -0
  109. package/dist/_examples/pokemons/store2.js.map +1 -0
  110. package/dist/_examples/pokemons/types.d.ts +26 -0
  111. package/dist/_examples/pokemons/types.d.ts.map +1 -0
  112. package/dist/_examples/pokemons/types.js +2 -0
  113. package/dist/_examples/pokemons/types.js.map +1 -0
  114. package/dist/_utils/chunk.util.d.ts +8 -0
  115. package/dist/_utils/chunk.util.d.ts.map +1 -0
  116. package/dist/_utils/chunk.util.js +21 -0
  117. package/dist/_utils/chunk.util.js.map +1 -0
  118. package/dist/_utils/deepMerge.util.d.ts +2 -0
  119. package/dist/_utils/deepMerge.util.d.ts.map +1 -0
  120. package/dist/_utils/deepMerge.util.js +16 -0
  121. package/dist/_utils/deepMerge.util.js.map +1 -0
  122. package/dist/_utils/flatMap.util.d.ts +10 -0
  123. package/dist/_utils/flatMap.util.d.ts.map +1 -0
  124. package/dist/_utils/flatMap.util.js +23 -0
  125. package/dist/_utils/flatMap.util.js.map +1 -0
  126. package/dist/_utils/index.d.ts +4 -0
  127. package/dist/_utils/index.d.ts.map +1 -0
  128. package/dist/_utils/index.js +4 -0
  129. package/dist/_utils/index.js.map +1 -0
  130. package/dist/api/api.module.d.ts +38 -0
  131. package/dist/api/api.module.d.ts.map +1 -0
  132. package/dist/api/api.module.js +82 -0
  133. package/dist/api/api.module.js.map +1 -0
  134. package/dist/api/components/endpoint.d.ts +26 -0
  135. package/dist/api/components/endpoint.d.ts.map +1 -0
  136. package/dist/api/components/endpoint.js +253 -0
  137. package/dist/api/components/endpoint.js.map +1 -0
  138. package/dist/api/components/query-storage.d.ts +84 -0
  139. package/dist/api/components/query-storage.d.ts.map +1 -0
  140. package/dist/api/components/query-storage.js +221 -0
  141. package/dist/api/components/query-storage.js.map +1 -0
  142. package/dist/api/example.d.ts +83 -0
  143. package/dist/api/example.d.ts.map +1 -0
  144. package/dist/api/example.js +85 -0
  145. package/dist/api/example.js.map +1 -0
  146. package/dist/api/index.d.ts +4 -0
  147. package/dist/api/index.d.ts.map +1 -0
  148. package/dist/api/index.js +6 -0
  149. package/dist/api/index.js.map +1 -0
  150. package/dist/api/types/api.interface.d.ts +108 -0
  151. package/dist/api/types/api.interface.d.ts.map +1 -0
  152. package/dist/api/types/api.interface.js +19 -0
  153. package/dist/api/types/api.interface.js.map +1 -0
  154. package/dist/api/types/endpoint.interface.d.ts +116 -0
  155. package/dist/api/types/endpoint.interface.d.ts.map +1 -0
  156. package/dist/api/types/endpoint.interface.js +2 -0
  157. package/dist/api/types/endpoint.interface.js.map +1 -0
  158. package/dist/api/types/query.interface.d.ts +87 -0
  159. package/dist/api/types/query.interface.d.ts.map +1 -0
  160. package/dist/api/types/query.interface.js +2 -0
  161. package/dist/api/types/query.interface.js.map +1 -0
  162. package/dist/api/utils/api-helpers.d.ts +22 -0
  163. package/dist/api/utils/api-helpers.d.ts.map +1 -0
  164. package/dist/api/utils/api-helpers.js +44 -0
  165. package/dist/api/utils/api-helpers.js.map +1 -0
  166. package/dist/api/utils/create-header-context.d.ts +10 -0
  167. package/dist/api/utils/create-header-context.d.ts.map +1 -0
  168. package/dist/api/utils/create-header-context.js +36 -0
  169. package/dist/api/utils/create-header-context.js.map +1 -0
  170. package/dist/api/utils/endpoint-headers.d.ts +23 -0
  171. package/dist/api/utils/endpoint-headers.d.ts.map +1 -0
  172. package/dist/api/utils/endpoint-headers.js +57 -0
  173. package/dist/api/utils/endpoint-headers.js.map +1 -0
  174. package/dist/api/utils/fetch-base-query.d.ts +9 -0
  175. package/dist/api/utils/fetch-base-query.d.ts.map +1 -0
  176. package/dist/api/utils/fetch-base-query.js +181 -0
  177. package/dist/api/utils/fetch-base-query.js.map +1 -0
  178. package/dist/api/utils/file-utils.d.ts +43 -0
  179. package/dist/api/utils/file-utils.d.ts.map +1 -0
  180. package/dist/api/utils/file-utils.js +108 -0
  181. package/dist/api/utils/file-utils.js.map +1 -0
  182. package/dist/api/utils/get-cacheable-headers.d.ts +8 -0
  183. package/dist/api/utils/get-cacheable-headers.d.ts.map +1 -0
  184. package/dist/api/utils/get-cacheable-headers.js +21 -0
  185. package/dist/api/utils/get-cacheable-headers.js.map +1 -0
  186. package/dist/core/index.d.ts +3 -0
  187. package/dist/core/index.d.ts.map +1 -0
  188. package/dist/core/index.js +3 -0
  189. package/dist/core/index.js.map +1 -0
  190. package/dist/core/selector/index.d.ts +3 -0
  191. package/dist/core/selector/index.d.ts.map +1 -0
  192. package/dist/core/selector/index.js +2 -0
  193. package/dist/core/selector/index.js.map +1 -0
  194. package/dist/core/selector/selector.interface.d.ts +91 -0
  195. package/dist/core/selector/selector.interface.d.ts.map +1 -0
  196. package/dist/core/selector/selector.interface.js +2 -0
  197. package/dist/core/selector/selector.interface.js.map +1 -0
  198. package/dist/core/selector/selector.module.d.ts +29 -0
  199. package/dist/core/selector/selector.module.d.ts.map +1 -0
  200. package/dist/core/selector/selector.module.js +467 -0
  201. package/dist/core/selector/selector.module.js.map +1 -0
  202. package/dist/core/storage/adapters/base-storage.service.d.ts +65 -0
  203. package/dist/core/storage/adapters/base-storage.service.d.ts.map +1 -0
  204. package/dist/core/storage/adapters/base-storage.service.js +660 -0
  205. package/dist/core/storage/adapters/base-storage.service.js.map +1 -0
  206. package/dist/core/storage/adapters/idb.d.ts +52 -0
  207. package/dist/core/storage/adapters/idb.d.ts.map +1 -0
  208. package/dist/core/storage/adapters/idb.js +528 -0
  209. package/dist/core/storage/adapters/idb.js.map +1 -0
  210. package/dist/core/storage/adapters/indexed-DB.service.d.ts +63 -0
  211. package/dist/core/storage/adapters/indexed-DB.service.d.ts.map +1 -0
  212. package/dist/core/storage/adapters/indexed-DB.service.js +595 -0
  213. package/dist/core/storage/adapters/indexed-DB.service.js.map +1 -0
  214. package/dist/core/storage/adapters/indexed-DB.service.old.d.ts +38 -0
  215. package/dist/core/storage/adapters/indexed-DB.service.old.d.ts.map +1 -0
  216. package/dist/core/storage/adapters/indexed-DB.service.old.js +318 -0
  217. package/dist/core/storage/adapters/indexed-DB.service.old.js.map +1 -0
  218. package/dist/core/storage/adapters/indexed-DB.service1.d.ts +38 -0
  219. package/dist/core/storage/adapters/indexed-DB.service1.d.ts.map +1 -0
  220. package/dist/core/storage/adapters/indexed-DB.service1.js +318 -0
  221. package/dist/core/storage/adapters/indexed-DB.service1.js.map +1 -0
  222. package/dist/core/storage/adapters/indexed-DB.service2.d.ts +61 -0
  223. package/dist/core/storage/adapters/indexed-DB.service2.d.ts.map +1 -0
  224. package/dist/core/storage/adapters/indexed-DB.service2.js +596 -0
  225. package/dist/core/storage/adapters/indexed-DB.service2.js.map +1 -0
  226. package/dist/core/storage/adapters/local-storage.service.d.ts +21 -0
  227. package/dist/core/storage/adapters/local-storage.service.d.ts.map +1 -0
  228. package/dist/core/storage/adapters/local-storage.service.js +99 -0
  229. package/dist/core/storage/adapters/local-storage.service.js.map +1 -0
  230. package/dist/core/storage/adapters/memory-storage.service.d.ts +22 -0
  231. package/dist/core/storage/adapters/memory-storage.service.d.ts.map +1 -0
  232. package/dist/core/storage/adapters/memory-storage.service.js +99 -0
  233. package/dist/core/storage/adapters/memory-storage.service.js.map +1 -0
  234. package/dist/core/storage/adapters/path.utils.d.ts +5 -0
  235. package/dist/core/storage/adapters/path.utils.d.ts.map +1 -0
  236. package/dist/core/storage/adapters/path.utils.js +35 -0
  237. package/dist/core/storage/adapters/path.utils.js.map +1 -0
  238. package/dist/core/storage/factory/createSynapseStorage.factory.d.ts +1 -0
  239. package/dist/core/storage/factory/createSynapseStorage.factory.d.ts.map +1 -0
  240. package/dist/core/storage/factory/createSynapseStorage.factory.js +2 -0
  241. package/dist/core/storage/factory/createSynapseStorage.factory.js.map +1 -0
  242. package/dist/core/storage/factory/index.d.ts +2 -0
  243. package/dist/core/storage/factory/index.d.ts.map +1 -0
  244. package/dist/core/storage/factory/index.js +2 -0
  245. package/dist/core/storage/factory/index.js.map +1 -0
  246. package/dist/core/storage/index.d.ts +11 -0
  247. package/dist/core/storage/index.d.ts.map +1 -0
  248. package/dist/core/storage/index.js +12 -0
  249. package/dist/core/storage/index.js.map +1 -0
  250. package/dist/core/storage/middlewares/broadcast.middleware.d.ts +9 -0
  251. package/dist/core/storage/middlewares/broadcast.middleware.d.ts.map +1 -0
  252. package/dist/core/storage/middlewares/broadcast.middleware.js +115 -0
  253. package/dist/core/storage/middlewares/broadcast.middleware.js.map +1 -0
  254. package/dist/core/storage/middlewares/index.d.ts +4 -0
  255. package/dist/core/storage/middlewares/index.d.ts.map +1 -0
  256. package/dist/core/storage/middlewares/index.js +3 -0
  257. package/dist/core/storage/middlewares/index.js.map +1 -0
  258. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts +7 -0
  259. package/dist/core/storage/middlewares/storage-batching.middleware.d.ts.map +1 -0
  260. package/dist/core/storage/middlewares/storage-batching.middleware.js +36 -0
  261. package/dist/core/storage/middlewares/storage-batching.middleware.js.map +1 -0
  262. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts +7 -0
  263. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts.map +1 -0
  264. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js +46 -0
  265. package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js.map +1 -0
  266. package/dist/core/storage/modules/plugin/plugin.interface.d.ts +201 -0
  267. package/dist/core/storage/modules/plugin/plugin.interface.d.ts.map +1 -0
  268. package/dist/core/storage/modules/plugin/plugin.interface.js +2 -0
  269. package/dist/core/storage/modules/plugin/plugin.interface.js.map +1 -0
  270. package/dist/core/storage/modules/plugin/plugin.service.d.ts +25 -0
  271. package/dist/core/storage/modules/plugin/plugin.service.d.ts.map +1 -0
  272. package/dist/core/storage/modules/plugin/plugin.service.js +186 -0
  273. package/dist/core/storage/modules/plugin/plugin.service.js.map +1 -0
  274. package/dist/core/storage/storage.interface.d.ts +70 -0
  275. package/dist/core/storage/storage.interface.d.ts.map +1 -0
  276. package/dist/core/storage/storage.interface.js +10 -0
  277. package/dist/core/storage/storage.interface.js.map +1 -0
  278. package/dist/core/storage/utils/batch.utils.d.ts +33 -0
  279. package/dist/core/storage/utils/batch.utils.d.ts.map +1 -0
  280. package/dist/core/storage/utils/batch.utils.js +88 -0
  281. package/dist/core/storage/utils/batch.utils.js.map +1 -0
  282. package/dist/core/storage/utils/broadcast.util.d.ts +48 -0
  283. package/dist/core/storage/utils/broadcast.util.d.ts.map +1 -0
  284. package/dist/core/storage/utils/broadcast.util.js +162 -0
  285. package/dist/core/storage/utils/broadcast.util.js.map +1 -0
  286. package/dist/core/storage/utils/cache.util.d.ts +33 -0
  287. package/dist/core/storage/utils/cache.util.d.ts.map +1 -0
  288. package/dist/core/storage/utils/cache.util.js +47 -0
  289. package/dist/core/storage/utils/cache.util.js.map +1 -0
  290. package/dist/core/storage/utils/middleware-module.d.ts +46 -0
  291. package/dist/core/storage/utils/middleware-module.d.ts.map +1 -0
  292. package/dist/core/storage/utils/middleware-module.js +109 -0
  293. package/dist/core/storage/utils/middleware-module.js.map +1 -0
  294. package/dist/core/storage/utils/storage-key.d.ts +11 -0
  295. package/dist/core/storage/utils/storage-key.d.ts.map +1 -0
  296. package/dist/core/storage/utils/storage-key.js +21 -0
  297. package/dist/core/storage/utils/storage-key.js.map +1 -0
  298. package/dist/core/storage/utils/storage.utils.d.ts +17 -0
  299. package/dist/core/storage/utils/storage.utils.d.ts.map +1 -0
  300. package/dist/core/storage/utils/storage.utils.js +57 -0
  301. package/dist/core/storage/utils/storage.utils.js.map +1 -0
  302. package/dist/examples/_example5.d.ts +1 -0
  303. package/dist/examples/_example5.d.ts.map +1 -0
  304. package/dist/examples/_example5.js +184 -0
  305. package/dist/examples/_example5.js.map +1 -0
  306. package/dist/examples/_example6.d.ts +1 -0
  307. package/dist/examples/_example6.d.ts.map +1 -0
  308. package/dist/examples/_example6.js +168 -0
  309. package/dist/examples/_example6.js.map +1 -0
  310. package/dist/examples/plugins.d.ts +1 -0
  311. package/dist/examples/plugins.d.ts.map +1 -0
  312. package/dist/examples/plugins.js +176 -0
  313. package/dist/examples/plugins.js.map +1 -0
  314. package/dist/examples/pokemons/PokemonList.d.ts +2 -0
  315. package/dist/examples/pokemons/PokemonList.d.ts.map +1 -0
  316. package/dist/examples/pokemons/PokemonList.js +110 -0
  317. package/dist/examples/pokemons/PokemonList.js.map +1 -0
  318. package/dist/examples/pokemons/api.d.ts +22 -0
  319. package/dist/examples/pokemons/api.d.ts.map +1 -0
  320. package/dist/examples/pokemons/api.js +43 -0
  321. package/dist/examples/pokemons/api.js.map +1 -0
  322. package/dist/examples/pokemons/app.config.d.ts +15 -0
  323. package/dist/examples/pokemons/app.config.d.ts.map +1 -0
  324. package/dist/examples/pokemons/app.config.js +15 -0
  325. package/dist/examples/pokemons/app.config.js.map +1 -0
  326. package/dist/examples/pokemons/dispatchers/pokemon.dispatcher.js +128 -0
  327. package/dist/examples/pokemons/dispatchers/pokemon.dispatcher.js.map +1 -0
  328. package/dist/examples/pokemons/effects/pokemon.effects.d.ts +16 -0
  329. package/dist/examples/pokemons/effects/pokemon.effects.d.ts.map +1 -0
  330. package/dist/examples/pokemons/effects/pokemon.effects.js +51 -0
  331. package/dist/examples/pokemons/effects/pokemon.effects.js.map +1 -0
  332. package/dist/examples/pokemons/middlewares/pokenon.middlewares.d.ts +4 -0
  333. package/dist/examples/pokemons/middlewares/pokenon.middlewares.d.ts.map +1 -0
  334. package/dist/examples/pokemons/middlewares/pokenon.middlewares.js +28 -0
  335. package/dist/examples/pokemons/middlewares/pokenon.middlewares.js.map +1 -0
  336. package/dist/examples/pokemons/selectors/pokemon.selectors.d.ts +13 -0
  337. package/dist/examples/pokemons/selectors/pokemon.selectors.d.ts.map +1 -0
  338. package/dist/examples/pokemons/selectors/pokemon.selectors.js +7 -0
  339. package/dist/examples/pokemons/selectors/pokemon.selectors.js.map +1 -0
  340. package/dist/examples/pokemons/storages/pokemon.storage.d.ts +5 -0
  341. package/dist/examples/pokemons/storages/pokemon.storage.d.ts.map +1 -0
  342. package/dist/examples/pokemons/storages/pokemon.storage.js +13 -0
  343. package/dist/examples/pokemons/storages/pokemon.storage.js.map +1 -0
  344. package/dist/examples/pokemons/store.d.ts +35 -0
  345. package/dist/examples/pokemons/store.d.ts.map +1 -0
  346. package/dist/examples/pokemons/store.js +21 -0
  347. package/dist/examples/pokemons/store.js.map +1 -0
  348. package/dist/examples/pokemons/types.d.ts +26 -0
  349. package/dist/examples/pokemons/types.d.ts.map +1 -0
  350. package/dist/examples/pokemons/types.js +2 -0
  351. package/dist/examples/pokemons/types.js.map +1 -0
  352. package/dist/index.d.ts +10 -0
  353. package/dist/index.d.ts.map +1 -0
  354. package/dist/index.js +18 -0
  355. package/dist/index.js.map +1 -0
  356. package/dist/react/hooks/index.d.ts +3 -0
  357. package/dist/react/hooks/index.d.ts.map +1 -0
  358. package/dist/react/hooks/index.js +3 -0
  359. package/dist/react/hooks/index.js.map +1 -0
  360. package/dist/react/hooks/useSelector.d.ts +22 -0
  361. package/dist/react/hooks/useSelector.d.ts.map +1 -0
  362. package/dist/react/hooks/useSelector.js +104 -0
  363. package/dist/react/hooks/useSelector.js.map +1 -0
  364. package/dist/react/hooks/useStorageSubscribe.d.ts +12 -0
  365. package/dist/react/hooks/useStorageSubscribe.d.ts.map +1 -0
  366. package/dist/react/hooks/useStorageSubscribe.js +49 -0
  367. package/dist/react/hooks/useStorageSubscribe.js.map +1 -0
  368. package/dist/react/index.d.ts +3 -0
  369. package/dist/react/index.d.ts.map +1 -0
  370. package/dist/react/index.js +3 -0
  371. package/dist/react/index.js.map +1 -0
  372. package/dist/react/utils/createSynapse.d.ts +47 -0
  373. package/dist/react/utils/createSynapse.d.ts.map +1 -0
  374. package/dist/react/utils/createSynapse.js +83 -0
  375. package/dist/react/utils/createSynapse.js.map +1 -0
  376. package/dist/react/utils/createSynapseContext.d.ts +29 -0
  377. package/dist/react/utils/createSynapseContext.d.ts.map +1 -0
  378. package/dist/react/utils/createSynapseContext.js +112 -0
  379. package/dist/react/utils/createSynapseContext.js.map +1 -0
  380. package/dist/react/utils/createSynapseCtx.d.ts +30 -0
  381. package/dist/react/utils/createSynapseCtx.d.ts.map +1 -0
  382. package/dist/react/utils/createSynapseCtx.js +124 -0
  383. package/dist/react/utils/createSynapseCtx.js.map +1 -0
  384. package/dist/react/utils/index.d.ts +2 -0
  385. package/dist/react/utils/index.d.ts.map +1 -0
  386. package/dist/react/utils/index.js +2 -0
  387. package/dist/react/utils/index.js.map +1 -0
  388. package/dist/reactive/dispatcher/dispatcher.module.d.ts +195 -0
  389. package/dist/reactive/dispatcher/dispatcher.module.d.ts.map +1 -0
  390. package/dist/reactive/dispatcher/dispatcher.module.js +288 -0
  391. package/dist/reactive/dispatcher/dispatcher.module.js.map +1 -0
  392. package/dist/reactive/dispatcher/index.d.ts +3 -0
  393. package/dist/reactive/dispatcher/index.d.ts.map +1 -0
  394. package/dist/reactive/dispatcher/index.js +3 -0
  395. package/dist/reactive/dispatcher/index.js.map +1 -0
  396. package/dist/reactive/dispatcher/middlewares/index.d.ts +2 -0
  397. package/dist/reactive/dispatcher/middlewares/index.d.ts.map +1 -0
  398. package/dist/reactive/dispatcher/middlewares/index.js +2 -0
  399. package/dist/reactive/dispatcher/middlewares/index.js.map +1 -0
  400. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts +31 -0
  401. package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts.map +1 -0
  402. package/dist/reactive/dispatcher/middlewares/logger.middleware.js +126 -0
  403. package/dist/reactive/dispatcher/middlewares/logger.middleware.js.map +1 -0
  404. package/dist/reactive/effects/effects.module.d.ts +140 -0
  405. package/dist/reactive/effects/effects.module.d.ts.map +1 -0
  406. package/dist/reactive/effects/effects.module.js +263 -0
  407. package/dist/reactive/effects/effects.module.js.map +1 -0
  408. package/dist/reactive/effects/index.d.ts +2 -0
  409. package/dist/reactive/effects/index.d.ts.map +1 -0
  410. package/dist/reactive/effects/index.js +2 -0
  411. package/dist/reactive/effects/index.js.map +1 -0
  412. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts +12 -0
  413. package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts.map +1 -0
  414. package/dist/reactive/effects/utils/chunkRequestConsistent.js +16 -0
  415. package/dist/reactive/effects/utils/chunkRequestConsistent.js.map +1 -0
  416. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts +12 -0
  417. package/dist/reactive/effects/utils/chunkRequestParallel.d.ts.map +1 -0
  418. package/dist/reactive/effects/utils/chunkRequestParallel.js +13 -0
  419. package/dist/reactive/effects/utils/chunkRequestParallel.js.map +1 -0
  420. package/dist/reactive/effects/utils/index.d.ts +3 -0
  421. package/dist/reactive/effects/utils/index.d.ts.map +1 -0
  422. package/dist/reactive/effects/utils/index.js +3 -0
  423. package/dist/reactive/effects/utils/index.js.map +1 -0
  424. package/dist/reactive/index.d.ts +3 -0
  425. package/dist/reactive/index.d.ts.map +1 -0
  426. package/dist/reactive/index.js +3 -0
  427. package/dist/reactive/index.js.map +1 -0
  428. package/dist/utils/chunk.util.d.ts +8 -0
  429. package/dist/utils/chunk.util.d.ts.map +1 -0
  430. package/dist/utils/chunk.util.js +21 -0
  431. package/dist/utils/chunk.util.js.map +1 -0
  432. package/dist/utils/createSynapse.d.ts +52 -0
  433. package/dist/utils/createSynapse.d.ts.map +1 -0
  434. package/dist/utils/createSynapse.js +87 -0
  435. package/dist/utils/createSynapse.js.map +1 -0
  436. package/dist/utils/deepMerge.util.d.ts +2 -0
  437. package/dist/utils/deepMerge.util.d.ts.map +1 -0
  438. package/dist/utils/deepMerge.util.js +16 -0
  439. package/dist/utils/deepMerge.util.js.map +1 -0
  440. package/dist/utils/flatMap.util.d.ts +10 -0
  441. package/dist/utils/flatMap.util.d.ts.map +1 -0
  442. package/dist/utils/flatMap.util.js +23 -0
  443. package/dist/utils/flatMap.util.js.map +1 -0
  444. package/dist/utils/index.d.ts +2 -0
  445. package/dist/utils/index.d.ts.map +1 -0
  446. package/dist/utils/index.js +2 -0
  447. package/dist/utils/index.js.map +1 -0
  448. package/package.json +111 -0
package/README.md ADDED
@@ -0,0 +1,1038 @@
1
+ # Synapse
2
+
3
+ Synapse — это набор инструментов для управления состоянием + API-клиент.
4
+
5
+ ## Особенности
6
+
7
+ - **Не привязан к конкретному фреймворку**: Вы можете использовать Synapse в контексте любого фреймворка или независимо от него
8
+ - **Разнообразные адаптеры хранилищ**: Выбирайте между Memory, LocalStorage или IndexedDB в зависимости от ваших потребностей
9
+ - **Различный способ получения данных**: Создавайте и комбинируйте селекторы для вычисляемых значений на основе состояния в стиле Redux или просто подписывайтесь на конкретное свойство в хранилище
10
+ - Возможность создания вычисляемых селекторов в стиле Redux
11
+ - Возможность прямой подписки на конкретное свойство в хранилище
12
+ - Возможность подписки на реактивное состояние
13
+ - **Надежный API-клиент**: Создайте удобный API-клиент для вашего приложения (похож на RTK Query)
14
+ - **Поддержка middleware**: Расширяйте функциональность с помощью пользовательских middleware
15
+ - **Система плагинов**: Используйте готовые или создавайте собственные плагины для расширения функциональности
16
+ - **Отдельные возможности для реактивного подхода**: Возможность гибкой работы с api-запросами в стиле Redux-Observable и RxJS
17
+
18
+ ## Автор
19
+
20
+ **Владислав** — Senior Frontend Developer (React, TypeScript)
21
+
22
+
23
+ > ### 🔎 Нахожусь в поиске новых карьерных возможностей!
24
+ >
25
+ > [GitHub](https://github.com/Vlad92msk/) | [LinkedIn](https://www.linkedin.com/in/vlad-firsov/)
26
+
27
+
28
+ ## Установка
29
+
30
+ ```bash
31
+ npm install synapse-storage
32
+ # или
33
+ yarn add synapse-storage
34
+ # или
35
+ pnpm add synapse-storage
36
+ ```
37
+
38
+
39
+ ## В своих примерах я буду использовать top-level-await, поэтому:
40
+
41
+ ### Версии Node.js
42
+ - ✅ Node.js ≥ 14.8.0 (минимальная версия с поддержкой top-level-await)
43
+ - ✅ Node.js ≥ 16.0.0 (рекомендуется для полной поддержки)
44
+
45
+ ### Версии TypeScript
46
+ - ✅ TypeScript ≥ 3.8 (базовая поддержка)
47
+ - ✅ TypeScript ≥ 4.5 (улучшенная поддержка)
48
+ - ✅ TypeScript ≥ 5.0 (рекомендуется, полная поддержка)
49
+
50
+ ### Параметр `target` в tsconfig.json
51
+ - ✅ ES2022 (рекомендуется)
52
+ - ✅ ESNext
53
+ - ❌ ES2021 или ниже (не поддерживает top-level-await)
54
+
55
+ ### Параметр `module` в tsconfig.json
56
+ - ✅ ESNext (рекомендуется)
57
+ - ✅ NodeNext
58
+ - ✅ ES2022
59
+ - ❌ CommonJS (не поддерживает top-level-await)
60
+ - ❌ AMD, UMD, System (не поддерживают top-level-await)
61
+
62
+ ### Параметр `moduleResolution` в tsconfig.json
63
+ - ✅ bundler (для проектов использующих Vite, Webpack 5, esbuild)
64
+ - ✅ node16 или nodenext (для Node.js проектов)
65
+ - ✅ node (для совместимости со старыми проектами, не рекомендуется)
66
+ - ❓ classic (может работать с ограничениями)
67
+
68
+ ### Бандлеры и сборщики
69
+ - ✅ Vite (полная поддержка)
70
+ - ✅ Webpack 5+ (с правильной конфигурацией)
71
+ - ✅ esbuild (полная поддержка)
72
+ - ✅ Rollup (с плагином @rollup/plugin-dynamic-import-vars)
73
+ - ✅ Next.js ≥ 12 (нужен правильный build target)
74
+ - ❌ Webpack 4 и ниже
75
+
76
+ ### Пример минимальной конфигурации tsconfig.json
77
+
78
+ ```json
79
+ {
80
+ "compilerOptions": {
81
+ "target": "ES2022",
82
+ "module": "ESNext",
83
+ "moduleResolution": "bundler",
84
+ "esModuleInterop": true
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## Быстрый старт
90
+
91
+ Импорты:
92
+ ```typescript
93
+ // Инструменты создания и управления хранилищем
94
+ import {
95
+ // Хранилища
96
+ MemoryStorage,
97
+ IndexedDBStorage,
98
+ LocalStorage,
99
+
100
+ // Интерфейсы для хранилищ
101
+ IStorage,
102
+
103
+ // middleware для хранилища
104
+ broadcastMiddleware,
105
+
106
+ // Для создания кастомных плагинов хранилища
107
+ StoragePluginModule,
108
+ IStoragePlugin,
109
+ PluginContext,
110
+ StorageKeyType,
111
+
112
+ // Для создания кастомных middlewares хранилища
113
+ Middleware,
114
+ MiddlewareAPI,
115
+ NextFunction,
116
+
117
+ // Модуль создания вычисляемых селекторов в Redux стиле
118
+ SelectorModule,
119
+ ISelectorModule
120
+ } from 'synapse-storage/core'
121
+
122
+ // Инструменты для использования реактивного подхода (немного похоже на Redux-Observable)
123
+ import {
124
+ // Инструменты для создания Dispatcher
125
+ createDispatcher,
126
+ loggerDispatcherMiddleware,
127
+
128
+ // Инструменты для создания Effects (напоминает Redux-Observable)
129
+ EffectsModule,
130
+ combineEffects,
131
+ createEffect,
132
+ ofType,
133
+ ofTypes,
134
+ selectorMap,
135
+ validateMap
136
+ } from 'synapse-storage/reactive';
137
+
138
+ // Инструменты для работы с api
139
+ import { ApiClient, ResponseFormat } from 'synapse-storage/api'
140
+
141
+ // Несколько инструментов для удобного использования в React
142
+ import { useStorageSubscribe, useSelector, createSynapseCtx } from 'synapse-storage/react'
143
+
144
+ import { createSynapse } from 'synapse-storage/utils'
145
+ ```
146
+
147
+ Вот простой пример использования Synapse с React:
148
+
149
+ ```tsx
150
+ import { IndexedDBStorage, LocalStorage, MemoryStorage } from 'synapse-storage/core'
151
+ import { useEffect, useState } from 'react'
152
+
153
+ // Создаем экземпляр хранилища (MemoryStorage / LocalStorage / IndexedDBStorage)
154
+ const counterStorage = await new MemoryStorage({
155
+ name: 'counter',
156
+ initialState: { value: 0 }
157
+ }).initialize();
158
+
159
+ function Counter() {
160
+ const [count, setCount] = useState(0);
161
+
162
+ useEffect(() => {
163
+ // Подписываемся на изменения
164
+ return counterStorage.subscribe('value', setCount);
165
+ }, []);
166
+
167
+ const increment = () => {
168
+ counterStorage.update(state => {
169
+ state.value++;
170
+ });
171
+ };
172
+
173
+ return (
174
+ <div>
175
+ <p>Счетчик: {count}</p>
176
+ <button onClick={increment}>Увеличить</button>
177
+ </div>
178
+ );
179
+ }
180
+ ```
181
+ Более подробные примеры можно найти в src/examples:
182
+ - пример использования api-client(api-example.md)
183
+ - пример комбинированного использования хранилищ всех типов, демонтсрация возможностей подписок и работы базовых middlewares(base-storage-example.md)
184
+ - расширенный пример комплексного использования, включая реактивный подход (pokemons)
185
+
186
+
187
+ ## Адаптеры хранилищ
188
+
189
+ Synapse предоставляет три типа адаптеров хранилищ:
190
+
191
+ ### MemoryStorage
192
+
193
+ In-memory хранилище для временных данных, которые очищаются при перезагрузке страницы.
194
+
195
+ ```typescript
196
+ const memoryStorage = await new MemoryStorage({
197
+ name: 'tempStorage',
198
+ }).initialize();
199
+ ```
200
+
201
+ ### LocalStorage
202
+
203
+ Хранилище на основе Web Storage API для небольших объемов данных, которые сохраняются между сессиями.
204
+
205
+ ```typescript
206
+ const localStorage = await new LocalStorage({
207
+ name: 'appStorage',
208
+ }).initialize();
209
+ ```
210
+
211
+ ### IndexedDBStorage
212
+
213
+ Хранилище на основе IndexedDB для больших объемов данных и сложных структур.
214
+ Создается немного иначе, но довольно похожим образом
215
+ ```typescript
216
+ import { IndexedDBStorage } from 'synapse-storage/core'
217
+ import { IDBApi, IDBCore } from './types'
218
+
219
+ export const { CORE, API } = await IndexedDBStorage.createStorages<{
220
+ CORE: IDBCore
221
+ API: IDBApi
222
+ }>(
223
+ 'social-network', // Название базы данных в indexDB
224
+ // Таблицы:
225
+ {
226
+ // === Хранение запросов для кэширования ===
227
+ API: {
228
+ name: 'api',
229
+ // eventEmitter: ,
230
+ // initialState: ,
231
+ // middlewares: ,
232
+ // pluginExecutor: ,
233
+ },
234
+ // === Основные данные проекта ===
235
+ CORE: {
236
+ name: 'core',
237
+ initialState: {
238
+ currentUserProfile: undefined,
239
+ },
240
+ //...
241
+ },
242
+ // Другие объекты (хранилища)
243
+ },
244
+ console, // logger (может быть любой, который имплементируют интерфейс ILogger)
245
+ )
246
+ ```
247
+
248
+ ## Селекторы
249
+
250
+ Селекторы предоставляют удобный способ доступа к данным в хранилище:
251
+
252
+ ### Базовые подписки на свойства хранилища
253
+
254
+ ```typescript
255
+ // Подписка на конкретное свойство (по пути)
256
+ const unsubscribe1 = storage.subscribe('value', (event) => {
257
+ console.log('Новое значение:', event);
258
+ });
259
+
260
+ // Подписка на свойство (через функцию селектора)
261
+ const unsubscribe2 = storage.subscribe((state) => state.value, (event) => {
262
+ console.log('Новое значение:', event);
263
+ });
264
+
265
+ // Подписка на вложенные свойства
266
+ const unsubscribe3 = storage.subscribe('user.settings.theme', (event) => {
267
+ console.log('Новая тема:', event);
268
+ });
269
+ ```
270
+
271
+ ### Селекторы для вычисляемых значений (в стиле Redux)
272
+
273
+ ```typescript
274
+ // Создание модуля селекторов
275
+ const counterSelector = new SelectorModule(counterStorage);
276
+
277
+ // Создание простого селектора
278
+ const countValueSelector = counterSelector.createSelector(s => s.value);
279
+
280
+ // Комбинирование селекторов
281
+ const doubledCountSelector = counterSelector.createSelector(
282
+ [countValueSelector],
283
+ count => count * 2,
284
+ // Опционально:
285
+ // {
286
+ // equals: , // Функция сравнения
287
+ // name: 'doubledCountSelector' // Имя селектора
288
+ // }
289
+ );
290
+
291
+ // Подписка на изменения вычисляемого значения
292
+ doubledCountSelector.subscribe({
293
+ notify: value => console.log('Удвоенное значение:', value)
294
+ });
295
+
296
+ // Одноразовое получение значения
297
+ doubledCountSelector.select().then(value => {
298
+ console.log('Текущее удвоенное значение:', value);
299
+ });
300
+ ```
301
+
302
+ ## API-клиент
303
+
304
+ Synapse включает в себя API-клиент с поддержкой кеширования:
305
+
306
+ ```typescript
307
+ const api = new ApiClient({
308
+ // Настройка кеширования запросов
309
+ cacheableHeaderKeys: ['X-Auth-Token'],
310
+ storage: API, // Передаем готовое экземпляр готового хранилища
311
+ // Настройки кеша
312
+ cache: {
313
+ ttl: 5 * 60 * 1000, // Время жизни кеша: 5 минут
314
+ invalidateOnError: true, // Инвалидация кеша при ошибке
315
+ cleanup: {
316
+ enabled: true, // Периодическая очистка кеша
317
+ interval: 10 * 60 * 1000, // Интервал очистки: 10 минут
318
+ },
319
+ },
320
+ // Базовые настройки запроса
321
+ baseQuery: {
322
+ baseUrl: 'https://api.example.com',
323
+ timeout: 10000, // 10 секунд
324
+ prepareHeaders: async (headers, context) => {
325
+ // Установка заголовков
326
+ headers.set('X-Auth-Token', 'some-token');
327
+ // Получение данных из хранилища или cookies
328
+ const token = context.getCookie('token');
329
+ if (token) {
330
+ headers.set('Authorization', `Bearer ${token}`);
331
+ }
332
+ return headers;
333
+ },
334
+ credentials: 'same-origin',
335
+ },
336
+ // Определение эндпоинтов
337
+ endpoints: async (create) => ({
338
+ getData: create({
339
+ request: (params) => ({
340
+ path: '/data',
341
+ method: 'GET',
342
+ query: params,
343
+ }),
344
+ // Можно указать специфичные настройки кеша для эндпоинта
345
+ cache: {
346
+ ttl: 60 * 1000, // 1 минута для этого эндпоинта
347
+ },
348
+ }),
349
+ }),
350
+ });
351
+
352
+ // Инициализация
353
+ const myApi = await api.init();
354
+
355
+ // Использование с подпиской на состояние запроса
356
+ const request = myApi.getEndpoints().getData.request({ id: 1 });
357
+
358
+ // Вариант 1: Подписка на изменения состояния запроса
359
+ request.subscribe((state) => {
360
+ switch (state.status) {
361
+ case 'idle':
362
+ console.log('Запрос неактивен');
363
+ break;
364
+ case 'loading':
365
+ console.log('Загрузка данных...');
366
+ break;
367
+ case 'success':
368
+ console.log('Данные получены:', state.data);
369
+ break;
370
+ case 'error':
371
+ console.log('Ошибка:', state.error);
372
+ break;
373
+ }
374
+ });
375
+
376
+ // Вариант 2: Ожидание результата запроса
377
+ const response = await request.wait();
378
+
379
+ // Вариант 3: Ожидание с колбеками для разных состояний
380
+ request.waitWithCallbacks({
381
+ loading: () => console.log('Загрузка...'),
382
+ success: (data) => console.log('Данные:', data),
383
+ error: (error) => console.error('Ошибка:', error),
384
+ });
385
+ ```
386
+
387
+ ## Реактивный подход
388
+ Synapse предоставляет инструменты для использования реактивного подхода, напоминающий Redux-Observable.
389
+
390
+ Пример создания Диспетчера:
391
+ ```typescript
392
+ import { createDispatcher, loggerDispatcherMiddleware } from 'synapse-storage/reactive'
393
+ import { PokemonStorage } from '../storages/pokemon.storage'
394
+ import { createPokemonAlertMiddleware } from '../middlewares/pokenon.middlewares'
395
+ import { Pokemon } from '../types'
396
+
397
+ // const myWorker = new Worker('path-to-my-worker')
398
+
399
+ export interface AlertPayload {
400
+ message: string
401
+ type: 'info' | 'warning' | 'error' | 'success'
402
+ duration?: number // Длительность показа в миллисекундах
403
+ }
404
+
405
+ // Функция для создания диспетчера
406
+ export function createPokemonDispatcher(storage: PokemonStorage) {
407
+ // Создаем middleware: логгер
408
+ const loggerMiddleware = loggerDispatcherMiddleware({
409
+ collapsed: true, // Сворачиваем группы в консоли для компактности
410
+ colors: {
411
+ title: '#3498db', // Кастомный синий цвет для заголовка
412
+ },
413
+ duration: true,
414
+ diff: true,
415
+ showFullState: true,
416
+ })
417
+
418
+ // Создаем middleware: alertM (просто для примера)
419
+ const alertM = createPokemonAlertMiddleware()
420
+
421
+ return createDispatcher({
422
+ storage,
423
+ middlewares: [loggerMiddleware, alertM],
424
+ }, (storage, { createWatcher, createAction }) => ({
425
+ // watcher для отслеживания текущего ID
426
+ watchCurrentId: createWatcher({...}),
427
+ // Загрузка покемона по ID
428
+ loadPokemon: createAction<number, { id: number }>({...}),
429
+
430
+ loadPokemonRequest: createAction<number, { id: number }>({...}),
431
+ // Успешное получение данных
432
+ success: createAction<{ data?: Pokemon}, { data?: Pokemon }>({...}, {
433
+ // Функция мемоизации (пока не тестировал)
434
+ // memoize: (currentArgs: any[], previousArgs: any[], previousResult: any) => true,
435
+ // Веб-воркер для выполнения действия (пока не тестировал)
436
+ // worker: myWorker,
437
+ }),
438
+ failure: createAction<Error, { err: Error }>({...}),
439
+ next: createAction<void, { id: number }>({...}),
440
+ prev: createAction<void, { id: number }>({...}),
441
+ showAlert: createAction<AlertPayload, void>({...}),
442
+ }))
443
+ // Альтернативный вариант добавления:
444
+ // .use(logger)
445
+ // .use(alertM)
446
+ }
447
+
448
+ // Экспортируем тип диспетчера
449
+ export type PokemonDispatcher = ReturnType<typeof createPokemonDispatcher>
450
+ ```
451
+
452
+ Пример создания Эффекта:
453
+ ```typescript
454
+ import { EMPTY, from, mapTo, of, tap } from 'rxjs'
455
+ import { catchError, map, switchMap } from 'rxjs/operators'
456
+
457
+ import {
458
+ ofType, // Слушает 1 событие
459
+ ofTypes, // Слушает несколько событий
460
+ createEffect, // Функция создания эффекта
461
+ combineEffects, // Объединяет несколько эффектов в один
462
+ selectorMap, // Выбор частей состояния с помощью селекторов
463
+ validateMap // Оператор для удобной работы с запросом
464
+ } from 'synapse-storage/reactive'
465
+ import { pokemonEndpoints } from '../api.md'
466
+ import { AppConfig } from '../app.config'
467
+ import { PokemonDispatcher } from '../pokemon.dispatcher'
468
+ import { Pokemon, PokemonState } from '../types'
469
+
470
+ // Определяем типы для наших эффектов
471
+ type PokemonDispatcherType = { pokemonDispatcher: PokemonDispatcher }
472
+ type PokemonApiType = { pokemonApi: typeof pokemonEndpoints }
473
+
474
+ // Эффект для навигации
475
+ export const navigationEffect = createEffect<
476
+ PokemonState,
477
+ PokemonDispatcherType,
478
+ PokemonApiType,
479
+ AppConfig,
480
+ any //ExternalStorages
481
+ >((action$, state$, externalStorages, { pokemonDispatcher }, _, config) =>
482
+ action$.pipe(
483
+ ofTypes([pokemonDispatcher.dispatch.next, pokemonDispatcher.dispatch.prev]),
484
+ switchMap((action) => {
485
+ const { id } = action.payload
486
+ return of(() => pokemonDispatcher.dispatch.loadPokemon(id))
487
+ }),
488
+ ),
489
+ )
490
+
491
+ // Эффект для отслеживания изменений ID
492
+ export const watchIdEffect = createEffect<
493
+ PokemonState,
494
+ PokemonDispatcherType,
495
+ PokemonApiType,
496
+ AppConfig,
497
+ any //ExternalStorages
498
+ >((action$, state$, externalStorages, { pokemonDispatcher }) =>
499
+ action$.pipe(
500
+ ofType(pokemonDispatcher.watchers.watchCurrentId),
501
+ selectorMap(
502
+ state$,
503
+ //... selectors
504
+ ),
505
+ // tap(([action, [loading, currentId]]) => {...}),
506
+ mapTo(null),
507
+ ),
508
+ )
509
+
510
+ // Эффект для загрузки данных покемона
511
+ export const loadPokemonEffect = createEffect<
512
+ PokemonState,
513
+ PokemonDispatcherType,
514
+ PokemonApiType,
515
+ AppConfig,
516
+ any //ExternalStorages
517
+ >((
518
+ action$, // Поток событий
519
+ state$, // Поток состояния
520
+ externalStorages, // Потоки внешних хранилищ
521
+ { pokemonDispatcher }, // Диспетчеры которые мы передали
522
+ { pokemonApi }, // различные API которые мы передали
523
+ config // Конфигурация, которую мы передали
524
+ ) =>
525
+ action$.pipe(
526
+ // Я использую отдельный action loadPokemon который уведомляет о намерении сделать запрос
527
+ // Для того, чтобы не устанавливать loading сразу
528
+ ofType(pokemonDispatcher.dispatch.loadPokemon),
529
+ selectorMap(state$, (state) => state.currentId), // Получаем данные из текущего хранилища
530
+ selectorMap(externalStorages.someExternalStorage, (state) => state.someValue1), // Получаем данные из внешнего хранилища
531
+ validateMap({
532
+ apiCall: ([action, [currentId], [someValue1]]) => {
533
+ const { id } = action.payload
534
+
535
+ return from(
536
+ // Использую waitWithCallbacks чтобы иметь доступ к методу loading
537
+ pokemonApi.fetchPokemonById.request({ id }).waitWithCallbacks({
538
+ // Вызывается только тогда, когда запрос реально отправляется, а не берется из кэша
539
+ loading: (request) => {
540
+ // Именно в в этот момент установится loading и другая необходимая логика
541
+ pokemonDispatcher.dispatch.loadPokemonRequest(id)
542
+ },
543
+ // Можно использовать так:
544
+ // success: (data, request) => {
545
+ // console.log('SUCCESS', request)
546
+ // pokemonDispatcher.dispatch.success({ data })
547
+ // },
548
+ // error: (error, request) => {
549
+ // console.log('ERROR', error, request)
550
+ // pokemonDispatcher.dispatch.failure(error!)
551
+ // },
552
+ }),
553
+ // Можно более стандартным способом:
554
+ ).pipe(
555
+ switchMap(({ data }) => {
556
+ return of(pokemonDispatcher.dispatch.success({ data }))
557
+ }),
558
+ catchError((err) => of(pokemonDispatcher.dispatch.failure(err))),
559
+ )
560
+ },
561
+ }),
562
+ ),
563
+ )
564
+
565
+ // Объединяем все эффекты в один и экспортируем
566
+ export const pokemonEffects = combineEffects(
567
+ navigationEffect,
568
+ watchIdEffect,
569
+ loadPokemonEffect
570
+ )
571
+ ```
572
+ ---
573
+ ## Пример организации кода и использования утилиты createSynapse
574
+
575
+ Предлагаемая структура файлов
576
+
577
+ ```md
578
+ 📦some-directory
579
+ └── 📂synapses
580
+ │ └── 📂core
581
+ │ │ ├── 📄core.dispatcher.ts
582
+ │ │ ├── 📄core.synapse.ts
583
+ │ │ └── ...
584
+ │ └── 📂user-info
585
+ │ │ ├── 📄user-info.context.tsx
586
+ │ │ ├── 📄user-info.dispatcher.ts
587
+ │ │ ├── 📄user-info.effects.ts
588
+ │ │ ├── 📄user-info.selectors.ts
589
+ │ │ ├── 📄user-info.store.ts
590
+ │ │ └── 📄user-info.synapse.ts
591
+ │ └──...
592
+
593
+ └── 📄indexdb.config.ts
594
+ ```
595
+
596
+ ```typescript
597
+ // user-info.store.ts
598
+ // === СОЗДАНИЕ ХРАНИЛИЩА НУЖНОГОТИПА ===
599
+ export async function createUserInfoStorage() {
600
+ return new MemoryStorage<AboutUserUserInfo>({
601
+ name: 'user-info',
602
+ initialState: {
603
+ userInfoInit: undefined,
604
+ isChangeActive: false,
605
+ fieldsInit: {},
606
+ fields: {},
607
+ },
608
+ }).initialize()
609
+ }
610
+ ```
611
+
612
+ ```typescript
613
+ // user-info.dispatcher.ts
614
+ // === СОЗДАНИЕ ДИСПЕТЧЕРА ===
615
+
616
+ import { IStorage } from 'synapse-storage/core'
617
+ import { createDispatcher, loggerDispatcherMiddleware } from 'synapse-storage/reactive'
618
+
619
+ export function createUserInfoDispatcher(store: IStorage<AboutUserUserInfo>) {
620
+ const loggerMiddleware = loggerDispatcherMiddleware({...})
621
+
622
+ return createDispatcher({ storage: store }, (storage, { createAction, createWatcher }) => ({
623
+ setCurrentUserProfile: createAction<UserProfileInfo, UserProfileInfo>({
624
+ type: 'setCurrentUserProfile',
625
+ // meta: ,
626
+ // action: async () => {...}),
627
+ }),
628
+
629
+ setActiveChange: createAction<void, void>({
630
+ type: 'setActiveChange',
631
+ // meta: ,
632
+ // action: async () => {...}),
633
+ })
634
+ // Другие диспетчеры ...
635
+ })).use(loggerMiddleware)
636
+ }
637
+
638
+ export type UserInfoDispatcher = ReturnType<typeof createUserInfoDispatcher>
639
+ ```
640
+
641
+ ```typescript
642
+ // user-info.dispatcher.ts
643
+ // === СОЗДАНИЕ СЕЛЕКТОРОВ ===
644
+ import { ISelectorModule } from 'synapse-storage/core'
645
+
646
+ export const createUserInfoSelectors = (selectorModule: ISelectorModule<AboutUserUserInfo>) => {
647
+ const currentUserProfile = selectorModule.createSelector((s) => s.userInfoInit)
648
+ const fieldsInit = selectorModule.createSelector((s) => s.fieldsInit)
649
+
650
+ const isChangeActive = selectorModule.createSelector((s) => s.isChangeActive)
651
+
652
+ const fields = selectorModule.createSelector((s) => s.fields)
653
+ // Для React
654
+ // Комопнент будет ререндериться всегда, когда меняется возвращаемое селектором значение
655
+ // Для уменьшения ререндеров советую создавать точечные селекторы
656
+ // Если для отображения information у вас отдельный компонент - лучше создать отдельный для него селектор
657
+ const fieldInformation = selectorModule.createSelector((s) => s.fields.information)
658
+ const fieldPosition = selectorModule.createSelector((s) => s.fields.position)
659
+ //...
660
+
661
+ return ({
662
+ currentUserProfile,
663
+ isChangeActive,
664
+ //...
665
+ })
666
+ }
667
+ ```
668
+
669
+ ```typescript
670
+ // user-info.effects.ts
671
+ // === СОЗДАНИЕ ЭФФЕКТОВ ===
672
+ import { EMPTY, from, of } from 'rxjs'
673
+ import { catchError, map } from 'rxjs/operators'
674
+ import { combineEffects, createEffect, ofType, validateMap } from 'synapse-storage/reactive'
675
+
676
+ type CurrentDispatchers = {
677
+ userInfoDispatcher: UserInfoDispatcher
678
+ coreIdbDispatcher: CoreDispatcher
679
+ };
680
+ type CurrentApis = {
681
+ userInfoAPi: typeof userInfoEndpoints
682
+ };
683
+
684
+ /**
685
+ * Добавляем полученный профиль пользователя в текущий СТор
686
+ */
687
+ const loadUserInfoById = createEffect<
688
+ AboutUserUserInfo,
689
+ CurrentDispatchers,
690
+ CurrentApis,
691
+ any
692
+ >((action$, state$, { userInfoDispatcher, coreIdbDispatcher }) => action$.pipe(
693
+ // Подписываемся на изменения в стороннем Synapse
694
+ ofType(coreIdbDispatcher.watchers.watchCurrentUserProfile),
695
+ map((s) => {
696
+ if (!s.payload) return EMPTY
697
+ // Берем данные из стороннего Synapse и кладем в текущий
698
+ return userInfoDispatcher.dispatch.setCurrentUserProfile(s.payload)
699
+ }),
700
+ ))
701
+
702
+ const updateUserProfile = createEffect<
703
+ AboutUserUserInfo,
704
+ CurrentDispatchers,
705
+ CurrentApis,
706
+ any
707
+ >((action$, state$, { userInfoDispatcher }, { userInfoAPi }) => action$.pipe(
708
+ ofType(userInfoDispatcher.dispatch.submit),
709
+ validateMap({
710
+ // Валидация перед запросом
711
+ validator: (action) => ({
712
+ skipAction: userInfoDispatcher.dispatch.reset(),
713
+ conditions: [Boolean(action.payload)]
714
+ }),
715
+ apiCall: (action) => {
716
+ return from(
717
+ userInfoAPi.getUserById.request({ user_id: 1 }).waitWithCallbacks({
718
+ // Вызывается только тогда, когда запрос реально отправляется, а не берется из кэша
719
+ loading: (request) => {
720
+ // Именно в в этот момент установится loading и другая необходимая логика
721
+ // userInfoDispatcher.dispatch.request(id)
722
+ },
723
+ // Можно использовать так:
724
+ success: (data, request) => {
725
+ // userInfoDispatcher.dispatch.success({ data })
726
+ },
727
+ error: (error, request) => {
728
+ // userInfoDispatcher.dispatch.failure(error!)
729
+ },
730
+ }),
731
+ )
732
+ },
733
+ }),
734
+ ))
735
+
736
+ export const userInfoEffects = combineEffects(
737
+ loadUserInfoById,
738
+ updateUserProfile,
739
+ )
740
+
741
+ ```
742
+
743
+ ```typescript
744
+ // user-info.synapse.ts
745
+ // === СОЗДАНИЕ Synapse ===
746
+ import { createSynapse } from 'synapse-storage/utils'
747
+ import { createUserInfoDispatcher } from './user-info.dispatcher'
748
+ import { userInfoEffects } from './user-info.effects'
749
+ import { createUserInfoSelectors } from './user-info.selectors'
750
+ import { createUserInfoStorage } from './user-info.store'
751
+ import { userInfoEndpoints } from '../../api/user-info.api'
752
+ import { coreSynapseIDB } from '../core/core.synapse'
753
+
754
+ export const userInfoSynapse = await createSynapse({
755
+ // Передаем хранилище
756
+ // Это может быть
757
+ // 1 - Функция, которая фозвращает готовое ранилище
758
+ createStorageFn: createUserInfoStorage,
759
+ // 2 - Класс для создания хранилища (initialize() убдет вызван внутри)
760
+ // storage: new MemoryStorage<AboutUserUserInfo>({
761
+ // name: 'user-info',
762
+ // initialState: {
763
+ // userInfoInit: undefined,
764
+ // isChangeActive: false,
765
+ // fieldsInit: {},
766
+ // fields: {},
767
+ // },
768
+ // }),
769
+ // Функция создания диспетчеров (Опционально)
770
+ createDispatcherFn: createUserInfoDispatcher,
771
+ // Функция создания селекторов (Опционально)
772
+ createSelectorsFn: createUserInfoSelectors,
773
+ // Конфигурация для эффектов (Опционально)
774
+ createEffectConfig: (userInfoDispatcher) => ({
775
+ // Диспетчеры для эффектов
776
+ dispatchers: {
777
+ userInfoDispatcher, // Текущий, для управления соственных хранилищем
778
+ coreIdbDispatcher: coreSynapseIDB.dispatcher, // Внешний, для взаиможействия с внешними хранилищами
779
+ //...
780
+ },
781
+ // Дополнительное АПИ по вашему усмотрения (у меня это API Clients)
782
+ api: {
783
+ userInfoAPi: userInfoEndpoints,
784
+ },
785
+ }),
786
+ // Эффекты которые будут запущены для этого synapse
787
+ effects: [userInfoEffects],
788
+ })
789
+ ```
790
+
791
+ ```tsx
792
+ // user-info.context.tsx
793
+ // === СОЗДАНИЕ React Context ===
794
+ import { createSynapseCtx } from 'synapse-storage/react'
795
+ import { userInfoSynapse } from './user-info.synapse'
796
+
797
+ // Получаем все необходимые инструменты для работы в компонете
798
+ export const {
799
+ contextSynapse: useUserInfoContextSynapse,
800
+ useSynapseActions: useUserInfoSynapseActions,
801
+ useSynapseSelectors: useUserInfoSynapseSelectors,
802
+ useSynapseState$: useUserInfoSynapseState$,
803
+ useSynapseStorage: useUserInfoSynapseStorage,
804
+ cleanupSynapse: useUserInfoCleanupSynapse,
805
+ } = createSynapseCtx(userInfoSynapse, {
806
+ loadingComponent: <div>loading</div>, // Компонент, который будет отображаться пока выполняется асинхронная загрузка Synapse
807
+ })
808
+ ```
809
+
810
+ Вы можете связывать Synapse между собой
811
+
812
+ ```typescript
813
+ // core.synapse.ts
814
+ export const coreSynapseIDB = await createSynapse({
815
+ storage: CORE,
816
+ createSelectorsFn: (selectorModule) => {
817
+ const currentUserProfile = selectorModule.createSelector((s) => s.currentUserProfile, { name: 'currentUserProfile' })
818
+
819
+ return ({
820
+ currentUserProfile,
821
+ })
822
+ },
823
+ createDispatcherFn: createCoreDispatcher,
824
+ })
825
+
826
+ // user-info.synapse.ts
827
+ import { createSynapse } from 'synapse-storage/utils'
828
+ import { coreSynapseIDB } from '../core/core.synapse'
829
+
830
+ export const userInfoSynapse = await createSynapse({
831
+ // Передаем внешие селекторы
832
+ externalSelectors: {
833
+ coreSelectors: coreSynapseIDB.selectors
834
+ },
835
+ // TypeScript подскажет интерфейс
836
+ // createSelectorsFn: (currentSelectorModule, { coreSelectors }) => {...},
837
+ })
838
+ ```
839
+
840
+ Таким образом вы можете резделить функционал на слои
841
+
842
+
843
+ ---
844
+
845
+
846
+ Полноценный рабочий пример можно найти в папке src/examples/pokemons
847
+ Там показано еще больше возможностей которые дает этот подход.
848
+
849
+ ## Middleware и плагины
850
+
851
+ Synapse предоставляет две системы расширения функциональности: middleware и плагины. Они выполняют разные роли и имеют разную область применения.
852
+
853
+ ### Middleware
854
+
855
+ Middleware в Synapse работают по принципу "цепочки обработчиков" и позволяют перехватывать любые операции хранилища. Каждое middleware может модифицировать действия до и после их обработки базовым хранилищем.
856
+
857
+ ```typescript
858
+ const storage = await new MemoryStorage({
859
+ name: 'appState',
860
+ middlewares: (getDefaultMiddleware) => {
861
+ const { shallowCompare, batching } = getDefaultMiddleware();
862
+ return [
863
+ // Синхронизация между вкладками браузера
864
+ broadcastMiddleware({
865
+ storageName: 'appState',
866
+ storageType: 'memory',
867
+ }),
868
+ // Предотвращает ненужные обновления при одинаковых значениях
869
+ shallowCompare(),
870
+ // Группирует операции для оптимизации
871
+ batching({
872
+ batchSize: 10, // Максимальное количество операций в батче
873
+ batchDelay: 300, // Задержка перед обработкой батча (мс)
874
+ }),
875
+ ];
876
+ },
877
+ }).initialize();
878
+ ```
879
+
880
+ #### Порядок выполнения middleware
881
+
882
+ Middleware выполняются в порядке их объявления в массиве:
883
+ 1. Действие проходит через все middleware сверху вниз
884
+ 2. Затем выполняется базовая операция хранилища
885
+ 3. Результат проходит через middleware снизу вверх
886
+
887
+ ```
888
+ Action → BroadcastMiddleware → ShallowCompare → Batching → Base Operation
889
+ Result ← BroadcastMiddleware ← ShallowCompare ← Batching ← Base Operation
890
+ ```
891
+
892
+ #### Создание пользовательского middleware
893
+
894
+ ```typescript
895
+ import { Middleware } from 'synapse-storage/core';
896
+
897
+ const loggingMiddleware = (): Middleware => ({
898
+ // Уникальное имя middleware
899
+ name: 'logging',
900
+
901
+ // Инициализация при добавлении middleware к хранилищу
902
+ setup: (api) => {
903
+ console.log('Logging middleware initialized');
904
+ },
905
+
906
+ // Основная логика перехвата и обработки действий
907
+ reducer: (api) => (next) => async (action) => {
908
+ console.log('Before action:', action);
909
+
910
+ try {
911
+ // Вызов следующего middleware в цепочке
912
+ const result = await next(action);
913
+
914
+ console.log('After action:', {
915
+ action,
916
+ result,
917
+ });
918
+
919
+ return result;
920
+ } catch (error) {
921
+ console.error('Action error:', error);
922
+ throw error;
923
+ }
924
+ },
925
+
926
+ // Очистка ресурсов при уничтожении хранилища
927
+ cleanup: () => {
928
+ console.log('Logging middleware cleanup');
929
+ }
930
+ });
931
+ ```
932
+
933
+ ### Плагины
934
+
935
+ Плагины в Synapse представляют собой систему обработчиков событий хранилища с определенным жизненным циклом. В отличие от middleware, они не формируют цепочку, а работают как независимые "наблюдатели" за операциями хранилища.
936
+
937
+ ```typescript
938
+ import { IStoragePlugin, StoragePluginModule } from 'synapse-storage/core';
939
+
940
+ // Создаем модуль плагинов
941
+ const plugins = new StoragePluginModule(
942
+ undefined, // Родительский модуль плагинов (опционально)
943
+ console, // Логгер
944
+ 'appStorage' // Имя хранилища
945
+ );
946
+
947
+ // Пример плагина валидации
948
+ class ValidationPlugin implements IStoragePlugin {
949
+ name = 'validation';
950
+ private validators = new Map();
951
+ private options: any;
952
+
953
+ constructor(options = {}) {
954
+ this.options = options;
955
+ }
956
+
957
+ // Добавление правила валидации для ключа
958
+ addValidator(key, validator) {
959
+ this.validators.set(key, validator);
960
+ return this;
961
+ }
962
+
963
+ // Вызывается перед сохранением значения
964
+ async onBeforeSet(value, context) {
965
+ const { key } = context.metadata || {};
966
+
967
+ if (key && this.validators.has(key)) {
968
+ const validator = this.validators.get(key);
969
+ const result = validator(value);
970
+
971
+ if (!result.valid) {
972
+ if (this.options.throwOnInvalid) {
973
+ throw new Error(`Validation failed for ${key}: ${result.message}`);
974
+ }
975
+
976
+ this.options.onValidationError?.(key, value, result.message);
977
+ }
978
+ }
979
+
980
+ return value;
981
+ }
982
+
983
+ // Инициализация плагина
984
+ async initialize() {
985
+ console.log('Validation plugin initialized');
986
+ }
987
+
988
+ // Очистка ресурсов
989
+ async destroy() {
990
+ this.validators.clear();
991
+ }
992
+ }
993
+
994
+ // Добавление плагинов в модуль
995
+ await plugins.add(new ValidationPlugin({
996
+ throwOnInvalid: true,
997
+ onValidationError: (key, value, message) => {
998
+ console.error(`Validation error: ${message}`);
999
+ }
1000
+ }));
1001
+
1002
+ // Создание хранилища с плагинами
1003
+ const storage = await new MemoryStorage(
1004
+ { name: 'app-storage' },
1005
+ plugins // Передаем модуль плагинов
1006
+ ).initialize();
1007
+ ```
1008
+
1009
+ #### Жизненный цикл плагинов
1010
+
1011
+ Плагины имеют следующие методы жизненного цикла:
1012
+
1013
+ 1. **Инициализация**: `initialize()` - вызывается при добавлении плагина в хранилище
1014
+ 2. **Операции хранилища**:
1015
+ - `onBeforeSet` / `onAfterSet` - до/после сохранения значения
1016
+ - `onBeforeGet` / `onAfterGet` - до/после получения значения
1017
+ - `onBeforeDelete` / `onAfterDelete` - до/после удаления значения
1018
+ - `onClear` - при очистке хранилища
1019
+ 3. **Уничтожение**: `destroy()` - вызывается при удалении плагина или уничтожении хранилища
1020
+
1021
+ #### Когда использовать middleware, а когда плагины?
1022
+
1023
+ - **Middleware** лучше использовать для:
1024
+ - Перехвата всех операций хранилища в одном месте
1025
+ - Изменения поведения базовых операций хранилища
1026
+ - Оптимизации (батчинг, дедупликация)
1027
+ - Синхронизации между хранилищами/вкладками
1028
+
1029
+ - **Плагины** лучше использовать для:
1030
+ - Обработки конкретных событий хранилища
1031
+ - Валидации данных
1032
+ - Логирования операций
1033
+ - Реализации бизнес-логики, связанной с хранением данных
1034
+ - Интеграции с внешними сервисами
1035
+
1036
+ ## Лицензия
1037
+
1038
+ MIT