synapse-storage 3.0.19 → 4.0.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.
- package/README.md +661 -104
- package/dist/_utils/chunk.util.d.ts +8 -0
- package/dist/_utils/chunk.util.d.ts.map +1 -0
- package/dist/_utils/chunk.util.js +21 -0
- package/dist/_utils/chunk.util.js.map +1 -0
- package/dist/_utils/deepMerge.util.d.ts +2 -0
- package/dist/_utils/deepMerge.util.d.ts.map +1 -0
- package/dist/_utils/deepMerge.util.js +19 -0
- package/dist/_utils/deepMerge.util.js.map +1 -0
- package/dist/_utils/error-handling.util.d.ts +50 -0
- package/dist/_utils/error-handling.util.d.ts.map +1 -0
- package/dist/_utils/error-handling.util.js +67 -0
- package/dist/_utils/error-handling.util.js.map +1 -0
- package/dist/_utils/flatMap.util.d.ts +10 -0
- package/dist/_utils/flatMap.util.d.ts.map +1 -0
- package/dist/_utils/flatMap.util.js +23 -0
- package/dist/_utils/flatMap.util.js.map +1 -0
- package/dist/_utils/index.d.ts +6 -0
- package/dist/_utils/index.d.ts.map +1 -0
- package/dist/_utils/index.js +13 -0
- package/dist/_utils/index.js.map +1 -0
- package/dist/_utils/logger-console.util.d.ts +9 -0
- package/dist/_utils/logger-console.util.d.ts.map +1 -0
- package/dist/_utils/logger-console.util.js +14 -0
- package/dist/_utils/logger-console.util.js.map +1 -0
- package/dist/api/api.module.d.ts +46 -0
- package/dist/api/api.module.d.ts.map +1 -0
- package/dist/api/api.module.js +121 -0
- package/dist/api/api.module.js.map +1 -0
- package/dist/api/components/endpoint.d.ts +57 -0
- package/dist/api/components/endpoint.d.ts.map +1 -0
- package/dist/api/components/endpoint.js +385 -0
- package/dist/api/components/endpoint.js.map +1 -0
- package/dist/api/components/query-storage.d.ts +100 -0
- package/dist/api/components/query-storage.d.ts.map +1 -0
- package/dist/api/components/query-storage.js +293 -0
- package/dist/api/components/query-storage.js.map +1 -0
- package/dist/api/example.d.ts +83 -0
- package/dist/api/example.d.ts.map +1 -0
- package/dist/api/example.js +90 -0
- package/dist/api/example.js.map +1 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types/api.interface.d.ts +126 -0
- package/dist/api/types/api.interface.d.ts.map +1 -0
- package/dist/api/types/api.interface.js +15 -0
- package/dist/api/types/api.interface.js.map +1 -0
- package/dist/api/types/endpoint.interface.d.ts +118 -0
- package/dist/api/types/endpoint.interface.d.ts.map +1 -0
- package/dist/api/types/endpoint.interface.js +6 -0
- package/dist/api/types/endpoint.interface.js.map +1 -0
- package/dist/api/types/query.interface.d.ts +85 -0
- package/dist/api/types/query.interface.d.ts.map +1 -0
- package/dist/api/types/query.interface.js +6 -0
- package/dist/api/types/query.interface.js.map +1 -0
- package/dist/api/utils/api-helpers.d.ts +22 -0
- package/dist/api/utils/api-helpers.d.ts.map +1 -0
- package/dist/api/utils/api-helpers.js +44 -0
- package/dist/api/utils/api-helpers.js.map +1 -0
- package/dist/api/utils/create-header-context.d.ts +10 -0
- package/dist/api/utils/create-header-context.d.ts.map +1 -0
- package/dist/api/utils/create-header-context.js +40 -0
- package/dist/api/utils/create-header-context.js.map +1 -0
- package/dist/api/utils/endpoint-headers.d.ts +23 -0
- package/dist/api/utils/endpoint-headers.d.ts.map +1 -0
- package/dist/api/utils/endpoint-headers.js +61 -0
- package/dist/api/utils/endpoint-headers.js.map +1 -0
- package/dist/api/utils/fetch-base-query.d.ts +9 -0
- package/dist/api/utils/fetch-base-query.d.ts.map +1 -0
- package/dist/api/utils/fetch-base-query.js +242 -0
- package/dist/api/utils/fetch-base-query.js.map +1 -0
- package/dist/api/utils/file-utils.d.ts +43 -0
- package/dist/api/utils/file-utils.d.ts.map +1 -0
- package/dist/api/utils/file-utils.js +102 -0
- package/dist/api/utils/file-utils.js.map +1 -0
- package/dist/api/utils/get-cacheable-headers.d.ts +8 -0
- package/dist/api/utils/get-cacheable-headers.d.ts.map +1 -0
- package/dist/api/utils/get-cacheable-headers.js +23 -0
- package/dist/api/utils/get-cacheable-headers.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/selector/index.d.ts +3 -0
- package/dist/core/selector/index.d.ts.map +1 -0
- package/dist/core/selector/index.js +5 -0
- package/dist/core/selector/index.js.map +1 -0
- package/dist/{selector.interface-CA5y-kD_.d.ts → core/selector/selector.interface.d.ts} +41 -8
- package/dist/core/selector/selector.interface.d.ts.map +1 -0
- package/dist/core/selector/selector.interface.js +7 -0
- package/dist/core/selector/selector.interface.js.map +1 -0
- package/dist/core/selector/selector.module.d.ts +36 -0
- package/dist/core/selector/selector.module.d.ts.map +1 -0
- package/dist/core/selector/selector.module.js +412 -0
- package/dist/core/selector/selector.module.js.map +1 -0
- package/dist/core/storage/adapters/async-base-storage.service.d.ts +49 -0
- package/dist/core/storage/adapters/async-base-storage.service.d.ts.map +1 -0
- package/dist/core/storage/adapters/async-base-storage.service.js +505 -0
- package/dist/core/storage/adapters/async-base-storage.service.js.map +1 -0
- package/dist/core/storage/adapters/indexed-DB.service.d.ts +89 -0
- package/dist/core/storage/adapters/indexed-DB.service.d.ts.map +1 -0
- package/dist/core/storage/adapters/indexed-DB.service.js +596 -0
- package/dist/core/storage/adapters/indexed-DB.service.js.map +1 -0
- package/dist/core/storage/adapters/local-storage.service.d.ts +23 -0
- package/dist/core/storage/adapters/local-storage.service.d.ts.map +1 -0
- package/dist/core/storage/adapters/local-storage.service.js +111 -0
- package/dist/core/storage/adapters/local-storage.service.js.map +1 -0
- package/dist/core/storage/adapters/memory-storage.service.d.ts +24 -0
- package/dist/core/storage/adapters/memory-storage.service.d.ts.map +1 -0
- package/dist/core/storage/adapters/memory-storage.service.js +110 -0
- package/dist/core/storage/adapters/memory-storage.service.js.map +1 -0
- package/dist/core/storage/adapters/path.utils.d.ts +5 -0
- package/dist/core/storage/adapters/path.utils.d.ts.map +1 -0
- package/dist/core/storage/adapters/path.utils.js +42 -0
- package/dist/core/storage/adapters/path.utils.js.map +1 -0
- package/dist/core/storage/adapters/storage-core.d.ts +61 -0
- package/dist/core/storage/adapters/storage-core.d.ts.map +1 -0
- package/dist/core/storage/adapters/storage-core.js +221 -0
- package/dist/core/storage/adapters/storage-core.js.map +1 -0
- package/dist/core/storage/adapters/sync-base-storage.service.d.ts +56 -0
- package/dist/core/storage/adapters/sync-base-storage.service.d.ts.map +1 -0
- package/dist/core/storage/adapters/sync-base-storage.service.js +481 -0
- package/dist/core/storage/adapters/sync-base-storage.service.js.map +1 -0
- package/dist/core/storage/index.d.ts +16 -0
- package/dist/core/storage/index.d.ts.map +1 -0
- package/dist/core/storage/index.js +38 -0
- package/dist/core/storage/index.js.map +1 -0
- package/dist/core/storage/middlewares/broadcast.middleware.d.ts +9 -0
- package/dist/core/storage/middlewares/broadcast.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/broadcast.middleware.js +197 -0
- package/dist/core/storage/middlewares/broadcast.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/index.d.ts +9 -0
- package/dist/core/storage/middlewares/index.d.ts.map +1 -0
- package/dist/core/storage/middlewares/index.js +17 -0
- package/dist/core/storage/middlewares/index.js.map +1 -0
- package/dist/core/storage/middlewares/storage-batching.middleware.d.ts +7 -0
- package/dist/core/storage/middlewares/storage-batching.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/storage-batching.middleware.js +108 -0
- package/dist/core/storage/middlewares/storage-batching.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts +7 -0
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js +43 -0
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts +9 -0
- package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/sync-broadcast.middleware.js +177 -0
- package/dist/core/storage/middlewares/sync-broadcast.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts +6 -0
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.js +56 -0
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts +7 -0
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts.map +1 -0
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js +39 -0
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js.map +1 -0
- package/dist/core/storage/modules/plugin/plugin.interface.d.ts +101 -0
- package/dist/core/storage/modules/plugin/plugin.interface.d.ts.map +1 -0
- package/dist/core/storage/modules/plugin/plugin.interface.js +8 -0
- package/dist/core/storage/modules/plugin/plugin.interface.js.map +1 -0
- package/dist/core/storage/modules/plugin/plugin.service.d.ts +49 -0
- package/dist/core/storage/modules/plugin/plugin.service.d.ts.map +1 -0
- package/dist/core/storage/modules/plugin/plugin.service.js +406 -0
- package/dist/core/storage/modules/plugin/plugin.service.js.map +1 -0
- package/dist/core/storage/modules/singleton/mixin.util.d.ts +6 -0
- package/dist/core/storage/modules/singleton/mixin.util.d.ts.map +1 -0
- package/dist/core/storage/modules/singleton/mixin.util.js +30 -0
- package/dist/core/storage/modules/singleton/mixin.util.js.map +1 -0
- package/dist/core/storage/modules/singleton/models.d.ts +143 -0
- package/dist/core/storage/modules/singleton/models.d.ts.map +1 -0
- package/dist/core/storage/modules/singleton/models.js +60 -0
- package/dist/core/storage/modules/singleton/models.js.map +1 -0
- package/dist/core/storage/modules/singleton/singleton.util.d.ts +36 -0
- package/dist/core/storage/modules/singleton/singleton.util.d.ts.map +1 -0
- package/dist/core/storage/modules/singleton/singleton.util.js +216 -0
- package/dist/core/storage/modules/singleton/singleton.util.js.map +1 -0
- package/dist/core/storage/storage.interface.d.ts +168 -0
- package/dist/core/storage/storage.interface.d.ts.map +1 -0
- package/dist/core/storage/storage.interface.js +23 -0
- package/dist/core/storage/storage.interface.js.map +1 -0
- package/dist/core/storage/utils/broadcast.util.d.ts +49 -0
- package/dist/core/storage/utils/broadcast.util.d.ts.map +1 -0
- package/dist/core/storage/utils/broadcast.util.js +141 -0
- package/dist/core/storage/utils/broadcast.util.js.map +1 -0
- package/dist/core/storage/utils/cache.util.d.ts +33 -0
- package/dist/core/storage/utils/cache.util.d.ts.map +1 -0
- package/dist/core/storage/utils/cache.util.js +54 -0
- package/dist/core/storage/utils/cache.util.js.map +1 -0
- package/dist/core/storage/utils/middleware-module.d.ts +94 -0
- package/dist/core/storage/utils/middleware-module.d.ts.map +1 -0
- package/dist/core/storage/utils/middleware-module.js +258 -0
- package/dist/core/storage/utils/middleware-module.js.map +1 -0
- package/dist/core/storage/utils/path-selector.util.d.ts +15 -0
- package/dist/core/storage/utils/path-selector.util.d.ts.map +1 -0
- package/dist/core/storage/utils/path-selector.util.js +58 -0
- package/dist/core/storage/utils/path-selector.util.js.map +1 -0
- package/dist/core/storage/utils/state-diff.util.d.ts +14 -0
- package/dist/core/storage/utils/state-diff.util.d.ts.map +1 -0
- package/dist/core/storage/utils/state-diff.util.js +88 -0
- package/dist/core/storage/utils/state-diff.util.js.map +1 -0
- package/dist/core/storage/utils/storage-factory.util.d.ts +21 -0
- package/dist/core/storage/utils/storage-factory.util.d.ts.map +1 -0
- package/dist/core/storage/utils/storage-factory.util.js +40 -0
- package/dist/core/storage/utils/storage-factory.util.js.map +1 -0
- package/dist/core/storage/utils/storage-key.d.ts +11 -0
- package/dist/core/storage/utils/storage-key.d.ts.map +1 -0
- package/dist/core/storage/utils/storage-key.js +24 -0
- package/dist/core/storage/utils/storage-key.js.map +1 -0
- package/dist/core/storage/utils/storage.utils.d.ts +17 -0
- package/dist/core/storage/utils/storage.utils.d.ts.map +1 -0
- package/dist/core/storage/utils/storage.utils.js +57 -0
- package/dist/core/storage/utils/storage.utils.js.map +1 -0
- package/dist/index.d.ts +10 -12
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -0
- package/dist/react/hooks/index.d.ts +5 -0
- package/dist/react/hooks/index.d.ts.map +1 -0
- package/dist/react/hooks/index.js +11 -0
- package/dist/react/hooks/index.js.map +1 -0
- package/dist/react/hooks/useCreateStorage.d.ts +39 -0
- package/dist/react/hooks/useCreateStorage.d.ts.map +1 -0
- package/dist/react/hooks/useCreateStorage.js +137 -0
- package/dist/react/hooks/useCreateStorage.js.map +1 -0
- package/dist/react/hooks/useSelector.d.ts +21 -0
- package/dist/react/hooks/useSelector.d.ts.map +1 -0
- package/dist/react/hooks/useSelector.js +56 -0
- package/dist/react/hooks/useSelector.js.map +1 -0
- package/dist/react/hooks/useStorage.d.ts +39 -0
- package/dist/react/hooks/useStorage.d.ts.map +1 -0
- package/dist/react/hooks/useStorage.js +78 -0
- package/dist/react/hooks/useStorage.js.map +1 -0
- package/dist/react/hooks/useStorageSubscribe.d.ts +16 -0
- package/dist/react/hooks/useStorageSubscribe.d.ts.map +1 -0
- package/dist/react/hooks/useStorageSubscribe.js +55 -0
- package/dist/react/hooks/useStorageSubscribe.js.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/utils/awaitSynapse.d.ts +34 -0
- package/dist/react/utils/awaitSynapse.d.ts.map +1 -0
- package/dist/react/utils/awaitSynapse.js +87 -0
- package/dist/react/utils/awaitSynapse.js.map +1 -0
- package/dist/react/utils/createSynapseCtx.d.ts +33 -0
- package/dist/react/utils/createSynapseCtx.d.ts.map +1 -0
- package/dist/react/utils/createSynapseCtx.js +139 -0
- package/dist/react/utils/createSynapseCtx.js.map +1 -0
- package/dist/react/utils/index.d.ts +3 -0
- package/dist/react/utils/index.d.ts.map +1 -0
- package/dist/react/utils/index.js +9 -0
- package/dist/react/utils/index.js.map +1 -0
- package/dist/reactive/dispatcher/dispatcher.module.d.ts +216 -0
- package/dist/reactive/dispatcher/dispatcher.module.d.ts.map +1 -0
- package/dist/reactive/dispatcher/dispatcher.module.js +384 -0
- package/dist/reactive/dispatcher/dispatcher.module.js.map +1 -0
- package/dist/reactive/dispatcher/index.d.ts +4 -0
- package/dist/reactive/dispatcher/index.d.ts.map +1 -0
- package/dist/reactive/dispatcher/index.js +9 -0
- package/dist/reactive/dispatcher/index.js.map +1 -0
- package/dist/reactive/dispatcher/middlewares/index.d.ts +2 -0
- package/dist/reactive/dispatcher/middlewares/index.d.ts.map +1 -0
- package/dist/reactive/dispatcher/middlewares/index.js +5 -0
- package/dist/reactive/dispatcher/middlewares/index.js.map +1 -0
- package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts +37 -0
- package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts.map +1 -0
- package/dist/reactive/dispatcher/middlewares/logger.middleware.js +188 -0
- package/dist/reactive/dispatcher/middlewares/logger.middleware.js.map +1 -0
- package/dist/reactive/dispatcher/standalone.d.ts +112 -0
- package/dist/reactive/dispatcher/standalone.d.ts.map +1 -0
- package/dist/reactive/dispatcher/standalone.js +142 -0
- package/dist/reactive/dispatcher/standalone.js.map +1 -0
- package/dist/reactive/effects/effects.module.d.ts +225 -0
- package/dist/reactive/effects/effects.module.d.ts.map +1 -0
- package/dist/reactive/effects/effects.module.js +356 -0
- package/dist/reactive/effects/effects.module.js.map +1 -0
- package/dist/reactive/effects/index.d.ts +4 -0
- package/dist/reactive/effects/index.d.ts.map +1 -0
- package/dist/reactive/effects/index.js +11 -0
- package/dist/reactive/effects/index.js.map +1 -0
- package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts +12 -0
- package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts.map +1 -0
- package/dist/reactive/effects/utils/chunkRequestConsistent.js +25 -0
- package/dist/reactive/effects/utils/chunkRequestConsistent.js.map +1 -0
- package/dist/reactive/effects/utils/chunkRequestParallel.d.ts +12 -0
- package/dist/reactive/effects/utils/chunkRequestParallel.d.ts.map +1 -0
- package/dist/reactive/effects/utils/chunkRequestParallel.js +22 -0
- package/dist/reactive/effects/utils/chunkRequestParallel.js.map +1 -0
- package/dist/reactive/effects/utils/fromRequest.d.ts +40 -0
- package/dist/reactive/effects/utils/fromRequest.d.ts.map +1 -0
- package/dist/reactive/effects/utils/fromRequest.js +64 -0
- package/dist/reactive/effects/utils/fromRequest.js.map +1 -0
- package/dist/reactive/effects/utils/index.d.ts +5 -0
- package/dist/reactive/effects/utils/index.d.ts.map +1 -0
- package/dist/reactive/effects/utils/index.js +11 -0
- package/dist/reactive/effects/utils/index.js.map +1 -0
- package/dist/reactive/effects/utils/toObservable.d.ts +23 -0
- package/dist/reactive/effects/utils/toObservable.d.ts.map +1 -0
- package/dist/reactive/effects/utils/toObservable.js +39 -0
- package/dist/reactive/effects/utils/toObservable.js.map +1 -0
- package/dist/reactive/index.d.ts +3 -0
- package/dist/reactive/index.d.ts.map +1 -0
- package/dist/reactive/index.js +7 -0
- package/dist/reactive/index.js.map +1 -0
- package/dist/utils/createEventBus.d.ts +87 -0
- package/dist/utils/createEventBus.d.ts.map +1 -0
- package/dist/utils/createEventBus.js +215 -0
- package/dist/utils/createEventBus.js.map +1 -0
- package/dist/utils/createSynapse/createSynapse.d.ts +9 -0
- package/dist/utils/createSynapse/createSynapse.d.ts.map +1 -0
- package/dist/utils/createSynapse/createSynapse.js +103 -0
- package/dist/utils/createSynapse/createSynapse.js.map +1 -0
- package/dist/utils/createSynapse/index.d.ts +3 -0
- package/dist/utils/createSynapse/index.d.ts.map +1 -0
- package/dist/utils/createSynapse/index.js +6 -0
- package/dist/utils/createSynapse/index.js.map +1 -0
- package/dist/utils/createSynapse/types.d.ts +93 -0
- package/dist/utils/createSynapse/types.d.ts.map +1 -0
- package/dist/utils/createSynapse/types.js +6 -0
- package/dist/utils/createSynapse/types.js.map +1 -0
- package/dist/utils/createSynapse/validate.d.ts +2 -0
- package/dist/utils/createSynapse/validate.d.ts.map +1 -0
- package/dist/utils/createSynapse/validate.js +76 -0
- package/dist/utils/createSynapse/validate.js.map +1 -0
- package/dist/utils/createSynapse/waitForDependencies.d.ts +3 -0
- package/dist/utils/createSynapse/waitForDependencies.d.ts.map +1 -0
- package/dist/utils/createSynapse/waitForDependencies.js +40 -0
- package/dist/utils/createSynapse/waitForDependencies.js.map +1 -0
- package/dist/utils/createSynapseAwaiter.d.ts +46 -0
- package/dist/utils/createSynapseAwaiter.d.ts.map +1 -0
- package/dist/utils/createSynapseAwaiter.js +102 -0
- package/dist/utils/createSynapseAwaiter.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +12 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +17 -21
- package/dist/api.d.ts +0 -365
- package/dist/api.js +0 -1
- package/dist/core.d.ts +0 -106
- package/dist/core.js +0 -1
- package/dist/createSynapse-vkfKjRob.d.ts +0 -97
- package/dist/dispatcher.module-BOsMHbD5.d.ts +0 -360
- package/dist/react.d.ts +0 -119
- package/dist/react.js +0 -1
- package/dist/reactive.d.ts +0 -35
- package/dist/reactive.js +0 -1
- package/dist/storage.interface-BA_ktyDz.d.ts +0 -591
- package/dist/utils.d.ts +0 -139
- package/dist/utils.js +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Synapse Storage
|
|
2
2
|
|
|
3
|
-
> **🇺🇸 English** | [
|
|
3
|
+
> **🇺🇸 English** | [📝 ChangeLog](./CHANGELOG.md)
|
|
4
4
|
|
|
5
5
|
State management toolkit + API client
|
|
6
6
|
|
|
@@ -9,36 +9,37 @@ State management toolkit + API client
|
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
[](https://rxjs.dev/)
|
|
11
11
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
12
|
+
## Key Features
|
|
13
|
+
|
|
14
|
+
- **Framework Agnostic** — works with any framework or standalone
|
|
15
|
+
- **Sync & Async Storage** — Memory/LocalStorage (fully synchronous) and IndexedDB (async) with type-safe separation
|
|
16
|
+
- **Selectors** — memoized computed values with dependency tracking (like Reselect)
|
|
17
|
+
- **Subscriptions** — subscribe to nested paths via selector functions
|
|
18
|
+
- **Immer-like Updates** — mutate state directly inside `update()` callbacks
|
|
19
|
+
- **API Client** — HTTP client with caching, tags, and invalidation (like RTK Query)
|
|
20
|
+
- **React Integration** — hooks built on `useSyncExternalStore` (Concurrent Mode safe)
|
|
21
|
+
- **RxJS Reactive** — Redux-Observable style effects, dispatchers, and watchers
|
|
22
|
+
- **Middleware & Plugins** — separate sync/async systems for extending storage behavior
|
|
23
|
+
- **Singleton Support** — shared storage instances across components with merge strategies
|
|
24
|
+
- **EventBus** — decoupled inter-module communication with wildcards and history
|
|
25
|
+
- **Cross-tab Sync** — BroadcastChannel middleware for multi-tab state synchronization
|
|
25
26
|
|
|
26
27
|
---
|
|
28
|
+
|
|
27
29
|
## Author
|
|
28
30
|
|
|
29
31
|
**Vladislav** — Senior Frontend Developer (React, TypeScript)
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
>
|
|
33
|
-
> [GitHub](https://github.com/Vlad92msk/) | [LinkedIn](https://www.linkedin.com/in/vlad-firsov/)
|
|
33
|
+
[GitHub](https://github.com/Vlad92msk/) | [LinkedIn](https://www.linkedin.com/in/vlad-firsov/)
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
*PS: Not recommended for production use yet as I develop this in my free time.
|
|
37
37
|
The library works in general, but I can provide guarantees only after full integration into my pet project - Social Network.
|
|
38
38
|
This won't happen before changing my current workplace and country of residence*
|
|
39
|
+
|
|
39
40
|
---
|
|
40
41
|
|
|
41
|
-
##
|
|
42
|
+
## Installation
|
|
42
43
|
|
|
43
44
|
```bash
|
|
44
45
|
npm install synapse-storage
|
|
@@ -48,144 +49,700 @@ npm install synapse-storage
|
|
|
48
49
|
# For reactive capabilities
|
|
49
50
|
npm install rxjs
|
|
50
51
|
|
|
51
|
-
# For React integration
|
|
52
|
+
# For React integration
|
|
52
53
|
npm install react react-dom
|
|
53
|
-
|
|
54
|
-
# All at once for full functionality
|
|
55
|
-
npm install synapse-storage rxjs react react-dom
|
|
56
54
|
```
|
|
57
55
|
|
|
58
56
|
| Module | Description | Dependencies |
|
|
59
57
|
|--------|-------------|--------------|
|
|
60
|
-
| `synapse-storage/core` |
|
|
61
|
-
| `synapse-storage/react` | React | React 18+ |
|
|
62
|
-
| `synapse-storage/reactive` |
|
|
63
|
-
| `synapse-storage/api` | HTTP client |
|
|
64
|
-
| `synapse-storage/utils` |
|
|
58
|
+
| `synapse-storage/core` | Storage, selectors, middleware, plugins | — |
|
|
59
|
+
| `synapse-storage/react` | React hooks and context utilities | React 18+ |
|
|
60
|
+
| `synapse-storage/reactive` | Dispatcher, effects, watchers | RxJS 7.8.2+ |
|
|
61
|
+
| `synapse-storage/api` | HTTP client with caching | — |
|
|
62
|
+
| `synapse-storage/utils` | createSynapse, EventBus, awaiter | — |
|
|
63
|
+
|
|
64
|
+
> Import only the modules you need — each works independently.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
### tsconfig.json
|
|
67
67
|
|
|
68
|
-
### tsconfig.json:
|
|
69
68
|
```json
|
|
70
69
|
{
|
|
71
70
|
"compilerOptions": {
|
|
72
71
|
"target": "ES2022",
|
|
73
|
-
"module": "ES2022",
|
|
72
|
+
"module": "ES2022",
|
|
74
73
|
"moduleResolution": "bundler"
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
```
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
---
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
- [🚀 Basic Usage](./docs/en/basic-usage.md)
|
|
83
|
-
- [🧮 Redux-style Computed Selectors](./docs/en/redux-selectors.md)
|
|
84
|
-
- [⚙️ Middlewares](./docs/en/middlewares.md)
|
|
85
|
-
- [🌐 API Client](./docs/en/api-client.md)
|
|
86
|
-
- ⚡ Reactive Approach
|
|
87
|
-
- [⚡ Creating Dispatcher](./docs/en/create-dispatcher.md)
|
|
88
|
-
- [⚡ Creating Effects](./docs/en/create-effects.md)
|
|
89
|
-
- [⚡ Creating Effects Module](./docs/en/create-effects-module.md)
|
|
90
|
-
- [🛠️ createSynapse Utility](./docs/en/create-synapse.md)
|
|
91
|
-
- [🔌 Creating Custom Plugins](./docs/en/custom-plugins.md)
|
|
92
|
-
- [⚙️ Creating Custom Middlewares](./docs/en/custom-middlewares.md)
|
|
93
|
-
- [📋 Additional](./docs/en/additional.md)
|
|
80
|
+
## Quick Start
|
|
94
81
|
|
|
95
|
-
|
|
82
|
+
```typescript
|
|
83
|
+
import { MemoryStorage } from 'synapse-storage/core'
|
|
96
84
|
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
const storage = new MemoryStorage({
|
|
86
|
+
name: 'counter',
|
|
87
|
+
initialState: { count: 0, user: { name: 'Anonymous' } },
|
|
88
|
+
})
|
|
89
|
+
await storage.initialize()
|
|
90
|
+
|
|
91
|
+
// Read
|
|
92
|
+
storage.getState() // { count: 0, user: { name: 'Anonymous' } }
|
|
93
|
+
storage.get('count') // 0
|
|
94
|
+
|
|
95
|
+
// Write
|
|
96
|
+
storage.set('count', 1)
|
|
97
|
+
|
|
98
|
+
// Immer-like update (multiple mutations = one notification)
|
|
99
|
+
storage.update((state) => {
|
|
100
|
+
state.count += 1
|
|
101
|
+
state.user.name = 'Alice'
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Subscribe to nested path
|
|
105
|
+
const unsub = storage.subscribe(
|
|
106
|
+
(s) => s.user.name,
|
|
107
|
+
(name) => console.log('Name changed:', name)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
// Reset to initialState
|
|
111
|
+
storage.reset()
|
|
112
|
+
```
|
|
99
113
|
|
|
100
114
|
---
|
|
101
115
|
|
|
102
|
-
##
|
|
116
|
+
## Storage Types
|
|
103
117
|
|
|
104
|
-
|
|
118
|
+
Synapse has two storage categories with **type-safe separation**:
|
|
105
119
|
|
|
106
|
-
|
|
107
|
-
|--------------|---------------------|---------|
|
|
108
|
-
| **State Management** | Redux + RTK (~45KB) | ✅ |
|
|
109
|
-
| **HTTP Client + Caching** | React Query (~39KB) | ✅|
|
|
110
|
-
| **Reactive Effects** | Redux-Observable (~25KB) | ✅|
|
|
111
|
-
| **Storage Adapters** | Custom solutions | ✅|
|
|
112
|
-
| **React Integration** | Custom hooks | ✅|
|
|
113
|
-
| **Computed Selectors** | Reselect (~5KB) | ✅|
|
|
114
|
-
| **Middleware System** | Custom implementation | ✅|
|
|
115
|
-
| **Plugin Architecture** | Custom implementation | ✅|
|
|
120
|
+
### Sync Storage (MemoryStorage, LocalStorage)
|
|
116
121
|
|
|
117
|
-
|
|
122
|
+
All operations are synchronous — `get()`, `set()`, `update()`, `getState()` return values directly.
|
|
118
123
|
|
|
119
124
|
```typescript
|
|
120
|
-
|
|
121
|
-
import { configureStore } from '@reduxjs/toolkit' // ~45KB
|
|
122
|
-
import { createApi } from '@reduxjs/toolkit/query' // included in RTK
|
|
123
|
-
import { QueryClient } from '@tanstack/react-query' // ~39KB
|
|
124
|
-
import { createEpicMiddleware } from 'redux-observable' // ~25KB
|
|
125
|
-
// Total: ~109KB + custom implementations
|
|
125
|
+
import { MemoryStorage, LocalStorage } from 'synapse-storage/core'
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
const memory = new MemoryStorage<State>({ name: 'app', initialState })
|
|
128
|
+
const local = new LocalStorage<State>({ name: 'app', initialState })
|
|
129
|
+
|
|
130
|
+
await memory.initialize()
|
|
131
|
+
const value = memory.get('key') // T — sync
|
|
130
132
|
```
|
|
131
133
|
|
|
132
|
-
###
|
|
134
|
+
### Async Storage (IndexedDBStorage)
|
|
135
|
+
|
|
136
|
+
Operations return Promises — persistent browser storage.
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
```typescript
|
|
139
|
+
import { IndexedDBStorage } from 'synapse-storage/core'
|
|
140
|
+
|
|
141
|
+
const idb = new IndexedDBStorage<State>({
|
|
142
|
+
name: 'app',
|
|
143
|
+
initialState,
|
|
144
|
+
options: { dbName: 'my_app_db' },
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
await idb.initialize()
|
|
148
|
+
const value = await idb.get('key') // Promise<T>
|
|
149
|
+
```
|
|
135
150
|
|
|
136
|
-
|
|
137
|
-
|-------------------|------------------------|------|---------------------------|
|
|
138
|
-
| **Basic state** | `synapse-storage/core` | ~42KB | vs Redux: 45KB |
|
|
139
|
-
| **+ HTTP client** | `+ /api` | +13KB | vs React Query: 39KB |
|
|
140
|
-
| **+ Reactive** | `+ /reactive` | +8KB | vs Redux-Observable: 25KB |
|
|
141
|
-
| **+ React hooks** | `+ /react` | +5KB | vs Custom hooks |
|
|
142
|
-
| **Full package** | all modules | ~171KB |vs 109KB stack + custom |
|
|
151
|
+
### getStateSync()
|
|
143
152
|
|
|
144
|
-
|
|
153
|
+
Available on **all** storage types — returns the cached state synchronously, even for IndexedDB:
|
|
145
154
|
|
|
146
|
-
|
|
155
|
+
```typescript
|
|
156
|
+
const state = storage.getStateSync() // always sync
|
|
157
|
+
```
|
|
147
158
|
|
|
148
|
-
|
|
159
|
+
### Static Factory Methods
|
|
149
160
|
|
|
150
|
-
|
|
161
|
+
Every storage class has a `.create()` static method:
|
|
151
162
|
|
|
152
163
|
```typescript
|
|
153
|
-
|
|
154
|
-
|
|
164
|
+
const storage = MemoryStorage.create<State>({ name: 'app', initialState })
|
|
165
|
+
const storage = LocalStorage.create<State>({ name: 'app', initialState })
|
|
166
|
+
const storage = IndexedDBStorage.create<State>({ name: 'app', initialState, options: {} })
|
|
167
|
+
```
|
|
155
168
|
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
### StorageFactory
|
|
170
|
+
|
|
171
|
+
Universal factory with type-safe overloads:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { StorageFactory } from 'synapse-storage/core'
|
|
175
|
+
|
|
176
|
+
// Typed factories
|
|
177
|
+
const mem = StorageFactory.createMemory<S>({ name: 'x', initialState })
|
|
178
|
+
const loc = StorageFactory.createLocal<S>({ name: 'x', initialState })
|
|
179
|
+
const idb = StorageFactory.createIndexedDB<S>({ name: 'x', initialState, options: {} })
|
|
180
|
+
|
|
181
|
+
// Universal — return type depends on `type`
|
|
182
|
+
const storage = StorageFactory.create<S>({
|
|
183
|
+
type: 'memory', // → ISyncStorage<S>
|
|
184
|
+
name: 'x',
|
|
185
|
+
initialState,
|
|
186
|
+
})
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Reading & Writing Data
|
|
192
|
+
|
|
193
|
+
### Reading
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
storage.get('key') // value by key
|
|
197
|
+
storage.getState() // full state
|
|
198
|
+
storage.getStateSync() // sync cache (all storage types)
|
|
199
|
+
storage.has('key') // boolean
|
|
200
|
+
storage.keys() // string[]
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Writing
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
storage.set('key', value) // set single key
|
|
207
|
+
storage.update((s) => { s.count++ }) // Immer-like mutations
|
|
208
|
+
storage.remove('key') // delete key
|
|
209
|
+
storage.reset() // restore initialState
|
|
210
|
+
storage.clear() // reset to {}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> For IndexedDB, all write operations return `Promise`.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Subscriptions
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Subscribe by key
|
|
221
|
+
const unsub = storage.subscribe('count', (newValue) => {
|
|
222
|
+
console.log('count:', newValue)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
// Subscribe by selector function (nested paths)
|
|
226
|
+
const unsub = storage.subscribe(
|
|
227
|
+
(state) => state.user.name,
|
|
228
|
+
(name) => console.log('name:', name)
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
// Subscribe to all changes
|
|
232
|
+
const unsub = storage.subscribeToAll((event) => {
|
|
233
|
+
// event.type: 'set' | 'update' | 'remove' | 'clear' | 'reset'
|
|
234
|
+
// event.key, event.changedPaths
|
|
235
|
+
})
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Selector System
|
|
241
|
+
|
|
242
|
+
Memoized computed values with dependency tracking:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { SelectorModule } from 'synapse-storage/core'
|
|
246
|
+
|
|
247
|
+
const sm = new SelectorModule(storage)
|
|
248
|
+
|
|
249
|
+
// Simple selector
|
|
250
|
+
const count = sm.createSelector((state) => state.count)
|
|
251
|
+
|
|
252
|
+
// With custom equality
|
|
253
|
+
const items = sm.createSelector(
|
|
254
|
+
(state) => state.items,
|
|
255
|
+
{ equals: (a, b) => JSON.stringify(a) === JSON.stringify(b) }
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
// Dependent selector (recalculates only when deps change)
|
|
259
|
+
const filtered = sm.createSelector(
|
|
260
|
+
[items, filter],
|
|
261
|
+
(itemsVal, filterVal) => itemsVal.filter(i => i.type === filterVal)
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
// Usage
|
|
265
|
+
const value = filtered.select()
|
|
266
|
+
const unsub = filtered.subscribe({ notify: (value) => console.log(value) })
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Middleware System
|
|
272
|
+
|
|
273
|
+
Separate sync and async middleware for each storage type:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const storage = new MemoryStorage<State>({
|
|
277
|
+
name: 'store',
|
|
278
|
+
initialState,
|
|
279
|
+
middlewares: (getDefault) => [
|
|
280
|
+
// Batch rapid writes
|
|
281
|
+
getDefault().batching({ batchSize: 5, batchDelay: 100 }),
|
|
282
|
+
|
|
283
|
+
// Skip updates if value unchanged
|
|
284
|
+
getDefault().shallowCompare(),
|
|
285
|
+
],
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Cross-tab Synchronization
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { syncBroadcastMiddleware } from 'synapse-storage/core'
|
|
293
|
+
|
|
294
|
+
const storage = new MemoryStorage<State>({
|
|
295
|
+
name: 'store',
|
|
296
|
+
initialState,
|
|
297
|
+
middlewares: () => [
|
|
298
|
+
syncBroadcastMiddleware({ storageName: 'store', storageType: 'memory' }),
|
|
299
|
+
],
|
|
300
|
+
})
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Plugin System
|
|
306
|
+
|
|
307
|
+
Lifecycle hooks for intercepting storage operations:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import { ISyncStoragePlugin, SyncStoragePluginModule } from 'synapse-storage/core'
|
|
311
|
+
|
|
312
|
+
class TimestampPlugin implements ISyncStoragePlugin {
|
|
313
|
+
name = 'timestamp'
|
|
314
|
+
|
|
315
|
+
async initialize() {}
|
|
316
|
+
async destroy() {}
|
|
317
|
+
|
|
318
|
+
onBeforeSet<T>(value: T, context): T { return value }
|
|
319
|
+
onAfterSet<T>(key, value: T, ctx): T { return value }
|
|
320
|
+
onBeforeGet(key, ctx) { return key }
|
|
321
|
+
onAfterGet<T>(key, value: T | undefined, ctx) { return value }
|
|
322
|
+
onBeforeDelete(key, ctx): boolean { return true } // false = block
|
|
323
|
+
onAfterDelete(key, ctx) {}
|
|
324
|
+
onClear(ctx) {}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const plugins = new SyncStoragePluginModule(undefined, undefined, 'store')
|
|
328
|
+
await plugins.add(new TimestampPlugin())
|
|
329
|
+
|
|
330
|
+
const storage = new MemoryStorage<State>(
|
|
331
|
+
{ name: 'store', initialState },
|
|
332
|
+
plugins
|
|
333
|
+
)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
> For IndexedDB, use `IAsyncStoragePlugin` and `AsyncStoragePluginModule`.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## React Integration
|
|
341
|
+
|
|
342
|
+
Hooks are built on `useSyncExternalStore` — safe in Concurrent Mode, no tearing.
|
|
343
|
+
|
|
344
|
+
### useCreateStorage
|
|
345
|
+
|
|
346
|
+
Returns a **discriminated union**: when `isReady: true`, `storage` is guaranteed non-null.
|
|
158
347
|
|
|
159
|
-
|
|
160
|
-
import {
|
|
348
|
+
```tsx
|
|
349
|
+
import { useCreateStorage } from 'synapse-storage/react'
|
|
161
350
|
|
|
162
|
-
|
|
351
|
+
function App() {
|
|
352
|
+
const { storage, isReady } = useCreateStorage<State>({
|
|
353
|
+
type: 'memory', // 'memory' | 'localStorage' → ISyncStorage
|
|
354
|
+
name: 'app', // 'indexedDB' → IAsyncStorage
|
|
355
|
+
initialState: { count: 0 },
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
if (!isReady) return <div>Loading...</div>
|
|
359
|
+
// storage is ISyncStorage<State> here (not null)
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### useStorageSubscribe
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
import { useStorageSubscribe } from 'synapse-storage/react'
|
|
367
|
+
|
|
368
|
+
function Counter() {
|
|
369
|
+
const count = useStorageSubscribe(storage, (s) => s.count)
|
|
370
|
+
const summary = useStorageSubscribe(storage, (s) => `Total: ${s.count}`)
|
|
371
|
+
return <div>{count} — {summary}</div>
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### useSelector
|
|
376
|
+
|
|
377
|
+
```tsx
|
|
163
378
|
import { useSelector } from 'synapse-storage/react'
|
|
379
|
+
|
|
380
|
+
function ItemList() {
|
|
381
|
+
const items = useSelector(filteredItemsSelector)
|
|
382
|
+
return <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>
|
|
383
|
+
}
|
|
164
384
|
```
|
|
165
385
|
|
|
166
|
-
###
|
|
386
|
+
### createSynapseCtx
|
|
387
|
+
|
|
388
|
+
Context-based pattern for sharing synapse across component tree:
|
|
389
|
+
|
|
390
|
+
```tsx
|
|
391
|
+
import { createSynapseCtx, useSelector } from 'synapse-storage/react'
|
|
392
|
+
|
|
393
|
+
const {
|
|
394
|
+
contextSynapse,
|
|
395
|
+
useSynapseStorage,
|
|
396
|
+
useSynapseSelectors,
|
|
397
|
+
useSynapseActions,
|
|
398
|
+
cleanupSynapse,
|
|
399
|
+
} = createSynapseCtx(storePromise, {
|
|
400
|
+
loadingComponent: <div>Loading...</div>,
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
const Page = contextSynapse(() => {
|
|
404
|
+
const selectors = useSynapseSelectors()
|
|
405
|
+
const actions = useSynapseActions()
|
|
406
|
+
const count = useSelector(selectors.count)
|
|
407
|
+
|
|
408
|
+
return <button onClick={() => actions.increment()}>Count: {count}</button>
|
|
409
|
+
})
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### awaitSynapse
|
|
413
|
+
|
|
414
|
+
HOC and hook for waiting on synapse initialization:
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { awaitSynapse } from 'synapse-storage/react'
|
|
418
|
+
|
|
419
|
+
const awaiter = awaitSynapse(storePromise, {
|
|
420
|
+
loadingComponent: <div>Loading...</div>,
|
|
421
|
+
errorComponent: (error) => <div>Error: {error.message}</div>,
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
// HOC
|
|
425
|
+
const ReadyComponent = awaiter.withSynapseReady(MyComponent)
|
|
426
|
+
|
|
427
|
+
// Hook
|
|
428
|
+
function Status() {
|
|
429
|
+
const { isReady, isPending, isError, store } = awaiter.useSynapseReady()
|
|
430
|
+
if (isPending) return <div>Loading...</div>
|
|
431
|
+
if (isError) return <div>Error</div>
|
|
432
|
+
return <div>Ready</div>
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Programmatic (also works outside React)
|
|
436
|
+
awaiter.isReady() // boolean
|
|
437
|
+
awaiter.getStatus() // 'pending' | 'ready' | 'error'
|
|
438
|
+
await awaiter.waitForReady() // Promise<Store>
|
|
439
|
+
awaiter.onReady((store) => { /* ... */ })
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Reactive Features (RxJS)
|
|
445
|
+
|
|
446
|
+
### Dispatcher — Actions & Watchers
|
|
167
447
|
|
|
168
448
|
```typescript
|
|
169
|
-
|
|
170
|
-
|
|
449
|
+
import { createDispatcher, createAction, createWatcher } from 'synapse-storage/reactive'
|
|
450
|
+
|
|
451
|
+
const dispatcher = createDispatcher(
|
|
452
|
+
{ storage },
|
|
453
|
+
(_storage, { createAction, createWatcher }) => {
|
|
454
|
+
const increment = createAction({
|
|
455
|
+
type: 'increment',
|
|
456
|
+
action: () => storage.update((s) => { s.count += 1 }),
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
const setName = createAction({
|
|
460
|
+
type: 'setName',
|
|
461
|
+
action: (name: string) => {
|
|
462
|
+
storage.set('name', name)
|
|
463
|
+
return name
|
|
464
|
+
},
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
const watchCount = createWatcher({
|
|
468
|
+
type: 'watchCount',
|
|
469
|
+
selector: (state) => state.count,
|
|
470
|
+
shouldTrigger: (prev, curr) => prev !== curr,
|
|
471
|
+
notifyAfterSubscribe: true,
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
return { increment, setName, watchCount }
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
// Dispatch
|
|
479
|
+
dispatcher.dispatch.increment()
|
|
480
|
+
dispatcher.dispatch.setName('Alice')
|
|
171
481
|
|
|
172
|
-
//
|
|
173
|
-
|
|
482
|
+
// Watch (RxJS Observable)
|
|
483
|
+
dispatcher.watchers.watchCount().subscribe((action) => {
|
|
484
|
+
console.log('count:', action.payload)
|
|
485
|
+
})
|
|
174
486
|
|
|
175
|
-
//
|
|
176
|
-
|
|
487
|
+
// Action stream
|
|
488
|
+
dispatcher.actions.subscribe((action) => {
|
|
489
|
+
console.log(action.type, action.payload)
|
|
490
|
+
})
|
|
177
491
|
|
|
178
|
-
|
|
492
|
+
dispatcher.destroy()
|
|
179
493
|
```
|
|
180
494
|
|
|
181
|
-
###
|
|
495
|
+
### Effects
|
|
182
496
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
497
|
+
```typescript
|
|
498
|
+
import { createEffect, ofType } from 'synapse-storage/reactive'
|
|
499
|
+
import { debounceTime, switchMap, tap } from 'rxjs/operators'
|
|
500
|
+
|
|
501
|
+
createEffect((action$, state$, { dispatcher }) =>
|
|
502
|
+
action$.pipe(
|
|
503
|
+
ofType(dispatcher.dispatch.search),
|
|
504
|
+
debounceTime(400),
|
|
505
|
+
switchMap((action) =>
|
|
506
|
+
fetchResults(action.payload).pipe(
|
|
507
|
+
tap((results) => dispatcher.dispatch.searchSuccess(results))
|
|
508
|
+
)
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
)
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## createSynapse
|
|
188
517
|
|
|
189
|
-
|
|
518
|
+
High-level utility that wires storage + selectors + dispatcher + effects together:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { createSynapse } from 'synapse-storage/utils'
|
|
522
|
+
|
|
523
|
+
const storePromise = createSynapse({
|
|
524
|
+
storage: new MemoryStorage<State>({ name: 'app', initialState }),
|
|
525
|
+
|
|
526
|
+
createSelectorsFn: (sm) => ({
|
|
527
|
+
count: sm.createSelector((s) => s.count),
|
|
528
|
+
doubled: sm.createSelector(
|
|
529
|
+
[count],
|
|
530
|
+
(c) => c * 2
|
|
531
|
+
),
|
|
532
|
+
}),
|
|
533
|
+
|
|
534
|
+
createDispatcherFn: (storage) =>
|
|
535
|
+
createDispatcher({ storage }, (_s, { createAction, createWatcher }) => ({
|
|
536
|
+
increment: createAction({
|
|
537
|
+
type: 'increment',
|
|
538
|
+
action: () => storage.update((s) => { s.count += 1 }),
|
|
539
|
+
}),
|
|
540
|
+
watchCount: createWatcher({
|
|
541
|
+
type: 'watchCount',
|
|
542
|
+
selector: (s) => s.count,
|
|
543
|
+
}),
|
|
544
|
+
})),
|
|
545
|
+
|
|
546
|
+
effects: [
|
|
547
|
+
createEffect((action$, state$, { dispatcher }) =>
|
|
548
|
+
action$.pipe(/* ... */)
|
|
549
|
+
),
|
|
550
|
+
],
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
const store = await storePromise
|
|
554
|
+
|
|
555
|
+
store.storage // ISyncStorage<State>
|
|
556
|
+
store.selectors // { count, doubled }
|
|
557
|
+
store.actions // { increment, ... }
|
|
558
|
+
store.dispatcher // Dispatcher
|
|
559
|
+
store.state$ // Observable<State> (when effects are used)
|
|
560
|
+
store.destroy() // cleanup everything
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Dependencies
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
const authStore = createSynapse({ /* ... */ })
|
|
567
|
+
|
|
568
|
+
const settingsStore = createSynapse({
|
|
569
|
+
dependencies: [authStore],
|
|
570
|
+
dependencyTimeout: 5000,
|
|
571
|
+
|
|
572
|
+
createStorageFn: async () => {
|
|
573
|
+
const auth = await authStore
|
|
574
|
+
const userId = auth.storage.getStateSync().userId
|
|
575
|
+
const storage = new MemoryStorage({ name: 'settings', initialState: { userId } })
|
|
576
|
+
await storage.initialize()
|
|
577
|
+
return storage
|
|
578
|
+
},
|
|
579
|
+
})
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## API Client
|
|
585
|
+
|
|
586
|
+
HTTP client with typed endpoints, caching, and tag-based invalidation:
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
import { ApiClient } from 'synapse-storage/api'
|
|
590
|
+
import { MemoryStorage } from 'synapse-storage/core'
|
|
591
|
+
|
|
592
|
+
const cacheStorage = new MemoryStorage<Record<string, any>>({
|
|
593
|
+
name: 'api-cache',
|
|
594
|
+
initialState: {},
|
|
595
|
+
})
|
|
596
|
+
|
|
597
|
+
const api = new ApiClient({
|
|
598
|
+
storage: cacheStorage,
|
|
599
|
+
baseQuery: {
|
|
600
|
+
baseUrl: 'https://api.example.com',
|
|
601
|
+
timeout: 10000,
|
|
602
|
+
prepareHeaders: async (headers, context) => {
|
|
603
|
+
headers.set('Authorization', `Bearer ${token}`)
|
|
604
|
+
return headers
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
cache: {
|
|
608
|
+
ttl: 60000,
|
|
609
|
+
cleanup: { enabled: true, interval: 120000 },
|
|
610
|
+
invalidateOnError: true,
|
|
611
|
+
},
|
|
612
|
+
endpoints: async (create) => ({
|
|
613
|
+
getUsers: create<{ limit?: number }, UsersResponse>({
|
|
614
|
+
request: (params) => ({
|
|
615
|
+
path: '/users',
|
|
616
|
+
method: 'GET',
|
|
617
|
+
query: params,
|
|
618
|
+
}),
|
|
619
|
+
cache: { ttl: 120000 },
|
|
620
|
+
tags: ['users'],
|
|
621
|
+
}),
|
|
622
|
+
createUser: create<CreateUserInput, User>({
|
|
623
|
+
request: (params) => ({
|
|
624
|
+
path: '/users',
|
|
625
|
+
method: 'POST',
|
|
626
|
+
body: params,
|
|
627
|
+
}),
|
|
628
|
+
invalidatesTags: ['users'],
|
|
629
|
+
cache: false,
|
|
630
|
+
}),
|
|
631
|
+
}),
|
|
632
|
+
})
|
|
633
|
+
|
|
634
|
+
await cacheStorage.initialize()
|
|
635
|
+
await api.init()
|
|
636
|
+
|
|
637
|
+
// Simple request
|
|
638
|
+
const result = await api.request('getUsers', { limit: 10 })
|
|
639
|
+
if (result.ok) console.log(result.data, result.fromCache)
|
|
640
|
+
|
|
641
|
+
// Endpoint-level subscription
|
|
642
|
+
const endpoints = api.getEndpoints()
|
|
643
|
+
const req = endpoints.getUsers.request({ limit: 10 })
|
|
644
|
+
|
|
645
|
+
req.subscribe((state) => {
|
|
646
|
+
// state.status: 'idle' | 'loading' | 'success' | 'error'
|
|
647
|
+
// state.data, state.error, state.fromCache
|
|
648
|
+
})
|
|
649
|
+
|
|
650
|
+
const result = await req.wait()
|
|
651
|
+
req.abort()
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## EventBus
|
|
657
|
+
|
|
658
|
+
Decoupled communication between modules:
|
|
659
|
+
|
|
660
|
+
```typescript
|
|
661
|
+
import { createEventBus } from 'synapse-storage/utils'
|
|
662
|
+
|
|
663
|
+
const eventBus = await createEventBus({
|
|
664
|
+
name: 'app-events',
|
|
665
|
+
autoCleanup: true,
|
|
666
|
+
maxEvents: 1000,
|
|
667
|
+
})
|
|
668
|
+
|
|
669
|
+
// Publish
|
|
670
|
+
await eventBus.actions.publish({
|
|
671
|
+
event: 'USER_UPDATED',
|
|
672
|
+
data: { userId: 123 },
|
|
673
|
+
metadata: { priority: 'high', ttl: 60000 },
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
// Subscribe (supports wildcards)
|
|
677
|
+
const { unsubscribe } = await eventBus.actions.subscribe({
|
|
678
|
+
eventPattern: 'USER_*',
|
|
679
|
+
handler: (data, event) => console.log(event.event, data),
|
|
680
|
+
})
|
|
681
|
+
|
|
682
|
+
// History
|
|
683
|
+
const history = await eventBus.actions.getEventHistory({
|
|
684
|
+
eventType: 'USER_UPDATED',
|
|
685
|
+
limit: 10,
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
await eventBus.destroy()
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## Singleton Pattern
|
|
694
|
+
|
|
695
|
+
Share storage instances across components:
|
|
696
|
+
|
|
697
|
+
```typescript
|
|
698
|
+
import { MemoryStorage, ConfigMergeStrategy } from 'synapse-storage/core'
|
|
699
|
+
|
|
700
|
+
// Component A
|
|
701
|
+
const storage1 = new MemoryStorage({
|
|
702
|
+
name: 'shared',
|
|
703
|
+
singleton: {
|
|
704
|
+
enabled: true,
|
|
705
|
+
mergeStrategy: ConfigMergeStrategy.FIRST_WINS,
|
|
706
|
+
},
|
|
707
|
+
initialState: { count: 0 },
|
|
708
|
+
})
|
|
709
|
+
|
|
710
|
+
// Component B — gets the same instance
|
|
711
|
+
const storage2 = new MemoryStorage({
|
|
712
|
+
name: 'shared',
|
|
713
|
+
singleton: { enabled: true },
|
|
714
|
+
initialState: { count: 99 }, // ignored (FIRST_WINS)
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
storage1 === storage2 // true
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
Merge strategies: `FIRST_WINS`, `DEEP_MERGE`, `OVERRIDE`, `WARN_AND_USE_FIRST`, `STRICT` (throws).
|
|
190
721
|
|
|
191
722
|
---
|
|
723
|
+
|
|
724
|
+
## Storage Lifecycle
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
await storage.initialize()
|
|
728
|
+
await storage.waitForReady()
|
|
729
|
+
|
|
730
|
+
storage.initStatus // { status: 'ready' | 'loading' | 'error' | 'idle' }
|
|
731
|
+
|
|
732
|
+
const unsub = storage.onStatusChange((status) => console.log(status))
|
|
733
|
+
|
|
734
|
+
await storage.destroy()
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
## Examples
|
|
740
|
+
|
|
741
|
+
- [GitHub Examples](https://github.com/Vlad92msk/synapse-examples)
|
|
742
|
+
- [YouTube](https://www.youtube.com/channel/UCGENI_i4qmBkPp93P2HvvGw)
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## License
|
|
747
|
+
|
|
748
|
+
MIT
|