synapse-storage 3.0.16 → 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 +657 -127
- 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 -95
- package/dist/core.js +0 -1
- package/dist/createSynapse-BLbPlWXK.d.ts +0 -97
- package/dist/dispatcher.module-DcXkCRNj.d.ts +0 -360
- package/dist/react.d.ts +0 -98
- package/dist/react.js +0 -1
- package/dist/reactive.d.ts +0 -35
- package/dist/reactive.js +0 -1
- package/dist/storage.interface-2HKvqdAJ.d.ts +0 -444
- 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,171 +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
|
+
---
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { MemoryStorage } from 'synapse-storage/core'
|
|
84
|
+
|
|
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
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Storage Types
|
|
117
|
+
|
|
118
|
+
Synapse has two storage categories with **type-safe separation**:
|
|
119
|
+
|
|
120
|
+
### Sync Storage (MemoryStorage, LocalStorage)
|
|
121
|
+
|
|
122
|
+
All operations are synchronous — `get()`, `set()`, `update()`, `getState()` return values directly.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { MemoryStorage, LocalStorage } from 'synapse-storage/core'
|
|
126
|
+
|
|
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
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Async Storage (IndexedDBStorage)
|
|
135
|
+
|
|
136
|
+
Operations return Promises — persistent browser storage.
|
|
137
|
+
|
|
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
|
+
```
|
|
150
|
+
|
|
151
|
+
### getStateSync()
|
|
152
|
+
|
|
153
|
+
Available on **all** storage types — returns the cached state synchronously, even for IndexedDB:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const state = storage.getStateSync() // always sync
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Static Factory Methods
|
|
160
|
+
|
|
161
|
+
Every storage class has a `.create()` static method:
|
|
80
162
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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)
|
|
163
|
+
```typescript
|
|
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
|
+
```
|
|
168
|
+
|
|
169
|
+
### StorageFactory
|
|
94
170
|
|
|
95
|
-
|
|
171
|
+
Universal factory with type-safe overloads:
|
|
96
172
|
|
|
97
|
-
|
|
98
|
-
-
|
|
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
|
+
```
|
|
99
188
|
|
|
100
189
|
---
|
|
101
190
|
|
|
102
|
-
##
|
|
191
|
+
## Reading & Writing Data
|
|
103
192
|
|
|
104
|
-
|
|
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
|
+
---
|
|
105
304
|
|
|
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 | ✅|
|
|
305
|
+
## Plugin System
|
|
116
306
|
|
|
117
|
-
|
|
307
|
+
Lifecycle hooks for intercepting storage operations:
|
|
118
308
|
|
|
119
309
|
```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
|
|
310
|
+
import { ISyncStoragePlugin, SyncStoragePluginModule } from 'synapse-storage/core'
|
|
126
311
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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.
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
import { useCreateStorage } from 'synapse-storage/react'
|
|
350
|
+
|
|
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
|
|
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
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
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
|
+
})
|
|
130
410
|
```
|
|
131
411
|
|
|
132
|
-
###
|
|
412
|
+
### awaitSynapse
|
|
413
|
+
|
|
414
|
+
HOC and hook for waiting on synapse initialization:
|
|
133
415
|
|
|
134
|
-
|
|
416
|
+
```tsx
|
|
417
|
+
import { awaitSynapse } from 'synapse-storage/react'
|
|
135
418
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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 |
|
|
419
|
+
const awaiter = awaitSynapse(storePromise, {
|
|
420
|
+
loadingComponent: <div>Loading...</div>,
|
|
421
|
+
errorComponent: (error) => <div>Error: {error.message}</div>,
|
|
422
|
+
})
|
|
143
423
|
|
|
144
|
-
|
|
424
|
+
// HOC
|
|
425
|
+
const ReadyComponent = awaiter.withSynapseReady(MyComponent)
|
|
145
426
|
|
|
146
|
-
|
|
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
|
+
---
|
|
147
443
|
|
|
148
|
-
|
|
444
|
+
## Reactive Features (RxJS)
|
|
149
445
|
|
|
150
|
-
###
|
|
446
|
+
### Dispatcher — Actions & Watchers
|
|
151
447
|
|
|
152
448
|
```typescript
|
|
153
|
-
|
|
154
|
-
|
|
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')
|
|
155
481
|
|
|
156
|
-
//
|
|
157
|
-
|
|
482
|
+
// Watch (RxJS Observable)
|
|
483
|
+
dispatcher.watchers.watchCount().subscribe((action) => {
|
|
484
|
+
console.log('count:', action.payload)
|
|
485
|
+
})
|
|
158
486
|
|
|
159
|
-
//
|
|
160
|
-
|
|
487
|
+
// Action stream
|
|
488
|
+
dispatcher.actions.subscribe((action) => {
|
|
489
|
+
console.log(action.type, action.payload)
|
|
490
|
+
})
|
|
161
491
|
|
|
162
|
-
|
|
163
|
-
import { useSelector } from 'synapse-storage/react' // +5KB
|
|
492
|
+
dispatcher.destroy()
|
|
164
493
|
```
|
|
165
494
|
|
|
166
|
-
###
|
|
495
|
+
### Effects
|
|
167
496
|
|
|
168
497
|
```typescript
|
|
169
|
-
|
|
170
|
-
import {
|
|
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
|
+
---
|
|
171
515
|
|
|
172
|
-
|
|
173
|
-
class MyApiClient { /* your logic */ }
|
|
516
|
+
## createSynapse
|
|
174
517
|
|
|
175
|
-
|
|
176
|
-
const useMyCustomHook = () => { /* your logic */ }
|
|
518
|
+
High-level utility that wires storage + selectors + dispatcher + effects together:
|
|
177
519
|
|
|
178
|
-
|
|
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
|
|
179
561
|
```
|
|
180
562
|
|
|
181
|
-
###
|
|
563
|
+
### Dependencies
|
|
182
564
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
+
```
|
|
188
581
|
|
|
189
|
-
> **💡 Evolution Example:** Started with MemoryStorage → added ApiClient → connected reactive effects → integrated React hooks. **Each step is optional!**
|
|
190
|
-
>
|
|
191
582
|
---
|
|
192
583
|
|
|
193
|
-
##
|
|
584
|
+
## API Client
|
|
194
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()
|
|
195
652
|
```
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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()
|
|
216
689
|
```
|
|
217
690
|
|
|
218
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).
|
|
721
|
+
|
|
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
|