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
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
interface Selector<T, R> {
|
|
1
|
+
export interface Selector<T, R> {
|
|
2
2
|
(state: T): R;
|
|
3
3
|
}
|
|
4
|
-
interface SelectorOptions<T> {
|
|
4
|
+
export interface SelectorOptions<T> {
|
|
5
5
|
equals?: (a: T, b: T) => boolean;
|
|
6
6
|
name?: string;
|
|
7
7
|
}
|
|
8
|
-
interface Subscriber<T> {
|
|
8
|
+
export interface Subscriber<T> {
|
|
9
9
|
notify: (value: T) => void | Promise<void>;
|
|
10
10
|
}
|
|
11
|
-
interface SelectorAPI<T> {
|
|
12
|
-
select: () =>
|
|
11
|
+
export interface SelectorAPI<T> {
|
|
12
|
+
select: () => T;
|
|
13
|
+
selectSync: () => T;
|
|
13
14
|
subscribe: (subscriber: Subscriber<T>) => VoidFunction;
|
|
14
15
|
getId: () => string;
|
|
16
|
+
/** @internal — проверка готовности источника данных */
|
|
17
|
+
isSourceReady: () => boolean;
|
|
18
|
+
/** @internal — подписка на изменение статуса источника */
|
|
19
|
+
onSourceStatusChange: (callback: (isReady: boolean) => void) => VoidFunction;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* Интерфейс для модуля селекторов
|
|
18
23
|
* Определяет контракт для работы с селекторами, который должен реализовывать SelectorModule
|
|
19
24
|
*/
|
|
20
|
-
interface ISelectorModule<TStore extends Record<string, any>> {
|
|
25
|
+
export interface ISelectorModule<TStore extends Record<string, any>> {
|
|
21
26
|
/**
|
|
22
27
|
* Имя связанного хранилища
|
|
23
28
|
*/
|
|
@@ -59,5 +64,33 @@ interface ISelectorModule<TStore extends Record<string, any>> {
|
|
|
59
64
|
*/
|
|
60
65
|
destroy(): void;
|
|
61
66
|
}
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Интерфейс для фабрики селекторов
|
|
69
|
+
* Позволяет создавать набор связанных селекторов
|
|
70
|
+
*/
|
|
71
|
+
export interface ISelectorCreator<TStore extends Record<string, any>, TSelectors, TExternalSelectors = Record<string, any>> {
|
|
72
|
+
/**
|
|
73
|
+
* Создает набор селекторов
|
|
74
|
+
*
|
|
75
|
+
* @param selectorModule Модуль селекторов
|
|
76
|
+
* @param externalSelectors Внешние селекторы (опционально)
|
|
77
|
+
* @returns Объект с селекторами
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const createUserSelectors: ISelectorCreator<UserStore, UserSelectors> =
|
|
81
|
+
* (selectorModule, externalSelectors) => {
|
|
82
|
+
* const isActive = selectorModule.createSelector(
|
|
83
|
+
* (state) => state.user.isActive
|
|
84
|
+
* );
|
|
85
|
+
*
|
|
86
|
+
* return { isActive };
|
|
87
|
+
* };
|
|
88
|
+
*/
|
|
89
|
+
(selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors): TSelectors;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Тип для функции, создающей селекторы
|
|
93
|
+
* Более простая версия ISelectorCreator, если не нужен полный интерфейс
|
|
94
|
+
*/
|
|
95
|
+
export type SelectorCreatorFunction<TStore extends Record<string, any> = Record<string, any>, TSelectors = any, TExternalSelectors = Record<string, any>> = (selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors) => TSelectors;
|
|
96
|
+
//# sourceMappingURL=selector.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.interface.d.ts","sourceRoot":"","sources":["../../../src/core/selector/selector.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC5B,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAA;CACd;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,CAAA;IACf,UAAU,EAAE,MAAM,CAAC,CAAA;IACnB,SAAS,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,YAAY,CAAA;IACtD,KAAK,EAAE,MAAM,MAAM,CAAA;IACnB,uDAAuD;IACvD,aAAa,EAAE,MAAM,OAAO,CAAA;IAC5B,0DAA0D;IAC1D,oBAAoB,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,YAAY,CAAA;CAC7E;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACjE;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAE9F;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE;SAAG,CAAC,IAAI,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAElL;;OAEG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACxH;;;;;;;;;;;;;;;;OAgBG;IACH,CAAC,cAAc,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,EAAE,kBAAkB,GAAG,UAAU,CAAA;CAC9F;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAC1J,cAAc,EAAE,eAAe,CAAC,MAAM,CAAC,EACvC,iBAAiB,CAAC,EAAE,kBAAkB,KACnC,UAAU,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core/selector/selector.interface.js","sources":["../../../src/core/selector/selector.interface.ts"],"sourcesContent":["export interface Selector<T, R> {\n (state: T): R\n}\n\nexport interface SelectorOptions<T> {\n equals?: (a: T, b: T) => boolean\n name?: string\n}\n\nexport interface Subscriber<T> {\n notify: (value: T) => void | Promise<void>\n}\n\nexport interface SelectorAPI<T> {\n select: () => T\n selectSync: () => T\n subscribe: (subscriber: Subscriber<T>) => VoidFunction\n getId: () => string\n /** @internal — проверка готовности источника данных */\n isSourceReady: () => boolean\n /** @internal — подписка на изменение статуса источника */\n onSourceStatusChange: (callback: (isReady: boolean) => void) => VoidFunction\n}\n\n/**\n * Интерфейс для модуля селекторов\n * Определяет контракт для работы с селекторами, который должен реализовывать SelectorModule\n */\nexport interface ISelectorModule<TStore extends Record<string, any>> {\n /**\n * Имя связанного хранилища\n */\n readonly storageName: string\n\n /**\n * Создает простой селектор на основе функции выбора\n *\n * @param selector Функция, извлекающая данные из состояния\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const isActive = selectorModule.createSelector(\n * (state) => state.user.isActive,\n * { name: 'userIsActive' }\n * );\n */\n createSelector<T>(selector: Selector<TStore, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Создает комбинированный селектор на основе других селекторов\n *\n * @param dependencies Массив селекторов, от которых зависит новый селектор\n * @param resultFn Функция, комбинирующая результаты зависимостей\n * @param options Опции селектора\n * @returns API селектора\n *\n * @example\n * const userWithStatus = selectorModule.createSelector(\n * [userSelector, statusSelector],\n * (user, status) => ({ ...user, status }),\n * { name: 'userWithStatus' }\n * );\n */\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n /**\n * Освобождает ресурсы, связанные с модулем селекторов\n */\n destroy(): void\n}\n\n/**\n * Интерфейс для фабрики селекторов\n * Позволяет создавать набор связанных селекторов\n */\nexport interface ISelectorCreator<TStore extends Record<string, any>, TSelectors, TExternalSelectors = Record<string, any>> {\n /**\n * Создает набор селекторов\n *\n * @param selectorModule Модуль селекторов\n * @param externalSelectors Внешние селекторы (опционально)\n * @returns Объект с селекторами\n *\n * @example\n * const createUserSelectors: ISelectorCreator<UserStore, UserSelectors> =\n * (selectorModule, externalSelectors) => {\n * const isActive = selectorModule.createSelector(\n * (state) => state.user.isActive\n * );\n *\n * return { isActive };\n * };\n */\n (selectorModule: ISelectorModule<TStore>, externalSelectors?: TExternalSelectors): TSelectors\n}\n\n/**\n * Тип для функции, создающей селекторы\n * Более простая версия ISelectorCreator, если не нужен полный интерфейс\n */\nexport type SelectorCreatorFunction<TStore extends Record<string, any> = Record<string, any>, TSelectors = any, TExternalSelectors = Record<string, any>> = (\n selectorModule: ISelectorModule<TStore>,\n externalSelectors?: TExternalSelectors,\n) => TSelectors\n"],"names":[],"mappings":"AAiGA;;;CAGC,GAIc"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ILogger, IStorage } from '../storage';
|
|
2
|
+
import type { ISelectorModule, Selector, SelectorAPI, SelectorOptions } from './selector.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Глубокое сравнение объектов по структуре с защитой от циклических ссылок и лимитом глубины.
|
|
5
|
+
* Используется только при явной передаче через options.equals.
|
|
6
|
+
*/
|
|
7
|
+
export declare function deepEquals<T>(a: T, b: T, depth?: number, visited?: WeakSet<object>): boolean;
|
|
8
|
+
export declare class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {
|
|
9
|
+
private readonly source;
|
|
10
|
+
private readonly logger?;
|
|
11
|
+
storageName: string;
|
|
12
|
+
private selectorIdCounter;
|
|
13
|
+
private subscriptions;
|
|
14
|
+
private localSelectorCache;
|
|
15
|
+
private batchUpdateInProgress;
|
|
16
|
+
private pendingUpdates;
|
|
17
|
+
constructor(source: IStorage<S>, logger?: ILogger | undefined);
|
|
18
|
+
private isSourceReady;
|
|
19
|
+
private onSourceStatusChange;
|
|
20
|
+
/**
|
|
21
|
+
* Генерирует уникальное имя для селектора через автоинкрементный счётчик
|
|
22
|
+
*/
|
|
23
|
+
private generateName;
|
|
24
|
+
/**
|
|
25
|
+
* Обрабатывает отложенные обновления синхронно
|
|
26
|
+
*/
|
|
27
|
+
private processPendingUpdates;
|
|
28
|
+
createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>;
|
|
29
|
+
createSelector<Deps extends unknown[], T>(dependencies: {
|
|
30
|
+
[K in keyof Deps]: SelectorAPI<Deps[K]>;
|
|
31
|
+
}, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>;
|
|
32
|
+
private createSimpleSelector;
|
|
33
|
+
private createCombinedSelector;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=selector.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.module.d.ts","sourceRoot":"","sources":["../../../src/core/selector/selector.module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAqB,MAAM,YAAY,CAAA;AAEtE,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAc,MAAM,sBAAsB,CAAA;AAW/G;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,SAAI,EAAE,OAAO,kBAAgB,GAAG,OAAO,CAmCrF;AA0ID,qBAAa,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IAoBpF,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IApB1B,WAAW,EAAE,MAAM,CAAA;IAEnB,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,aAAa,CAA+C;IAEpE,OAAO,CAAC,kBAAkB,CAOvB;IAGH,OAAO,CAAC,qBAAqB,CAAQ;IACrC,OAAO,CAAC,cAAc,CAAoB;gBAGvB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,MAAM,CAAC,EAAE,OAAO,YAAA;IAKnC,OAAO,CAAC,aAAa,CAEpB;IAED,OAAO,CAAC,oBAAoB,CAI3B;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;IACzF,cAAc,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE;SAAG,CAAC,IAAI,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;IA4DlL,OAAO,CAAC,oBAAoB;IA0D5B,OAAO,CAAC,sBAAsB;IAkG9B,OAAO,IAAI,IAAI;CAchB"}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { StorageStatus } from "../storage/index.js";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reference equality (===) — поведение по умолчанию
|
|
7
|
+
*/ function defaultEquals(a, b) {
|
|
8
|
+
return a === b;
|
|
9
|
+
}
|
|
10
|
+
const MAX_DEEP_EQUAL_DEPTH = 10;
|
|
11
|
+
/**
|
|
12
|
+
* Глубокое сравнение объектов по структуре с защитой от циклических ссылок и лимитом глубины.
|
|
13
|
+
* Используется только при явной передаче через options.equals.
|
|
14
|
+
*/ function deepEquals(a, b, depth = 0, visited = new WeakSet()) {
|
|
15
|
+
if (a === b) return true;
|
|
16
|
+
if (a == null || b == null) return false;
|
|
17
|
+
if (typeof a !== typeof b) return false;
|
|
18
|
+
if (depth > MAX_DEEP_EQUAL_DEPTH) return false;
|
|
19
|
+
if (typeof a !== 'object') return a === b;
|
|
20
|
+
// Защита от циклических ссылок
|
|
21
|
+
if (visited.has(a)) return false;
|
|
22
|
+
visited.add(a);
|
|
23
|
+
if (a instanceof Date && b instanceof Date) {
|
|
24
|
+
return a.getTime() === b.getTime();
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
27
|
+
if (a.length !== b.length) return false;
|
|
28
|
+
for(let i = 0; i < a.length; i++){
|
|
29
|
+
if (!deepEquals(a[i], b[i], depth + 1, visited)) return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
34
|
+
const keysA = Object.keys(a);
|
|
35
|
+
const keysB = Object.keys(b);
|
|
36
|
+
if (keysA.length !== keysB.length) return false;
|
|
37
|
+
return keysA.every((key)=>{
|
|
38
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
39
|
+
return deepEquals(a[key], b[key], depth + 1, visited);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Оборачивает state в Proxy для отслеживания обращений к ключам верхнего уровня.
|
|
44
|
+
* Возвращает проксированный state и Set с именами ключей, к которым обратился селектор.
|
|
45
|
+
*/ function trackDependencies(state) {
|
|
46
|
+
const accessedKeys = new Set();
|
|
47
|
+
const proxy = new Proxy(state, {
|
|
48
|
+
get (target, prop, receiver) {
|
|
49
|
+
if (typeof prop === 'string') {
|
|
50
|
+
accessedKeys.add(prop);
|
|
51
|
+
}
|
|
52
|
+
return Reflect.get(target, prop, receiver);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
proxy,
|
|
57
|
+
accessedKeys
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Мемоизирует функцию селектора для оптимизации + трекинг зависимостей через Proxy
|
|
61
|
+
function memoizeSelector(selectorFn, equals = defaultEquals) {
|
|
62
|
+
let lastState;
|
|
63
|
+
let lastResult;
|
|
64
|
+
let hasResult = false;
|
|
65
|
+
let trackedKeys = null;
|
|
66
|
+
const memoized = function(state) {
|
|
67
|
+
// Если это первый вызов или состояние изменилось
|
|
68
|
+
if (!hasResult || lastState !== state) {
|
|
69
|
+
// Трекаем зависимости через Proxy при каждом реальном пересчёте
|
|
70
|
+
const { proxy, accessedKeys } = trackDependencies(state);
|
|
71
|
+
const newResult = selectorFn(proxy);
|
|
72
|
+
trackedKeys = accessedKeys;
|
|
73
|
+
// Проверяем, изменился ли результат
|
|
74
|
+
if (!hasResult || !equals(newResult, lastResult)) {
|
|
75
|
+
lastResult = newResult;
|
|
76
|
+
}
|
|
77
|
+
lastState = state;
|
|
78
|
+
hasResult = true;
|
|
79
|
+
}
|
|
80
|
+
return lastResult;
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
memoized,
|
|
84
|
+
getTrackedKeys: ()=>trackedKeys
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
class SelectorSubscription {
|
|
88
|
+
name;
|
|
89
|
+
getState;
|
|
90
|
+
equals;
|
|
91
|
+
logger;
|
|
92
|
+
id;
|
|
93
|
+
subscribers = new Set();
|
|
94
|
+
lastValue;
|
|
95
|
+
hasValue = false;
|
|
96
|
+
constructor(name, getState, equals = defaultEquals, logger){
|
|
97
|
+
this.name = name;
|
|
98
|
+
this.getState = getState;
|
|
99
|
+
this.equals = equals;
|
|
100
|
+
this.logger = logger;
|
|
101
|
+
this.id = name;
|
|
102
|
+
this.logger?.debug(`[${this.id}] SelectorSubscription created`);
|
|
103
|
+
}
|
|
104
|
+
notify() {
|
|
105
|
+
try {
|
|
106
|
+
const newValue = this.getState();
|
|
107
|
+
// Проверка на изменение значения с использованием функции сравнения
|
|
108
|
+
if (!this.hasValue || !this.equals(newValue, this.lastValue)) {
|
|
109
|
+
this.logger?.debug(`[${this.id}] Value changed, notify()`);
|
|
110
|
+
this.lastValue = newValue;
|
|
111
|
+
this.hasValue = true;
|
|
112
|
+
for (const subscriber of this.subscribers){
|
|
113
|
+
try {
|
|
114
|
+
subscriber.notify(newValue);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, {
|
|
117
|
+
error
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
this.logger?.error(`[${this.id}] Ошибка в notify()`, {
|
|
124
|
+
error
|
|
125
|
+
});
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
subscribe(subscriber) {
|
|
130
|
+
this.subscribers.add(subscriber);
|
|
131
|
+
// Отправляем текущее значение синхронно
|
|
132
|
+
if (this.hasValue) {
|
|
133
|
+
try {
|
|
134
|
+
subscriber.notify(this.lastValue);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, {
|
|
137
|
+
error
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
// Вычисляем значение синхронно
|
|
142
|
+
this.notify();
|
|
143
|
+
}
|
|
144
|
+
return ()=>{
|
|
145
|
+
this.subscribers.delete(subscriber);
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
cleanup() {
|
|
149
|
+
this.subscribers.clear();
|
|
150
|
+
this.lastValue = undefined;
|
|
151
|
+
this.hasValue = false;
|
|
152
|
+
}
|
|
153
|
+
getLastValue() {
|
|
154
|
+
return this.lastValue;
|
|
155
|
+
}
|
|
156
|
+
getValue() {
|
|
157
|
+
if (!this.hasValue) {
|
|
158
|
+
this.lastValue = this.getState();
|
|
159
|
+
this.hasValue = true;
|
|
160
|
+
}
|
|
161
|
+
return this.lastValue;
|
|
162
|
+
}
|
|
163
|
+
getId() {
|
|
164
|
+
return this.id;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
class SelectorModule {
|
|
168
|
+
source;
|
|
169
|
+
logger;
|
|
170
|
+
storageName;
|
|
171
|
+
selectorIdCounter = 0;
|
|
172
|
+
subscriptions = new Map();
|
|
173
|
+
localSelectorCache = new Map();
|
|
174
|
+
// Флаг для батчинга обновлений
|
|
175
|
+
batchUpdateInProgress = false;
|
|
176
|
+
pendingUpdates = new Set();
|
|
177
|
+
constructor(source, logger){
|
|
178
|
+
this.source = source;
|
|
179
|
+
this.logger = logger;
|
|
180
|
+
this.storageName = source.name;
|
|
181
|
+
}
|
|
182
|
+
isSourceReady = ()=>{
|
|
183
|
+
return this.source.initStatus.status === StorageStatus.READY;
|
|
184
|
+
};
|
|
185
|
+
onSourceStatusChange = (callback)=>{
|
|
186
|
+
return this.source.onStatusChange((status)=>{
|
|
187
|
+
callback(status.status === StorageStatus.READY);
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Генерирует уникальное имя для селектора через автоинкрементный счётчик
|
|
192
|
+
*/ generateName() {
|
|
193
|
+
return `${this.storageName}_selector_${this.selectorIdCounter++}`;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Обрабатывает отложенные обновления синхронно
|
|
197
|
+
*/ processPendingUpdates() {
|
|
198
|
+
if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return;
|
|
199
|
+
this.batchUpdateInProgress = true;
|
|
200
|
+
try {
|
|
201
|
+
// Копируем список селекторов для обновления
|
|
202
|
+
const subscriptionsToUpdate = Array.from(this.pendingUpdates);
|
|
203
|
+
this.pendingUpdates.clear();
|
|
204
|
+
// Обновляем все ожидающие селекторы синхронно
|
|
205
|
+
for (const id of subscriptionsToUpdate){
|
|
206
|
+
const subscription = this.subscriptions.get(id);
|
|
207
|
+
if (subscription) {
|
|
208
|
+
try {
|
|
209
|
+
subscription.notify();
|
|
210
|
+
} catch (error) {
|
|
211
|
+
this.logger?.error(`Ошибка уведомления подписчика ${id}`, {
|
|
212
|
+
error
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
this.logger?.error('Ошибка обработки ожидающих обновлений', {
|
|
219
|
+
error
|
|
220
|
+
});
|
|
221
|
+
} finally{
|
|
222
|
+
this.batchUpdateInProgress = false;
|
|
223
|
+
// Если появились новые обновления во время обработки, запускаем процесс снова
|
|
224
|
+
if (this.pendingUpdates.size > 0) {
|
|
225
|
+
this.processPendingUpdates();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
createSelector(selectorOrDeps, resultFnOrOptions, optionsArg) {
|
|
230
|
+
// Определяем, какую перегрузку используем
|
|
231
|
+
const isSimpleSelector = !Array.isArray(selectorOrDeps);
|
|
232
|
+
// Извлекаем options
|
|
233
|
+
const options = isSimpleSelector ? resultFnOrOptions || {} : optionsArg || {};
|
|
234
|
+
const hasExplicitName = !!options.name;
|
|
235
|
+
// Используем предоставленное имя или генерируем уникальный ID
|
|
236
|
+
const selectorId = options.name || this.generateName();
|
|
237
|
+
// Кеширование по имени — только для явно именованных селекторов
|
|
238
|
+
if (hasExplicitName && this.localSelectorCache.has(selectorId)) {
|
|
239
|
+
return this.localSelectorCache.get(selectorId).api;
|
|
240
|
+
}
|
|
241
|
+
// Создаем новый селектор
|
|
242
|
+
let result;
|
|
243
|
+
let dependencies;
|
|
244
|
+
let unsubscribeFunctions = [];
|
|
245
|
+
if (isSimpleSelector) {
|
|
246
|
+
// Простой селектор с мемоизацией и трекингом зависимостей
|
|
247
|
+
const { memoized, getTrackedKeys } = memoizeSelector(selectorOrDeps, options.equals || defaultEquals);
|
|
248
|
+
const created = this.createSimpleSelector(memoized, getTrackedKeys, {
|
|
249
|
+
...options,
|
|
250
|
+
name: selectorId,
|
|
251
|
+
equals: options.equals || defaultEquals
|
|
252
|
+
});
|
|
253
|
+
result = created.api;
|
|
254
|
+
unsubscribeFunctions = created.unsubscribeFunctions;
|
|
255
|
+
} else {
|
|
256
|
+
// Комбинированный селектор
|
|
257
|
+
dependencies = selectorOrDeps;
|
|
258
|
+
const created = this.createCombinedSelector(dependencies, resultFnOrOptions, {
|
|
259
|
+
...options,
|
|
260
|
+
name: selectorId,
|
|
261
|
+
equals: options.equals || defaultEquals
|
|
262
|
+
});
|
|
263
|
+
result = created.api;
|
|
264
|
+
unsubscribeFunctions = created.unsubscribeFunctions;
|
|
265
|
+
}
|
|
266
|
+
// Сохраняем в кеши
|
|
267
|
+
this.localSelectorCache.set(selectorId, {
|
|
268
|
+
api: result,
|
|
269
|
+
dependencies,
|
|
270
|
+
unsubscribeFunctions
|
|
271
|
+
});
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
createSimpleSelector(selector, getTrackedKeys, options) {
|
|
275
|
+
// Синхронное получение состояния из кеша
|
|
276
|
+
const getState = ()=>{
|
|
277
|
+
const state = this.source.getStateSync();
|
|
278
|
+
return selector(state);
|
|
279
|
+
};
|
|
280
|
+
const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger);
|
|
281
|
+
const id = subscription.getId();
|
|
282
|
+
this.subscriptions.set(id, subscription);
|
|
283
|
+
// Подписка на обновления хранилища с фильтрацией по changedPaths
|
|
284
|
+
const unsubscribeFromStorage = this.source.subscribeToAll((event)=>{
|
|
285
|
+
if (event?.type === 'storage:update') {
|
|
286
|
+
// Фильтруем по changedPaths: если зависимости известны и нет пересечения — пропускаем
|
|
287
|
+
const changedPaths = event?.changedPaths;
|
|
288
|
+
const deps = getTrackedKeys();
|
|
289
|
+
if (changedPaths && deps && deps.size > 0) {
|
|
290
|
+
const hasRelevantChange = changedPaths.some((path)=>{
|
|
291
|
+
// changedPaths может содержать вложенные пути ("users.0.name")
|
|
292
|
+
// берём ключ верхнего уровня для сравнения с deps
|
|
293
|
+
const topLevelKey = path.split('.')[0];
|
|
294
|
+
return deps.has(topLevelKey);
|
|
295
|
+
});
|
|
296
|
+
if (!hasRelevantChange) return;
|
|
297
|
+
}
|
|
298
|
+
this.pendingUpdates.add(id);
|
|
299
|
+
this.processPendingUpdates();
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
const unsubscribeFunctions = [
|
|
303
|
+
unsubscribeFromStorage
|
|
304
|
+
];
|
|
305
|
+
return {
|
|
306
|
+
api: {
|
|
307
|
+
select: ()=>getState(),
|
|
308
|
+
selectSync: ()=>subscription.getValue(),
|
|
309
|
+
subscribe: (subscriber)=>{
|
|
310
|
+
return subscription.subscribe(subscriber);
|
|
311
|
+
},
|
|
312
|
+
getId: ()=>id,
|
|
313
|
+
isSourceReady: this.isSourceReady,
|
|
314
|
+
onSourceStatusChange: this.onSourceStatusChange
|
|
315
|
+
},
|
|
316
|
+
unsubscribeFunctions
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
createCombinedSelector(selectors, resultFn, options) {
|
|
320
|
+
// Мемоизация для combined selectors: поэлементное сравнение аргументов по ссылке (как reselect)
|
|
321
|
+
let lastArgs;
|
|
322
|
+
let lastResult;
|
|
323
|
+
let hasResult = false;
|
|
324
|
+
const equals = options.equals || defaultEquals;
|
|
325
|
+
const memoizedResultFn = (args)=>{
|
|
326
|
+
// Проверяем, изменился ли хотя бы один аргумент
|
|
327
|
+
if (hasResult && lastArgs && lastArgs.length === args.length) {
|
|
328
|
+
let argsEqual = true;
|
|
329
|
+
for(let i = 0; i < args.length; i++){
|
|
330
|
+
if (lastArgs[i] !== args[i]) {
|
|
331
|
+
argsEqual = false;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (argsEqual) return lastResult;
|
|
336
|
+
}
|
|
337
|
+
const newResult = resultFn(...args);
|
|
338
|
+
// Сохраняем аргументы без создания нового массива — переиспользуем переданный
|
|
339
|
+
lastArgs = args;
|
|
340
|
+
if (!hasResult || !equals(newResult, lastResult)) {
|
|
341
|
+
lastResult = newResult;
|
|
342
|
+
}
|
|
343
|
+
hasResult = true;
|
|
344
|
+
return lastResult;
|
|
345
|
+
};
|
|
346
|
+
const getState = ()=>{
|
|
347
|
+
const values = selectors.map((s)=>s.selectSync());
|
|
348
|
+
return memoizedResultFn(values);
|
|
349
|
+
};
|
|
350
|
+
const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger);
|
|
351
|
+
const id = subscription.getId();
|
|
352
|
+
this.subscriptions.set(id, subscription);
|
|
353
|
+
// Батчинг обновлений через microtask — без искусственной задержки
|
|
354
|
+
let pendingNotify = false;
|
|
355
|
+
let destroyed = false;
|
|
356
|
+
const triggerUpdate = ()=>{
|
|
357
|
+
if (!pendingNotify) {
|
|
358
|
+
pendingNotify = true;
|
|
359
|
+
queueMicrotask(()=>{
|
|
360
|
+
pendingNotify = false;
|
|
361
|
+
if (!destroyed) {
|
|
362
|
+
try {
|
|
363
|
+
subscription.notify();
|
|
364
|
+
} catch (error) {
|
|
365
|
+
this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, {
|
|
366
|
+
error
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
const unsubscribeFunctions = selectors.map((selector)=>selector.subscribe({
|
|
374
|
+
notify: ()=>{
|
|
375
|
+
triggerUpdate();
|
|
376
|
+
}
|
|
377
|
+
}));
|
|
378
|
+
// При уничтожении предотвращаем выполнение отложенного microtask
|
|
379
|
+
unsubscribeFunctions.push(()=>{
|
|
380
|
+
destroyed = true;
|
|
381
|
+
});
|
|
382
|
+
return {
|
|
383
|
+
api: {
|
|
384
|
+
select: ()=>getState(),
|
|
385
|
+
selectSync: ()=>subscription.getValue(),
|
|
386
|
+
subscribe: (subscriber)=>{
|
|
387
|
+
return subscription.subscribe(subscriber);
|
|
388
|
+
},
|
|
389
|
+
getId: ()=>id,
|
|
390
|
+
isSourceReady: this.isSourceReady,
|
|
391
|
+
onSourceStatusChange: this.onSourceStatusChange
|
|
392
|
+
},
|
|
393
|
+
unsubscribeFunctions
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
destroy() {
|
|
397
|
+
// Очищаем все подписки
|
|
398
|
+
this.subscriptions.forEach((sub)=>sub.cleanup());
|
|
399
|
+
this.subscriptions.clear();
|
|
400
|
+
// Очищаем список ожидающих обновлений
|
|
401
|
+
this.pendingUpdates.clear();
|
|
402
|
+
// Очищаем подписки из локального кеша
|
|
403
|
+
this.localSelectorCache.forEach((cached)=>{
|
|
404
|
+
cached.unsubscribeFunctions.forEach((unsub)=>unsub());
|
|
405
|
+
});
|
|
406
|
+
this.localSelectorCache.clear();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export { SelectorModule, deepEquals };
|
|
411
|
+
|
|
412
|
+
//# sourceMappingURL=selector.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core/selector/selector.module.js","sources":["../../../src/core/selector/selector.module.ts"],"sourcesContent":["import type { ILogger, IStorage, StorageInitStatus } from '../storage'\nimport { StorageStatus } from '../storage'\nimport type { ISelectorModule, Selector, SelectorAPI, SelectorOptions, Subscriber } from './selector.interface'\n\n/**\n * Reference equality (===) — поведение по умолчанию\n */\nfunction defaultEquals<T>(a: T, b: T): boolean {\n return a === b\n}\n\nconst MAX_DEEP_EQUAL_DEPTH = 10\n\n/**\n * Глубокое сравнение объектов по структуре с защитой от циклических ссылок и лимитом глубины.\n * Используется только при явной передаче через options.equals.\n */\nexport function deepEquals<T>(a: T, b: T, depth = 0, visited = new WeakSet()): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n if (depth > MAX_DEEP_EQUAL_DEPTH) return false\n\n if (typeof a !== 'object') return a === b\n\n // Защита от циклических ссылок\n if (visited.has(a as object)) return false\n visited.add(a as object)\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!deepEquals(a[i], b[i], depth + 1, visited)) return false\n }\n return true\n }\n\n if (Array.isArray(a) || Array.isArray(b)) return false\n\n const keysA = Object.keys(a as object)\n const keysB = Object.keys(b as object)\n\n if (keysA.length !== keysB.length) return false\n\n return keysA.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false\n return deepEquals((a as any)[key], (b as any)[key], depth + 1, visited)\n })\n}\n\n/**\n * Оборачивает state в Proxy для отслеживания обращений к ключам верхнего уровня.\n * Возвращает проксированный state и Set с именами ключей, к которым обратился селектор.\n */\nfunction trackDependencies<S extends Record<string, any>>(state: S): { proxy: S; accessedKeys: Set<string> } {\n const accessedKeys = new Set<string>()\n\n const proxy = new Proxy(state, {\n get(target, prop, receiver) {\n if (typeof prop === 'string') {\n accessedKeys.add(prop)\n }\n return Reflect.get(target, prop, receiver)\n },\n })\n\n return { proxy, accessedKeys }\n}\n\n// Мемоизирует функцию селектора для оптимизации + трекинг зависимостей через Proxy\nfunction memoizeSelector<S extends Record<string, any>, R>(\n selectorFn: (state: S) => R,\n equals: (a: R, b: R) => boolean = defaultEquals,\n): { memoized: (state: S) => R; getTrackedKeys: () => Set<string> | null } {\n let lastState: S | undefined\n let lastResult: R | undefined\n let hasResult = false\n let trackedKeys: Set<string> | null = null\n\n const memoized = function (state: S): R {\n // Если это первый вызов или состояние изменилось\n if (!hasResult || lastState !== state) {\n // Трекаем зависимости через Proxy при каждом реальном пересчёте\n const { proxy, accessedKeys } = trackDependencies(state)\n const newResult = selectorFn(proxy)\n trackedKeys = accessedKeys\n\n // Проверяем, изменился ли результат\n if (!hasResult || !equals(newResult, lastResult as R)) {\n lastResult = newResult\n }\n\n lastState = state\n hasResult = true\n }\n\n return lastResult as R\n }\n\n return { memoized, getTrackedKeys: () => trackedKeys }\n}\n\nclass SelectorSubscription<T> {\n private readonly id: string\n readonly subscribers = new Set<Subscriber<T>>()\n private lastValue?: T\n private hasValue = false\n\n constructor(\n private readonly name: string,\n private readonly getState: () => T,\n private readonly equals: (a: T, b: T) => boolean = defaultEquals,\n private readonly logger?: ILogger,\n ) {\n this.id = name\n this.logger?.debug(`[${this.id}] SelectorSubscription created`)\n }\n\n notify(): void {\n try {\n const newValue = this.getState()\n\n // Проверка на изменение значения с использованием функции сравнения\n if (!this.hasValue || !this.equals(newValue, this.lastValue as T)) {\n this.logger?.debug(`[${this.id}] Value changed, notify()`)\n\n this.lastValue = newValue\n this.hasValue = true\n\n for (const subscriber of this.subscribers) {\n try {\n subscriber.notify(newValue)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в уведомлении подписчика`, { error })\n }\n }\n }\n } catch (error: any) {\n this.logger?.error(`[${this.id}] Ошибка в notify()`, { error })\n throw error\n }\n }\n\n subscribe(subscriber: Subscriber<T>): VoidFunction {\n this.subscribers.add(subscriber)\n\n // Отправляем текущее значение синхронно\n if (this.hasValue) {\n try {\n subscriber.notify(this.lastValue as T)\n } catch (error) {\n this.logger?.error(`[${this.id}] Ошибка в первоначальном уведомлении`, { error })\n }\n } else {\n // Вычисляем значение синхронно\n this.notify()\n }\n\n return () => {\n this.subscribers.delete(subscriber)\n }\n }\n\n cleanup(): void {\n this.subscribers.clear()\n this.lastValue = undefined\n this.hasValue = false\n }\n\n getLastValue(): T | undefined {\n return this.lastValue\n }\n\n getValue(): T {\n if (!this.hasValue) {\n this.lastValue = this.getState()\n this.hasValue = true\n }\n return this.lastValue as T\n }\n\n getId(): string {\n return this.id\n }\n}\n\nexport class SelectorModule<S extends Record<string, any>> implements ISelectorModule<S> {\n storageName: string\n\n private selectorIdCounter = 0\n private subscriptions = new Map<string, SelectorSubscription<any>>()\n\n private localSelectorCache = new Map<\n string,\n {\n api: SelectorAPI<any>\n dependencies?: SelectorAPI<any>[]\n unsubscribeFunctions: Array<() => void>\n }\n >()\n\n // Флаг для батчинга обновлений\n private batchUpdateInProgress = false\n private pendingUpdates = new Set<string>()\n\n constructor(\n private readonly source: IStorage<S>,\n private readonly logger?: ILogger,\n ) {\n this.storageName = source.name\n }\n\n private isSourceReady = (): boolean => {\n return this.source.initStatus.status === StorageStatus.READY\n }\n\n private onSourceStatusChange = (callback: (isReady: boolean) => void): VoidFunction => {\n return this.source.onStatusChange((status: StorageInitStatus) => {\n callback(status.status === StorageStatus.READY)\n })\n }\n\n /**\n * Генерирует уникальное имя для селектора через автоинкрементный счётчик\n */\n private generateName(): string {\n return `${this.storageName}_selector_${this.selectorIdCounter++}`\n }\n\n /**\n * Обрабатывает отложенные обновления синхронно\n */\n private processPendingUpdates(): void {\n if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return\n\n this.batchUpdateInProgress = true\n\n try {\n // Копируем список селекторов для обновления\n const subscriptionsToUpdate = Array.from(this.pendingUpdates)\n this.pendingUpdates.clear()\n\n // Обновляем все ожидающие селекторы синхронно\n for (const id of subscriptionsToUpdate) {\n const subscription = this.subscriptions.get(id)\n if (subscription) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`Ошибка уведомления подписчика ${id}`, { error })\n }\n }\n }\n } catch (error) {\n this.logger?.error('Ошибка обработки ожидающих обновлений', { error })\n } finally {\n this.batchUpdateInProgress = false\n\n // Если появились новые обновления во время обработки, запускаем процесс снова\n if (this.pendingUpdates.size > 0) {\n this.processPendingUpdates()\n }\n }\n }\n\n createSelector<T>(selector: Selector<S, T>, options?: SelectorOptions<T>): SelectorAPI<T>\n createSelector<Deps extends unknown[], T>(dependencies: { [K in keyof Deps]: SelectorAPI<Deps[K]> }, resultFn: (...args: Deps) => T, options?: SelectorOptions<T>): SelectorAPI<T>\n\n createSelector<T>(\n selectorOrDeps: Selector<S, T> | SelectorAPI<any>[],\n resultFnOrOptions?: ((...args: any[]) => T) | SelectorOptions<T>,\n optionsArg?: SelectorOptions<T>,\n ): SelectorAPI<T> {\n // Определяем, какую перегрузку используем\n const isSimpleSelector = !Array.isArray(selectorOrDeps)\n\n // Извлекаем options\n const options = isSimpleSelector ? (resultFnOrOptions as SelectorOptions<T>) || {} : optionsArg || {}\n\n const hasExplicitName = !!options.name\n\n // Используем предоставленное имя или генерируем уникальный ID\n const selectorId = options.name || this.generateName()\n\n // Кеширование по имени — только для явно именованных селекторов\n if (hasExplicitName && this.localSelectorCache.has(selectorId)) {\n return this.localSelectorCache.get(selectorId)!.api\n }\n\n // Создаем новый селектор\n let result: SelectorAPI<T>\n let dependencies: SelectorAPI<any>[] | undefined\n let unsubscribeFunctions: VoidFunction[] = []\n\n if (isSimpleSelector) {\n // Простой селектор с мемоизацией и трекингом зависимостей\n const { memoized, getTrackedKeys } = memoizeSelector(selectorOrDeps as Selector<S, T>, options.equals || defaultEquals)\n\n const created = this.createSimpleSelector(memoized, getTrackedKeys, { ...options, name: selectorId, equals: options.equals || defaultEquals })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n } else {\n // Комбинированный селектор\n dependencies = selectorOrDeps as SelectorAPI<any>[]\n\n const created = this.createCombinedSelector(dependencies, resultFnOrOptions as (...args: any[]) => T, {\n ...options,\n name: selectorId,\n equals: options.equals || defaultEquals,\n })\n\n result = created.api\n unsubscribeFunctions = created.unsubscribeFunctions\n }\n\n // Сохраняем в кеши\n this.localSelectorCache.set(selectorId, {\n api: result,\n dependencies,\n unsubscribeFunctions,\n })\n\n return result\n }\n\n private createSimpleSelector<T>(\n selector: Selector<S, T>,\n getTrackedKeys: () => Set<string> | null,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: VoidFunction[]\n } {\n // Синхронное получение состояния из кеша\n const getState = (): T => {\n const state = this.source.getStateSync()\n return selector(state as S)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Подписка на обновления хранилища с фильтрацией по changedPaths\n const unsubscribeFromStorage = this.source.subscribeToAll((event: any) => {\n if (event?.type === 'storage:update') {\n // Фильтруем по changedPaths: если зависимости известны и нет пересечения — пропускаем\n const changedPaths: string[] | undefined = event?.changedPaths\n const deps = getTrackedKeys()\n\n if (changedPaths && deps && deps.size > 0) {\n const hasRelevantChange = changedPaths.some((path) => {\n // changedPaths может содержать вложенные пути (\"users.0.name\")\n // берём ключ верхнего уровня для сравнения с deps\n const topLevelKey = path.split('.')[0]\n return deps.has(topLevelKey)\n })\n if (!hasRelevantChange) return\n }\n\n this.pendingUpdates.add(id)\n this.processPendingUpdates()\n }\n })\n\n const unsubscribeFunctions = [unsubscribeFromStorage]\n\n return {\n api: {\n select: () => getState(),\n selectSync: () => subscription.getValue(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n isSourceReady: this.isSourceReady,\n onSourceStatusChange: this.onSourceStatusChange,\n },\n unsubscribeFunctions,\n }\n }\n\n private createCombinedSelector<Deps extends unknown[], T>(\n selectors: { [K in keyof Deps]: SelectorAPI<Deps[K]> },\n resultFn: (...args: Deps) => T,\n options: SelectorOptions<T> & { name: string },\n ): {\n api: SelectorAPI<T>\n unsubscribeFunctions: Array<VoidFunction>\n } {\n // Мемоизация для combined selectors: поэлементное сравнение аргументов по ссылке (как reselect)\n let lastArgs: Deps | undefined\n let lastResult: T | undefined\n let hasResult = false\n const equals = options.equals || defaultEquals\n\n const memoizedResultFn = (args: Deps): T => {\n // Проверяем, изменился ли хотя бы один аргумент\n if (hasResult && lastArgs && lastArgs.length === args.length) {\n let argsEqual = true\n for (let i = 0; i < args.length; i++) {\n if (lastArgs[i] !== args[i]) {\n argsEqual = false\n break\n }\n }\n if (argsEqual) return lastResult as T\n }\n\n const newResult = resultFn(...args)\n\n // Сохраняем аргументы без создания нового массива — переиспользуем переданный\n lastArgs = args\n\n if (!hasResult || !equals(newResult, lastResult as T)) {\n lastResult = newResult\n }\n\n hasResult = true\n return lastResult as T\n }\n\n const getState = (): T => {\n const values = selectors.map((s) => s.selectSync()) as Deps\n return memoizedResultFn(values)\n }\n\n const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger)\n\n const id = subscription.getId()\n this.subscriptions.set(id, subscription)\n\n // Батчинг обновлений через microtask — без искусственной задержки\n let pendingNotify = false\n let destroyed = false\n\n const triggerUpdate = () => {\n if (!pendingNotify) {\n pendingNotify = true\n queueMicrotask(() => {\n pendingNotify = false\n if (!destroyed) {\n try {\n subscription.notify()\n } catch (error) {\n this.logger?.error(`[${id}] Ошибка в объединенном уведомлении:`, { error })\n }\n }\n })\n }\n }\n\n const unsubscribeFunctions: Array<VoidFunction> = selectors.map((selector) =>\n selector.subscribe({\n notify: () => {\n triggerUpdate()\n },\n }),\n )\n\n // При уничтожении предотвращаем выполнение отложенного microtask\n unsubscribeFunctions.push(() => {\n destroyed = true\n })\n\n return {\n api: {\n select: () => getState(),\n selectSync: () => subscription.getValue(),\n subscribe: (subscriber) => {\n return subscription.subscribe(subscriber)\n },\n getId: () => id,\n isSourceReady: this.isSourceReady,\n onSourceStatusChange: this.onSourceStatusChange,\n },\n unsubscribeFunctions,\n }\n }\n\n destroy(): void {\n // Очищаем все подписки\n this.subscriptions.forEach((sub) => sub.cleanup())\n this.subscriptions.clear()\n\n // Очищаем список ожидающих обновлений\n this.pendingUpdates.clear()\n\n // Очищаем подписки из локального кеша\n this.localSelectorCache.forEach((cached) => {\n cached.unsubscribeFunctions.forEach((unsub) => unsub())\n })\n this.localSelectorCache.clear()\n }\n}\n"],"names":["StorageStatus","defaultEquals","a","b","MAX_DEEP_EQUAL_DEPTH","deepEquals","depth","visited","WeakSet","Date","Array","i","keysA","Object","keysB","key","trackDependencies","state","accessedKeys","Set","proxy","Proxy","target","prop","receiver","Reflect","memoizeSelector","selectorFn","equals","lastState","lastResult","hasResult","trackedKeys","memoized","newResult","SelectorSubscription","name","getState","logger","newValue","subscriber","error","undefined","SelectorModule","Map","source","callback","status","subscriptionsToUpdate","id","subscription","selectorOrDeps","resultFnOrOptions","optionsArg","isSimpleSelector","options","hasExplicitName","selectorId","result","dependencies","unsubscribeFunctions","getTrackedKeys","created","selector","unsubscribeFromStorage","event","changedPaths","deps","hasRelevantChange","path","topLevelKey","selectors","resultFn","lastArgs","memoizedResultFn","args","argsEqual","values","s","pendingNotify","destroyed","triggerUpdate","queueMicrotask","sub","cached","unsub"],"mappings":"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"}
|