synapse-storage 4.1.2 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -12
- package/dist/_utils/chunk.util.d.ts +0 -1
- package/dist/_utils/deepMerge.util.d.ts +0 -1
- package/dist/_utils/error-handling.util.d.ts +0 -1
- package/dist/_utils/flatMap.util.d.ts +0 -1
- package/dist/_utils/index.d.ts +0 -1
- package/dist/_utils/logger-console.util.d.ts +0 -1
- package/dist/api/api.module.d.ts +0 -1
- package/dist/api/components/endpoint.d.ts +11 -12
- package/dist/api/components/endpoint.js.map +1 -1
- package/dist/api/components/query-storage.d.ts +0 -1
- package/dist/api/components/query-storage.js +1 -1
- package/dist/api/components/query-storage.js.map +1 -1
- package/dist/api/index.d.ts +0 -1
- package/dist/api/types/api.interface.d.ts +0 -1
- package/dist/api/types/endpoint.interface.d.ts +0 -1
- package/dist/api/types/query.interface.d.ts +0 -1
- package/dist/api/utils/api-helpers.d.ts +0 -1
- package/dist/{core/storage → api}/utils/cache.util.d.ts +3 -6
- package/dist/{core/storage → api}/utils/cache.util.js +4 -7
- package/dist/api/utils/cache.util.js.map +1 -0
- package/dist/api/utils/create-header-context.d.ts +0 -1
- package/dist/api/utils/endpoint-headers.d.ts +0 -1
- package/dist/api/utils/fetch-base-query.d.ts +0 -1
- package/dist/api/utils/file-utils.d.ts +0 -1
- package/dist/api/utils/get-cacheable-headers.d.ts +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/selector/index.d.ts +1 -1
- package/dist/core/selector/index.js +2 -0
- package/dist/core/selector/index.js.map +1 -1
- package/dist/core/selector/selector.interface.d.ts +15 -30
- package/dist/core/selector/selector.interface.js +2 -2
- package/dist/core/selector/selector.interface.js.map +1 -1
- package/dist/core/selector/selector.module.d.ts +16 -1
- package/dist/core/selector/selector.module.js +82 -20
- package/dist/core/selector/selector.module.js.map +1 -1
- package/dist/core/selector/selectors.base.d.ts +56 -0
- package/dist/core/selector/selectors.base.js +118 -0
- package/dist/core/selector/selectors.base.js.map +1 -0
- package/dist/core/storage/adapters/async-base-storage.service.d.ts +15 -4
- package/dist/core/storage/adapters/async-base-storage.service.js +106 -36
- package/dist/core/storage/adapters/async-base-storage.service.js.map +1 -1
- package/dist/core/storage/adapters/indexed-DB.service.d.ts +4 -5
- package/dist/core/storage/adapters/indexed-DB.service.js +66 -14
- package/dist/core/storage/adapters/indexed-DB.service.js.map +1 -1
- package/dist/core/storage/adapters/local-storage.service.d.ts +9 -4
- package/dist/core/storage/adapters/local-storage.service.js +25 -5
- package/dist/core/storage/adapters/local-storage.service.js.map +1 -1
- package/dist/core/storage/adapters/memory-storage.service.d.ts +2 -4
- package/dist/core/storage/adapters/memory-storage.service.js +5 -5
- package/dist/core/storage/adapters/memory-storage.service.js.map +1 -1
- package/dist/core/storage/adapters/path.utils.d.ts +0 -1
- package/dist/core/storage/adapters/storage-core.d.ts +6 -2
- package/dist/core/storage/adapters/storage-core.js +6 -3
- package/dist/core/storage/adapters/storage-core.js.map +1 -1
- package/dist/core/storage/adapters/sync-base-storage.service.d.ts +20 -4
- package/dist/core/storage/adapters/sync-base-storage.service.js +110 -35
- package/dist/core/storage/adapters/sync-base-storage.service.js.map +1 -1
- package/dist/core/storage/index.d.ts +2 -5
- package/dist/core/storage/index.js +1 -5
- package/dist/core/storage/index.js.map +1 -1
- package/dist/core/storage/middlewares/broadcast.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/index.d.ts +3 -1
- package/dist/core/storage/middlewares/index.js +6 -0
- package/dist/core/storage/middlewares/index.js.map +1 -1
- package/dist/core/storage/middlewares/storage-batching.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/storage-logger.middleware.d.ts +20 -0
- package/dist/core/storage/middlewares/storage-logger.middleware.js +53 -0
- package/dist/core/storage/middlewares/storage-logger.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js +4 -10
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.js.map +1 -1
- package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/sync-storage-logger.middleware.d.ts +7 -0
- package/dist/core/storage/middlewares/sync-storage-logger.middleware.js +48 -0
- package/dist/core/storage/middlewares/sync-storage-logger.middleware.js.map +1 -0
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts +0 -1
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js +4 -10
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.js.map +1 -1
- package/dist/core/storage/modules/singleton/mixin.util.d.ts +0 -1
- package/dist/core/storage/modules/singleton/models.d.ts +0 -1
- package/dist/core/storage/modules/singleton/singleton.util.d.ts +0 -1
- package/dist/core/storage/storage.interface.d.ts +59 -4
- package/dist/core/storage/storage.interface.js +0 -2
- package/dist/core/storage/storage.interface.js.map +1 -1
- package/dist/core/storage/utils/broadcast.util.d.ts +0 -1
- package/dist/core/storage/utils/middleware-module.d.ts +0 -3
- package/dist/core/storage/utils/middleware-module.js +0 -8
- package/dist/core/storage/utils/middleware-module.js.map +1 -1
- package/dist/core/storage/utils/migration.util.d.ts +38 -0
- package/dist/core/storage/utils/migration.util.js +48 -0
- package/dist/core/storage/utils/migration.util.js.map +1 -0
- package/dist/core/storage/utils/path-selector.util.d.ts +0 -1
- package/dist/core/storage/utils/state-diff.util.d.ts +8 -1
- package/dist/core/storage/utils/state-diff.util.js +17 -1
- package/dist/core/storage/utils/state-diff.util.js.map +1 -1
- package/dist/core/storage/utils/storage-factory.util.d.ts +7 -9
- package/dist/core/storage/utils/storage-factory.util.js +10 -10
- package/dist/core/storage/utils/storage-factory.util.js.map +1 -1
- package/dist/core/storage/utils/storage-key.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/react/hooks/index.d.ts +2 -1
- package/dist/react/hooks/index.js +4 -0
- package/dist/react/hooks/index.js.map +1 -1
- package/dist/react/hooks/useCreateStorage.d.ts +5 -6
- package/dist/react/hooks/useCreateStorage.js +2 -2
- package/dist/react/hooks/useCreateStorage.js.map +1 -1
- package/dist/react/hooks/useObservable.d.ts +17 -0
- package/dist/react/hooks/useObservable.js +38 -0
- package/dist/react/hooks/useObservable.js.map +1 -0
- package/dist/react/hooks/useSelector.d.ts +0 -1
- package/dist/react/hooks/useSelector.js +5 -2
- package/dist/react/hooks/useSelector.js.map +1 -1
- package/dist/react/hooks/useStorage.d.ts +0 -1
- package/dist/react/hooks/useStorageSubscribe.d.ts +0 -1
- package/dist/react/hooks/useSubscription.d.ts +13 -0
- package/dist/react/hooks/useSubscription.js +23 -0
- package/dist/react/hooks/useSubscription.js.map +1 -0
- package/dist/react/index.d.ts +0 -1
- package/dist/react/utils/awaitSynapse.d.ts +9 -10
- package/dist/react/utils/awaitSynapse.js +3 -2
- package/dist/react/utils/awaitSynapse.js.map +1 -1
- package/dist/react/utils/createSynapseCtx.d.ts +18 -23
- package/dist/react/utils/createSynapseCtx.js +64 -39
- package/dist/react/utils/createSynapseCtx.js.map +1 -1
- package/dist/react/utils/index.d.ts +0 -1
- package/dist/reactive/dispatcher/dispatcher.base.d.ts +122 -0
- package/dist/reactive/dispatcher/dispatcher.base.js +294 -0
- package/dist/reactive/dispatcher/dispatcher.base.js.map +1 -0
- package/dist/reactive/dispatcher/dispatcher.module.d.ts +12 -67
- package/dist/reactive/dispatcher/dispatcher.module.js +13 -72
- package/dist/reactive/dispatcher/dispatcher.module.js.map +1 -1
- package/dist/reactive/dispatcher/index.d.ts +1 -1
- package/dist/reactive/dispatcher/index.js +2 -0
- package/dist/reactive/dispatcher/index.js.map +1 -1
- package/dist/reactive/dispatcher/middlewares/index.d.ts +0 -1
- package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts +0 -1
- package/dist/reactive/dispatcher/path.util.d.ts +15 -0
- package/dist/reactive/dispatcher/path.util.js +34 -0
- package/dist/reactive/dispatcher/path.util.js.map +1 -0
- package/dist/reactive/dispatcher/standalone.d.ts +1 -150
- package/dist/reactive/dispatcher/standalone.js +6 -217
- package/dist/reactive/dispatcher/standalone.js.map +1 -1
- package/dist/reactive/effects/effects.base.d.ts +62 -0
- package/dist/reactive/effects/effects.base.js +90 -0
- package/dist/reactive/effects/effects.base.js.map +1 -0
- package/dist/reactive/effects/effects.module.d.ts +122 -11
- package/dist/reactive/effects/effects.module.js +129 -17
- package/dist/reactive/effects/effects.module.js.map +1 -1
- package/dist/reactive/effects/index.d.ts +1 -1
- package/dist/reactive/effects/index.js +2 -0
- package/dist/reactive/effects/index.js.map +1 -1
- package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts +0 -1
- package/dist/reactive/effects/utils/chunkRequestParallel.d.ts +0 -1
- package/dist/reactive/effects/utils/fromRequest.d.ts +0 -1
- package/dist/reactive/effects/utils/index.d.ts +0 -1
- package/dist/reactive/effects/utils/toObservable.d.ts +0 -1
- package/dist/reactive/index.d.ts +0 -1
- package/dist/utils/createEventBus.d.ts +47 -46
- package/dist/utils/createEventBus.js +152 -174
- package/dist/utils/createEventBus.js.map +1 -1
- package/dist/utils/createSynapse/createSynapse.d.ts +25 -7
- package/dist/utils/createSynapse/createSynapse.js +28 -98
- package/dist/utils/createSynapse/createSynapse.js.map +1 -1
- package/dist/utils/createSynapse/factory.d.ts +6 -0
- package/dist/utils/createSynapse/factory.js +256 -0
- package/dist/utils/createSynapse/factory.js.map +1 -0
- package/dist/utils/createSynapse/index.d.ts +2 -2
- package/dist/utils/createSynapse/index.js.map +1 -1
- package/dist/utils/createSynapse/synapse.types.d.ts +87 -0
- package/dist/utils/createSynapse/synapse.types.js +11 -0
- package/dist/utils/createSynapse/synapse.types.js.map +1 -0
- package/dist/utils/createSynapse/types.d.ts +6 -85
- package/dist/utils/createSynapse/types.js +2 -1
- package/dist/utils/createSynapse/types.js.map +1 -1
- package/dist/utils/createSynapse/waitForDependencies.d.ts +0 -1
- package/dist/utils/createSynapse/waitForDependencies.js +1 -1
- package/dist/utils/createSynapse/waitForDependencies.js.map +1 -1
- package/dist/utils/createSynapseAwaiter.d.ts +13 -10
- package/dist/utils/createSynapseAwaiter.js +30 -3
- package/dist/utils/createSynapseAwaiter.js.map +1 -1
- package/dist/utils/dehydrateModule.d.ts +6 -0
- package/dist/utils/dehydrateModule.js +43 -0
- package/dist/utils/dehydrateModule.js.map +1 -0
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +12 -2
- package/dist/_utils/chunk.util.d.ts.map +0 -1
- package/dist/_utils/deepMerge.util.d.ts.map +0 -1
- package/dist/_utils/error-handling.util.d.ts.map +0 -1
- package/dist/_utils/flatMap.util.d.ts.map +0 -1
- package/dist/_utils/index.d.ts.map +0 -1
- package/dist/_utils/logger-console.util.d.ts.map +0 -1
- package/dist/api/api.module.d.ts.map +0 -1
- package/dist/api/components/endpoint.d.ts.map +0 -1
- package/dist/api/components/query-storage.d.ts.map +0 -1
- package/dist/api/example.d.ts +0 -83
- package/dist/api/example.d.ts.map +0 -1
- package/dist/api/example.js +0 -90
- package/dist/api/example.js.map +0 -1
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/types/api.interface.d.ts.map +0 -1
- package/dist/api/types/endpoint.interface.d.ts.map +0 -1
- package/dist/api/types/query.interface.d.ts.map +0 -1
- package/dist/api/utils/api-helpers.d.ts.map +0 -1
- package/dist/api/utils/create-header-context.d.ts.map +0 -1
- package/dist/api/utils/endpoint-headers.d.ts.map +0 -1
- package/dist/api/utils/fetch-base-query.d.ts.map +0 -1
- package/dist/api/utils/file-utils.d.ts.map +0 -1
- package/dist/api/utils/get-cacheable-headers.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/selector/index.d.ts.map +0 -1
- package/dist/core/selector/selector.interface.d.ts.map +0 -1
- package/dist/core/selector/selector.module.d.ts.map +0 -1
- package/dist/core/storage/adapters/async-base-storage.service.d.ts.map +0 -1
- package/dist/core/storage/adapters/indexed-DB.service.d.ts.map +0 -1
- package/dist/core/storage/adapters/local-storage.service.d.ts.map +0 -1
- package/dist/core/storage/adapters/memory-storage.service.d.ts.map +0 -1
- package/dist/core/storage/adapters/path.utils.d.ts.map +0 -1
- package/dist/core/storage/adapters/storage-core.d.ts.map +0 -1
- package/dist/core/storage/adapters/sync-base-storage.service.d.ts.map +0 -1
- package/dist/core/storage/index.d.ts.map +0 -1
- package/dist/core/storage/middlewares/broadcast.middleware.d.ts.map +0 -1
- package/dist/core/storage/middlewares/index.d.ts.map +0 -1
- package/dist/core/storage/middlewares/storage-batching.middleware.d.ts.map +0 -1
- package/dist/core/storage/middlewares/storage-shallow-compare.middleware.d.ts.map +0 -1
- package/dist/core/storage/middlewares/sync-broadcast.middleware.d.ts.map +0 -1
- package/dist/core/storage/middlewares/sync-storage-batching.middleware.d.ts.map +0 -1
- package/dist/core/storage/middlewares/sync-storage-shallow-compare.middleware.d.ts.map +0 -1
- package/dist/core/storage/modules/plugin/plugin.interface.d.ts +0 -101
- package/dist/core/storage/modules/plugin/plugin.interface.d.ts.map +0 -1
- package/dist/core/storage/modules/plugin/plugin.interface.js +0 -8
- package/dist/core/storage/modules/plugin/plugin.interface.js.map +0 -1
- package/dist/core/storage/modules/plugin/plugin.service.d.ts +0 -49
- package/dist/core/storage/modules/plugin/plugin.service.d.ts.map +0 -1
- package/dist/core/storage/modules/plugin/plugin.service.js +0 -406
- package/dist/core/storage/modules/plugin/plugin.service.js.map +0 -1
- package/dist/core/storage/modules/singleton/mixin.util.d.ts.map +0 -1
- package/dist/core/storage/modules/singleton/models.d.ts.map +0 -1
- package/dist/core/storage/modules/singleton/singleton.util.d.ts.map +0 -1
- package/dist/core/storage/storage.interface.d.ts.map +0 -1
- package/dist/core/storage/utils/broadcast.util.d.ts.map +0 -1
- package/dist/core/storage/utils/cache.util.d.ts.map +0 -1
- package/dist/core/storage/utils/cache.util.js.map +0 -1
- package/dist/core/storage/utils/middleware-module.d.ts.map +0 -1
- package/dist/core/storage/utils/path-selector.util.d.ts.map +0 -1
- package/dist/core/storage/utils/state-diff.util.d.ts.map +0 -1
- package/dist/core/storage/utils/storage-factory.util.d.ts.map +0 -1
- package/dist/core/storage/utils/storage-key.d.ts.map +0 -1
- package/dist/core/storage/utils/storage.utils.d.ts +0 -17
- package/dist/core/storage/utils/storage.utils.d.ts.map +0 -1
- package/dist/core/storage/utils/storage.utils.js +0 -57
- package/dist/core/storage/utils/storage.utils.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/react/hooks/index.d.ts.map +0 -1
- package/dist/react/hooks/useCreateStorage.d.ts.map +0 -1
- package/dist/react/hooks/useSelector.d.ts.map +0 -1
- package/dist/react/hooks/useStorage.d.ts.map +0 -1
- package/dist/react/hooks/useStorageSubscribe.d.ts.map +0 -1
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/utils/awaitSynapse.d.ts.map +0 -1
- package/dist/react/utils/createSynapseCtx.d.ts.map +0 -1
- package/dist/react/utils/index.d.ts.map +0 -1
- package/dist/reactive/dispatcher/dispatcher.module.d.ts.map +0 -1
- package/dist/reactive/dispatcher/index.d.ts.map +0 -1
- package/dist/reactive/dispatcher/middlewares/index.d.ts.map +0 -1
- package/dist/reactive/dispatcher/middlewares/logger.middleware.d.ts.map +0 -1
- package/dist/reactive/dispatcher/standalone.d.ts.map +0 -1
- package/dist/reactive/effects/effects.module.d.ts.map +0 -1
- package/dist/reactive/effects/index.d.ts.map +0 -1
- package/dist/reactive/effects/utils/chunkRequestConsistent.d.ts.map +0 -1
- package/dist/reactive/effects/utils/chunkRequestParallel.d.ts.map +0 -1
- package/dist/reactive/effects/utils/fromRequest.d.ts.map +0 -1
- package/dist/reactive/effects/utils/index.d.ts.map +0 -1
- package/dist/reactive/effects/utils/toObservable.d.ts.map +0 -1
- package/dist/reactive/index.d.ts.map +0 -1
- package/dist/utils/createEventBus.d.ts.map +0 -1
- package/dist/utils/createSynapse/createSynapse.d.ts.map +0 -1
- package/dist/utils/createSynapse/index.d.ts.map +0 -1
- package/dist/utils/createSynapse/types.d.ts.map +0 -1
- package/dist/utils/createSynapse/validate.d.ts +0 -2
- package/dist/utils/createSynapse/validate.d.ts.map +0 -1
- package/dist/utils/createSynapse/validate.js +0 -76
- package/dist/utils/createSynapse/validate.js.map +0 -1
- package/dist/utils/createSynapse/waitForDependencies.d.ts.map +0 -1
- package/dist/utils/createSynapseAwaiter.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import type { IStorage } from '../../core';
|
|
3
|
+
import type { Action, DispatchFunction, EnhancedMiddleware, WatcherFunction } from './dispatcher.module';
|
|
4
|
+
import { type ApiRequestState } from './standalone';
|
|
5
|
+
/**
|
|
6
|
+
* Маркер метода финализации диспетчера.
|
|
7
|
+
*
|
|
8
|
+
* Имя экшена/вотчера берётся из имени поля класса, но прочитать имена полей можно
|
|
9
|
+
* только ПОСЛЕ полного конструирования инстанса (инициализаторы полей derived-класса
|
|
10
|
+
* выполняются после конструктора базового класса). Поэтому имена назначаются отдельным
|
|
11
|
+
* шагом-финализацией:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Сборщик `createSynapse(factory)`** вызывает `dispatcher[FINALIZE]()` до старта
|
|
14
|
+
* эффектов (эффекты читают `actionType` при сборке пайплайна).
|
|
15
|
+
* 2. **Ленивая само-финализация** — страховка для standalone-использования и тестов:
|
|
16
|
+
* первый dispatch экшена или первое обращение к реестру `dispatch`/`watchers`
|
|
17
|
+
* финализирует инстанс, если это ещё не сделано.
|
|
18
|
+
*/
|
|
19
|
+
export declare const FINALIZE: unique symbol;
|
|
20
|
+
/**
|
|
21
|
+
* Вызываемая группа жизненного цикла API-запроса.
|
|
22
|
+
*
|
|
23
|
+
* Сам вызов группы — это `init` (намерение): сбрасывает статус в `idle` и пробрасывает
|
|
24
|
+
* payload намерения дальше эффектам. Жизненный цикл — через методы-поля.
|
|
25
|
+
*
|
|
26
|
+
* `ofType(d.loadPosts)` ловит ТОЛЬКО init; чтобы среагировать на успех —
|
|
27
|
+
* `ofType(d.loadPosts.success)`.
|
|
28
|
+
*/
|
|
29
|
+
export interface ApiActions<TInitPayload = void> extends DispatchFunction<TInitPayload, TInitPayload> {
|
|
30
|
+
loading: DispatchFunction<void, void>;
|
|
31
|
+
success: DispatchFunction<void, void>;
|
|
32
|
+
failure: DispatchFunction<string, void>;
|
|
33
|
+
reset: DispatchFunction<void, void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Keyed-вариант: статус хранится по ключу. `init`/`loading`/`success`/`reset` принимают
|
|
37
|
+
* `key`, `failure` — `{ key, error }`.
|
|
38
|
+
*/
|
|
39
|
+
export interface KeyedApiActions<TInitPayload extends {
|
|
40
|
+
key: string;
|
|
41
|
+
} = {
|
|
42
|
+
key: string;
|
|
43
|
+
}> extends DispatchFunction<TInitPayload, TInitPayload> {
|
|
44
|
+
loading: DispatchFunction<string, string>;
|
|
45
|
+
success: DispatchFunction<string, string>;
|
|
46
|
+
failure: DispatchFunction<{
|
|
47
|
+
key: string;
|
|
48
|
+
error: string;
|
|
49
|
+
}, {
|
|
50
|
+
key: string;
|
|
51
|
+
error: string;
|
|
52
|
+
}>;
|
|
53
|
+
reset: DispatchFunction<string, string>;
|
|
54
|
+
}
|
|
55
|
+
/** Опции конструктора базового диспетчера. */
|
|
56
|
+
export interface DispatcherBaseOptions<TState extends Record<string, any>> {
|
|
57
|
+
middlewares?: EnhancedMiddleware<TState>[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Публичный class-based слой диспетчера. Экшены объявляются как поля класса через
|
|
61
|
+
* фабрики `this.action` / `this.signal` / `this.apiActions` / `this.keyedApiActions`
|
|
62
|
+
* / `this.watcher`. Имя экшена = имя поля.
|
|
63
|
+
*
|
|
64
|
+
* Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном
|
|
65
|
+
* namespace и НЕ конфликтуют с полями-экшенами подкласса. Запрещённые имена экшенов —
|
|
66
|
+
* только `protected`/публичная поверхность из `RESERVED_NAMES`.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* class PostsDispatcher extends Dispatcher<PostsState> {
|
|
71
|
+
* readonly loadPosts = this.apiActions<PostsFindAllParams>((s) => s.api.postsRequest)
|
|
72
|
+
* readonly mounted = this.signal<FeedLifecyclePayload>('Лента смонтирована')
|
|
73
|
+
* readonly applyPosts = this.action((store, page: PostsFeedResponseDto) =>
|
|
74
|
+
* store.update((s) => { s.list = page.data }))
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare abstract class Dispatcher<TState extends Record<string, any>> {
|
|
79
|
+
#private;
|
|
80
|
+
protected readonly storage: IStorage<TState>;
|
|
81
|
+
/** Поток всех экшенов модуля (его потребляет EffectsModule). */
|
|
82
|
+
readonly action$: Observable<Action>;
|
|
83
|
+
constructor(storage: IStorage<TState>, options?: DispatcherBaseOptions<TState>);
|
|
84
|
+
/** Реестр экшенов по имени — для middleware/devtools. */
|
|
85
|
+
get dispatch(): Record<string, DispatchFunction<any, any>>;
|
|
86
|
+
get watchers(): Record<string, WatcherFunction<any>>;
|
|
87
|
+
/** Алиас потока экшенов для совместимости с EffectsModule (`dispatcher.actions`). */
|
|
88
|
+
get actions(): Observable<Action>;
|
|
89
|
+
/**
|
|
90
|
+
* Экшен: handler в «рецептной» сигнатуре `(storage, params) => result`.
|
|
91
|
+
* payload экшена = возвращаемое значение handler'а.
|
|
92
|
+
*/
|
|
93
|
+
protected action<TParams = void, TResult = void>(handler: (storage: IStorage<TState>, params: TParams) => TResult | Promise<TResult>, options?: {
|
|
94
|
+
type?: string;
|
|
95
|
+
meta?: Record<string, any>;
|
|
96
|
+
memoize?: (cur: TParams, prev: TParams, prevResult: TResult) => boolean;
|
|
97
|
+
}): DispatchFunction<TParams, TResult>;
|
|
98
|
+
/** Чистый сигнал: `(_store, p) => p`. `description` уходит в meta. */
|
|
99
|
+
protected signal<TPayload = void>(description?: string): DispatchFunction<TPayload, TPayload>;
|
|
100
|
+
/** Вызываемая группа жизненного цикла API-запроса. Сам вызов = init (намерение). */
|
|
101
|
+
protected apiActions<TInitPayload = void>(accessor: (state: TState) => ApiRequestState): ApiActions<TInitPayload>;
|
|
102
|
+
/** То же для статусов по ключу (`Record<string, ApiRequestState>`). */
|
|
103
|
+
protected keyedApiActions<TInitPayload extends {
|
|
104
|
+
key: string;
|
|
105
|
+
} = {
|
|
106
|
+
key: string;
|
|
107
|
+
}>(accessor: (state: TState) => Record<string, ApiRequestState>): KeyedApiActions<TInitPayload>;
|
|
108
|
+
protected watcher<R>(config: {
|
|
109
|
+
selector: (state: TState) => R;
|
|
110
|
+
shouldTrigger?: (prev: R | undefined, current: R) => boolean;
|
|
111
|
+
notifyAfterSubscribe?: boolean;
|
|
112
|
+
type?: string;
|
|
113
|
+
meta?: Record<string, any>;
|
|
114
|
+
}): WatcherFunction<R>;
|
|
115
|
+
use(...middlewares: EnhancedMiddleware<TState>[]): this;
|
|
116
|
+
destroy(): void;
|
|
117
|
+
/**
|
|
118
|
+
* Финализация: скан own enumerable полей, назначение имён (`_assignType(имя поля)`)
|
|
119
|
+
* и регистрация в реестрах `dispatch`/`watchers`. Идемпотентна.
|
|
120
|
+
*/
|
|
121
|
+
[FINALIZE](): void;
|
|
122
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { DispatcherCore } from "./dispatcher.module.js";
|
|
2
|
+
import { resolvePath, setByPath } from "./path.util.js";
|
|
3
|
+
import { ApiStatus } from "./standalone.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Маркер метода финализации диспетчера.
|
|
13
|
+
*
|
|
14
|
+
* Имя экшена/вотчера берётся из имени поля класса, но прочитать имена полей можно
|
|
15
|
+
* только ПОСЛЕ полного конструирования инстанса (инициализаторы полей derived-класса
|
|
16
|
+
* выполняются после конструктора базового класса). Поэтому имена назначаются отдельным
|
|
17
|
+
* шагом-финализацией:
|
|
18
|
+
*
|
|
19
|
+
* 1. **Сборщик `createSynapse(factory)`** вызывает `dispatcher[FINALIZE]()` до старта
|
|
20
|
+
* эффектов (эффекты читают `actionType` при сборке пайплайна).
|
|
21
|
+
* 2. **Ленивая само-финализация** — страховка для standalone-использования и тестов:
|
|
22
|
+
* первый dispatch экшена или первое обращение к реестру `dispatch`/`watchers`
|
|
23
|
+
* финализирует инстанс, если это ещё не сделано.
|
|
24
|
+
*/ const FINALIZE = Symbol('synapse.dispatcher.finalize');
|
|
25
|
+
/** Имена членов базового класса, которые нельзя переопределять полями-экшенами. */ const RESERVED_NAMES = new Set([
|
|
26
|
+
'storage',
|
|
27
|
+
'action$',
|
|
28
|
+
'actions',
|
|
29
|
+
'dispatch',
|
|
30
|
+
'watchers',
|
|
31
|
+
'use',
|
|
32
|
+
'destroy'
|
|
33
|
+
]);
|
|
34
|
+
function isWrapper(value) {
|
|
35
|
+
return typeof value === 'function' && (value._type === 'dispatch' || value._type === 'watchers');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Публичный class-based слой диспетчера. Экшены объявляются как поля класса через
|
|
39
|
+
* фабрики `this.action` / `this.signal` / `this.apiActions` / `this.keyedApiActions`
|
|
40
|
+
* / `this.watcher`. Имя экшена = имя поля.
|
|
41
|
+
*
|
|
42
|
+
* Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном
|
|
43
|
+
* namespace и НЕ конфликтуют с полями-экшенами подкласса. Запрещённые имена экшенов —
|
|
44
|
+
* только `protected`/публичная поверхность из `RESERVED_NAMES`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* class PostsDispatcher extends Dispatcher<PostsState> {
|
|
49
|
+
* readonly loadPosts = this.apiActions<PostsFindAllParams>((s) => s.api.postsRequest)
|
|
50
|
+
* readonly mounted = this.signal<FeedLifecyclePayload>('Лента смонтирована')
|
|
51
|
+
* readonly applyPosts = this.action((store, page: PostsFeedResponseDto) =>
|
|
52
|
+
* store.update((s) => { s.list = page.data }))
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/ class Dispatcher {
|
|
56
|
+
storage;
|
|
57
|
+
/** Движок, поверх которого работает class-слой. */ #core;
|
|
58
|
+
/** Реестры по имени (наполняются при финализации). Делят ссылку с движком. */ #dispatch;
|
|
59
|
+
#watchers;
|
|
60
|
+
#finalized = false;
|
|
61
|
+
/** Поток всех экшенов модуля (его потребляет EffectsModule). */ action$;
|
|
62
|
+
constructor(storage, options){
|
|
63
|
+
this.storage = storage;
|
|
64
|
+
this.#core = new DispatcherCore({
|
|
65
|
+
storage,
|
|
66
|
+
middlewares: options?.middlewares
|
|
67
|
+
});
|
|
68
|
+
this.#dispatch = this.#core.dispatch;
|
|
69
|
+
this.#watchers = this.#core.watchers;
|
|
70
|
+
this.action$ = this.#core.actions;
|
|
71
|
+
}
|
|
72
|
+
// ── Публичные реестры: обращение к ним финализирует (страховка) ──────────────
|
|
73
|
+
/** Реестр экшенов по имени — для middleware/devtools. */ get dispatch() {
|
|
74
|
+
this.#ensureFinalized();
|
|
75
|
+
return this.#dispatch;
|
|
76
|
+
}
|
|
77
|
+
get watchers() {
|
|
78
|
+
this.#ensureFinalized();
|
|
79
|
+
return this.#watchers;
|
|
80
|
+
}
|
|
81
|
+
/** Алиас потока экшенов для совместимости с EffectsModule (`dispatcher.actions`). */ get actions() {
|
|
82
|
+
return this.action$;
|
|
83
|
+
}
|
|
84
|
+
// ── Фабрики для class fields ─────────────────────────────────────────────────
|
|
85
|
+
/**
|
|
86
|
+
* Экшен: handler в «рецептной» сигнатуре `(storage, params) => result`.
|
|
87
|
+
* payload экшена = возвращаемое значение handler'а.
|
|
88
|
+
*/ action(handler, options) {
|
|
89
|
+
const inner = this.#core.createAction({
|
|
90
|
+
type: options?.type,
|
|
91
|
+
meta: options?.meta,
|
|
92
|
+
action: (params)=>handler(this.storage, params)
|
|
93
|
+
}, options?.memoize ? {
|
|
94
|
+
memoize: options.memoize
|
|
95
|
+
} : undefined);
|
|
96
|
+
return this.#wrapDispatch(inner);
|
|
97
|
+
}
|
|
98
|
+
/** Чистый сигнал: `(_store, p) => p`. `description` уходит в meta. */ signal(description) {
|
|
99
|
+
return this.action((_storage, payload)=>payload, description ? {
|
|
100
|
+
meta: {
|
|
101
|
+
description
|
|
102
|
+
}
|
|
103
|
+
} : undefined);
|
|
104
|
+
}
|
|
105
|
+
/** Вызываемая группа жизненного цикла API-запроса. Сам вызов = init (намерение). */ apiActions(accessor) {
|
|
106
|
+
const path = resolvePath(accessor);
|
|
107
|
+
const write = (storage, request)=>storage.update((s)=>setByPath(s, path, request));
|
|
108
|
+
const init = this.action((storage, payload)=>{
|
|
109
|
+
write(storage, {
|
|
110
|
+
status: ApiStatus.Idle,
|
|
111
|
+
error: null
|
|
112
|
+
});
|
|
113
|
+
return payload;
|
|
114
|
+
});
|
|
115
|
+
init.loading = this.action((storage)=>write(storage, {
|
|
116
|
+
status: ApiStatus.Loading,
|
|
117
|
+
error: null
|
|
118
|
+
}));
|
|
119
|
+
init.success = this.action((storage)=>write(storage, {
|
|
120
|
+
status: ApiStatus.Success,
|
|
121
|
+
error: null
|
|
122
|
+
}));
|
|
123
|
+
init.failure = this.action((storage, error)=>write(storage, {
|
|
124
|
+
status: ApiStatus.Error,
|
|
125
|
+
error
|
|
126
|
+
}));
|
|
127
|
+
init.reset = this.action((storage)=>write(storage, {
|
|
128
|
+
status: ApiStatus.Reset,
|
|
129
|
+
error: null
|
|
130
|
+
}));
|
|
131
|
+
return this.#markApiGroup(init);
|
|
132
|
+
}
|
|
133
|
+
/** То же для статусов по ключу (`Record<string, ApiRequestState>`). */ keyedApiActions(accessor) {
|
|
134
|
+
const path = resolvePath(accessor);
|
|
135
|
+
const write = (storage, key, request)=>storage.update((s)=>setByPath(s, [
|
|
136
|
+
...path,
|
|
137
|
+
key
|
|
138
|
+
], request));
|
|
139
|
+
const init = this.action((storage, payload)=>{
|
|
140
|
+
write(storage, payload.key, {
|
|
141
|
+
status: ApiStatus.Idle,
|
|
142
|
+
error: null
|
|
143
|
+
});
|
|
144
|
+
return payload;
|
|
145
|
+
});
|
|
146
|
+
init.loading = this.action((storage, key)=>{
|
|
147
|
+
write(storage, key, {
|
|
148
|
+
status: ApiStatus.Loading,
|
|
149
|
+
error: null
|
|
150
|
+
});
|
|
151
|
+
return key;
|
|
152
|
+
});
|
|
153
|
+
init.success = this.action((storage, key)=>{
|
|
154
|
+
write(storage, key, {
|
|
155
|
+
status: ApiStatus.Success,
|
|
156
|
+
error: null
|
|
157
|
+
});
|
|
158
|
+
return key;
|
|
159
|
+
});
|
|
160
|
+
init.reset = this.action((storage, key)=>{
|
|
161
|
+
write(storage, key, {
|
|
162
|
+
status: ApiStatus.Reset,
|
|
163
|
+
error: null
|
|
164
|
+
});
|
|
165
|
+
return key;
|
|
166
|
+
});
|
|
167
|
+
init.failure = this.action((storage, payload)=>{
|
|
168
|
+
write(storage, payload.key, {
|
|
169
|
+
status: ApiStatus.Error,
|
|
170
|
+
error: payload.error
|
|
171
|
+
});
|
|
172
|
+
return payload;
|
|
173
|
+
});
|
|
174
|
+
return this.#markApiGroup(init);
|
|
175
|
+
}
|
|
176
|
+
watcher(config) {
|
|
177
|
+
const inner = this.#core.createWatcher(config);
|
|
178
|
+
return this.#wrapWatcher(inner);
|
|
179
|
+
}
|
|
180
|
+
// ── Жизненный цикл ───────────────────────────────────────────────────────────
|
|
181
|
+
use(...middlewares) {
|
|
182
|
+
this.#core.use(...middlewares);
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
destroy() {
|
|
186
|
+
// Движок отпишет вотчеры (реестр общий) и завершит action$.
|
|
187
|
+
this.#core.destroy();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Финализация: скан own enumerable полей, назначение имён (`_assignType(имя поля)`)
|
|
191
|
+
* и регистрация в реестрах `dispatch`/`watchers`. Идемпотентна.
|
|
192
|
+
*/ [FINALIZE]() {
|
|
193
|
+
if (this.#finalized) return;
|
|
194
|
+
this.#finalized = true;
|
|
195
|
+
// Для детекции полей-алиасов (одна функция под двумя именами).
|
|
196
|
+
const seen = new Map();
|
|
197
|
+
for (const [name, value] of Object.entries(this)){
|
|
198
|
+
if (!isWrapper(value)) continue;
|
|
199
|
+
if (RESERVED_NAMES.has(name)) {
|
|
200
|
+
throw new Error(`Dispatcher: поле "${name}" конфликтует с зарезервированным членом базового класса. Переименуйте экшен.`);
|
|
201
|
+
}
|
|
202
|
+
if (seen.has(value)) {
|
|
203
|
+
throw new Error(`Dispatcher: поле "${name}" является алиасом поля "${seen.get(value)}" — один экшен не может иметь два имени. Объявите отдельный экшен.`);
|
|
204
|
+
}
|
|
205
|
+
seen.set(value, name);
|
|
206
|
+
if (value._apiGroup) {
|
|
207
|
+
this.#finalizeApiGroup(name, value);
|
|
208
|
+
} else if (value._type === 'watchers') {
|
|
209
|
+
this.#finalizeNamed(name, value, this.#watchers);
|
|
210
|
+
} else {
|
|
211
|
+
this.#finalizeNamed(name, value, this.#dispatch);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// ── Внутреннее ───────────────────────────────────────────────────────────────
|
|
216
|
+
#ensureFinalized() {
|
|
217
|
+
if (!this.#finalized) this[FINALIZE]();
|
|
218
|
+
}
|
|
219
|
+
/** Назначает имя через `_assignType` (если тип не был задан явно) и регистрирует обёртку. */ #finalizeNamed(name, wrapper, registry) {
|
|
220
|
+
if (typeof wrapper._inner._assignType === 'function') {
|
|
221
|
+
wrapper._inner._assignType(name);
|
|
222
|
+
}
|
|
223
|
+
registry[name] = wrapper;
|
|
224
|
+
}
|
|
225
|
+
#finalizeApiGroup(name, init) {
|
|
226
|
+
this.#finalizeNamed(name, init, this.#dispatch);
|
|
227
|
+
const group = init._apiGroup;
|
|
228
|
+
this.#finalizeNamed(`${name}:loading`, group.loading, this.#dispatch);
|
|
229
|
+
this.#finalizeNamed(`${name}:success`, group.success, this.#dispatch);
|
|
230
|
+
this.#finalizeNamed(`${name}:failure`, group.failure, this.#dispatch);
|
|
231
|
+
this.#finalizeNamed(`${name}:reset`, group.reset, this.#dispatch);
|
|
232
|
+
}
|
|
233
|
+
#markApiGroup(init) {
|
|
234
|
+
const w = init;
|
|
235
|
+
w._apiGroup = {
|
|
236
|
+
loading: init.loading,
|
|
237
|
+
success: init.success,
|
|
238
|
+
failure: init.failure,
|
|
239
|
+
reset: init.reset
|
|
240
|
+
};
|
|
241
|
+
return init;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Оборачивает функцию-экшен движка: на первый вызов лениво финализирует диспетчер,
|
|
245
|
+
* затем делегирует. `actionType`/`meta` форвардятся «вживую» (значение появляется
|
|
246
|
+
* после `_assignType` при финализации).
|
|
247
|
+
*/ #wrapDispatch(inner) {
|
|
248
|
+
const wrapper = (params)=>{
|
|
249
|
+
this.#ensureFinalized();
|
|
250
|
+
return inner(params);
|
|
251
|
+
};
|
|
252
|
+
wrapper._type = 'dispatch';
|
|
253
|
+
wrapper._inner = inner;
|
|
254
|
+
Object.defineProperty(wrapper, 'actionType', {
|
|
255
|
+
get: ()=>inner.actionType,
|
|
256
|
+
enumerable: true,
|
|
257
|
+
configurable: true
|
|
258
|
+
});
|
|
259
|
+
Object.defineProperty(wrapper, 'meta', {
|
|
260
|
+
get: ()=>inner.meta,
|
|
261
|
+
enumerable: true,
|
|
262
|
+
configurable: true
|
|
263
|
+
});
|
|
264
|
+
return wrapper;
|
|
265
|
+
}
|
|
266
|
+
#wrapWatcher(inner) {
|
|
267
|
+
const wrapper = ()=>{
|
|
268
|
+
this.#ensureFinalized();
|
|
269
|
+
return inner();
|
|
270
|
+
};
|
|
271
|
+
wrapper._type = 'watchers';
|
|
272
|
+
wrapper._inner = inner;
|
|
273
|
+
Object.defineProperty(wrapper, 'actionType', {
|
|
274
|
+
get: ()=>inner.actionType,
|
|
275
|
+
enumerable: true,
|
|
276
|
+
configurable: true
|
|
277
|
+
});
|
|
278
|
+
Object.defineProperty(wrapper, 'meta', {
|
|
279
|
+
get: ()=>inner.meta,
|
|
280
|
+
enumerable: true,
|
|
281
|
+
configurable: true
|
|
282
|
+
});
|
|
283
|
+
Object.defineProperty(wrapper, 'unsubscribe', {
|
|
284
|
+
value: ()=>inner.unsubscribe(),
|
|
285
|
+
enumerable: true,
|
|
286
|
+
configurable: true
|
|
287
|
+
});
|
|
288
|
+
return wrapper;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export { Dispatcher, FINALIZE };
|
|
293
|
+
|
|
294
|
+
//# sourceMappingURL=dispatcher.base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive/dispatcher/dispatcher.base.js","sources":["../../../src/reactive/dispatcher/dispatcher.base.ts"],"sourcesContent":["import type { Observable } from 'rxjs'\n\nimport type { IStorage } from '../../core'\nimport type { Action, DispatchFunction, EnhancedMiddleware, WatcherFunction } from './dispatcher.module'\nimport { DispatcherCore } from './dispatcher.module'\nimport { resolvePath, setByPath } from './path.util'\nimport { type ApiRequestState, ApiStatus } from './standalone'\n\n/**\n * Маркер метода финализации диспетчера.\n *\n * Имя экшена/вотчера берётся из имени поля класса, но прочитать имена полей можно\n * только ПОСЛЕ полного конструирования инстанса (инициализаторы полей derived-класса\n * выполняются после конструктора базового класса). Поэтому имена назначаются отдельным\n * шагом-финализацией:\n *\n * 1. **Сборщик `createSynapse(factory)`** вызывает `dispatcher[FINALIZE]()` до старта\n * эффектов (эффекты читают `actionType` при сборке пайплайна).\n * 2. **Ленивая само-финализация** — страховка для standalone-использования и тестов:\n * первый dispatch экшена или первое обращение к реестру `dispatch`/`watchers`\n * финализирует инстанс, если это ещё не сделано.\n */\nexport const FINALIZE = Symbol('synapse.dispatcher.finalize')\n\n/**\n * Внутренний маркер «продукта фабрики» на функции экшена/вотчера.\n * `_type` уже выставляется движком (`DispatcherCore.createAction/createWatcher`),\n * здесь — те же значения, что и у движка.\n */\ntype FactoryKind = 'dispatch' | 'watchers'\n\n/** Имена членов базового класса, которые нельзя переопределять полями-экшенами. */\nconst RESERVED_NAMES = new Set(['storage', 'action$', 'actions', 'dispatch', 'watchers', 'use', 'destroy'])\n\n/**\n * Вызываемая группа жизненного цикла API-запроса.\n *\n * Сам вызов группы — это `init` (намерение): сбрасывает статус в `idle` и пробрасывает\n * payload намерения дальше эффектам. Жизненный цикл — через методы-поля.\n *\n * `ofType(d.loadPosts)` ловит ТОЛЬКО init; чтобы среагировать на успех —\n * `ofType(d.loadPosts.success)`.\n */\nexport interface ApiActions<TInitPayload = void> extends DispatchFunction<TInitPayload, TInitPayload> {\n loading: DispatchFunction<void, void>\n success: DispatchFunction<void, void>\n failure: DispatchFunction<string, void>\n reset: DispatchFunction<void, void>\n}\n\n/**\n * Keyed-вариант: статус хранится по ключу. `init`/`loading`/`success`/`reset` принимают\n * `key`, `failure` — `{ key, error }`.\n */\nexport interface KeyedApiActions<TInitPayload extends { key: string } = { key: string }> extends DispatchFunction<TInitPayload, TInitPayload> {\n loading: DispatchFunction<string, string>\n success: DispatchFunction<string, string>\n failure: DispatchFunction<{ key: string; error: string }, { key: string; error: string }>\n reset: DispatchFunction<string, string>\n}\n\n/** Опции конструктора базового диспетчера. */\nexport interface DispatcherBaseOptions<TState extends Record<string, any>> {\n middlewares?: EnhancedMiddleware<TState>[]\n}\n\n/** Внутренняя форма фабричной обёртки. */\ninterface Wrapper {\n (params?: any): any\n _type: FactoryKind\n /** Реальная функция движка, на которую делегирует обёртка. */\n _inner: any\n /** Для API-групп: вложенные lifecycle-обёртки. */\n _apiGroup?: Record<string, Wrapper>\n}\n\nfunction isWrapper(value: unknown): value is Wrapper {\n return typeof value === 'function' && ((value as any)._type === 'dispatch' || (value as any)._type === 'watchers')\n}\n\n/**\n * Публичный class-based слой диспетчера. Экшены объявляются как поля класса через\n * фабрики `this.action` / `this.signal` / `this.apiActions` / `this.keyedApiActions`\n * / `this.watcher`. Имя экшена = имя поля.\n *\n * Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном\n * namespace и НЕ конфликтуют с полями-экшенами подкласса. Запрещённые имена экшенов —\n * только `protected`/публичная поверхность из `RESERVED_NAMES`.\n *\n * @example\n * ```ts\n * class PostsDispatcher extends Dispatcher<PostsState> {\n * readonly loadPosts = this.apiActions<PostsFindAllParams>((s) => s.api.postsRequest)\n * readonly mounted = this.signal<FeedLifecyclePayload>('Лента смонтирована')\n * readonly applyPosts = this.action((store, page: PostsFeedResponseDto) =>\n * store.update((s) => { s.list = page.data }))\n * }\n * ```\n */\nexport abstract class Dispatcher<TState extends Record<string, any>> {\n protected readonly storage: IStorage<TState>\n\n /** Движок, поверх которого работает class-слой. */\n readonly #core: DispatcherCore<TState>\n\n /** Реестры по имени (наполняются при финализации). Делят ссылку с движком. */\n readonly #dispatch: Record<string, DispatchFunction<any, any>>\n readonly #watchers: Record<string, WatcherFunction<any>>\n\n #finalized = false\n\n /** Поток всех экшенов модуля (его потребляет EffectsModule). */\n readonly action$: Observable<Action>\n\n constructor(storage: IStorage<TState>, options?: DispatcherBaseOptions<TState>) {\n this.storage = storage\n this.#core = new DispatcherCore<TState>({ storage, middlewares: options?.middlewares })\n this.#dispatch = this.#core.dispatch\n this.#watchers = this.#core.watchers\n this.action$ = this.#core.actions\n }\n\n // ── Публичные реестры: обращение к ним финализирует (страховка) ──────────────\n\n /** Реестр экшенов по имени — для middleware/devtools. */\n get dispatch(): Record<string, DispatchFunction<any, any>> {\n this.#ensureFinalized()\n return this.#dispatch\n }\n\n get watchers(): Record<string, WatcherFunction<any>> {\n this.#ensureFinalized()\n return this.#watchers\n }\n\n /** Алиас потока экшенов для совместимости с EffectsModule (`dispatcher.actions`). */\n get actions(): Observable<Action> {\n return this.action$\n }\n\n // ── Фабрики для class fields ─────────────────────────────────────────────────\n\n /**\n * Экшен: handler в «рецептной» сигнатуре `(storage, params) => result`.\n * payload экшена = возвращаемое значение handler'а.\n */\n protected action<TParams = void, TResult = void>(\n handler: (storage: IStorage<TState>, params: TParams) => TResult | Promise<TResult>,\n options?: {\n type?: string\n meta?: Record<string, any>\n memoize?: (cur: TParams, prev: TParams, prevResult: TResult) => boolean\n },\n ): DispatchFunction<TParams, TResult> {\n const inner = this.#core.createAction<TParams, TResult>(\n {\n type: options?.type,\n meta: options?.meta,\n action: (params: TParams) => handler(this.storage, params),\n },\n options?.memoize ? { memoize: options.memoize } : undefined,\n )\n return this.#wrapDispatch(inner) as unknown as DispatchFunction<TParams, TResult>\n }\n\n /** Чистый сигнал: `(_store, p) => p`. `description` уходит в meta. */\n protected signal<TPayload = void>(description?: string): DispatchFunction<TPayload, TPayload> {\n return this.action<TPayload, TPayload>((_storage, payload) => payload, description ? { meta: { description } } : undefined)\n }\n\n /** Вызываемая группа жизненного цикла API-запроса. Сам вызов = init (намерение). */\n protected apiActions<TInitPayload = void>(accessor: (state: TState) => ApiRequestState): ApiActions<TInitPayload> {\n const path = resolvePath(accessor)\n const write = (storage: IStorage<TState>, request: ApiRequestState) => storage.update((s) => setByPath(s, path, request))\n\n const init = this.action<TInitPayload, TInitPayload>((storage, payload) => {\n write(storage, { status: ApiStatus.Idle, error: null })\n return payload\n }) as ApiActions<TInitPayload>\n\n init.loading = this.action((storage) => write(storage, { status: ApiStatus.Loading, error: null }))\n init.success = this.action((storage) => write(storage, { status: ApiStatus.Success, error: null }))\n init.failure = this.action<string, void>((storage, error) => write(storage, { status: ApiStatus.Error, error }))\n init.reset = this.action((storage) => write(storage, { status: ApiStatus.Reset, error: null }))\n\n return this.#markApiGroup(init)\n }\n\n /** То же для статусов по ключу (`Record<string, ApiRequestState>`). */\n protected keyedApiActions<TInitPayload extends { key: string } = { key: string }>(accessor: (state: TState) => Record<string, ApiRequestState>): KeyedApiActions<TInitPayload> {\n const path = resolvePath(accessor)\n const write = (storage: IStorage<TState>, key: string, request: ApiRequestState) => storage.update((s) => setByPath(s, [...path, key], request))\n\n const init = this.action<TInitPayload, TInitPayload>((storage, payload) => {\n write(storage, payload.key, { status: ApiStatus.Idle, error: null })\n return payload\n }) as KeyedApiActions<TInitPayload>\n\n init.loading = this.action<string, string>((storage, key) => {\n write(storage, key, { status: ApiStatus.Loading, error: null })\n return key\n })\n init.success = this.action<string, string>((storage, key) => {\n write(storage, key, { status: ApiStatus.Success, error: null })\n return key\n })\n init.reset = this.action<string, string>((storage, key) => {\n write(storage, key, { status: ApiStatus.Reset, error: null })\n return key\n })\n init.failure = this.action<{ key: string; error: string }, { key: string; error: string }>((storage, payload) => {\n write(storage, payload.key, { status: ApiStatus.Error, error: payload.error })\n return payload\n })\n\n return this.#markApiGroup(init)\n }\n\n protected watcher<R>(config: {\n selector: (state: TState) => R\n shouldTrigger?: (prev: R | undefined, current: R) => boolean\n notifyAfterSubscribe?: boolean\n type?: string\n meta?: Record<string, any>\n }): WatcherFunction<R> {\n const inner = this.#core.createWatcher<R>(config)\n return this.#wrapWatcher(inner) as unknown as WatcherFunction<R>\n }\n\n // ── Жизненный цикл ───────────────────────────────────────────────────────────\n\n use(...middlewares: EnhancedMiddleware<TState>[]): this {\n this.#core.use(...middlewares)\n return this\n }\n\n destroy(): void {\n // Движок отпишет вотчеры (реестр общий) и завершит action$.\n this.#core.destroy()\n }\n\n /**\n * Финализация: скан own enumerable полей, назначение имён (`_assignType(имя поля)`)\n * и регистрация в реестрах `dispatch`/`watchers`. Идемпотентна.\n */\n [FINALIZE](): void {\n if (this.#finalized) return\n this.#finalized = true\n\n // Для детекции полей-алиасов (одна функция под двумя именами).\n const seen = new Map<Wrapper, string>()\n\n for (const [name, value] of Object.entries(this)) {\n if (!isWrapper(value)) continue\n\n if (RESERVED_NAMES.has(name)) {\n throw new Error(`Dispatcher: поле \"${name}\" конфликтует с зарезервированным членом базового класса. Переименуйте экшен.`)\n }\n\n if (seen.has(value)) {\n throw new Error(`Dispatcher: поле \"${name}\" является алиасом поля \"${seen.get(value)}\" — один экшен не может иметь два имени. Объявите отдельный экшен.`)\n }\n seen.set(value, name)\n\n if (value._apiGroup) {\n this.#finalizeApiGroup(name, value)\n } else if (value._type === 'watchers') {\n this.#finalizeNamed(name, value, this.#watchers)\n } else {\n this.#finalizeNamed(name, value, this.#dispatch)\n }\n }\n }\n\n // ── Внутреннее ───────────────────────────────────────────────────────────────\n\n #ensureFinalized(): void {\n if (!this.#finalized) this[FINALIZE]()\n }\n\n /** Назначает имя через `_assignType` (если тип не был задан явно) и регистрирует обёртку. */\n #finalizeNamed(name: string, wrapper: Wrapper, registry: Record<string, any>): void {\n if (typeof wrapper._inner._assignType === 'function') {\n wrapper._inner._assignType(name)\n }\n registry[name] = wrapper\n }\n\n #finalizeApiGroup(name: string, init: Wrapper): void {\n this.#finalizeNamed(name, init, this.#dispatch)\n const group = init._apiGroup!\n this.#finalizeNamed(`${name}:loading`, group.loading, this.#dispatch)\n this.#finalizeNamed(`${name}:success`, group.success, this.#dispatch)\n this.#finalizeNamed(`${name}:failure`, group.failure, this.#dispatch)\n this.#finalizeNamed(`${name}:reset`, group.reset, this.#dispatch)\n }\n\n #markApiGroup<T extends DispatchFunction<any, any>>(init: T): T {\n const w = init as unknown as Wrapper\n w._apiGroup = {\n loading: (init as any).loading,\n success: (init as any).success,\n failure: (init as any).failure,\n reset: (init as any).reset,\n }\n return init\n }\n\n /**\n * Оборачивает функцию-экшен движка: на первый вызов лениво финализирует диспетчер,\n * затем делегирует. `actionType`/`meta` форвардятся «вживую» (значение появляется\n * после `_assignType` при финализации).\n */\n #wrapDispatch(inner: DispatchFunction<any, any>): Wrapper {\n const wrapper = ((params?: any) => {\n this.#ensureFinalized()\n return inner(params)\n }) as Wrapper\n wrapper._type = 'dispatch'\n wrapper._inner = inner\n Object.defineProperty(wrapper, 'actionType', { get: () => inner.actionType, enumerable: true, configurable: true })\n Object.defineProperty(wrapper, 'meta', { get: () => inner.meta, enumerable: true, configurable: true })\n return wrapper\n }\n\n #wrapWatcher(inner: WatcherFunction<any>): Wrapper {\n const wrapper = (() => {\n this.#ensureFinalized()\n return inner()\n }) as unknown as Wrapper\n wrapper._type = 'watchers'\n wrapper._inner = inner\n Object.defineProperty(wrapper, 'actionType', { get: () => inner.actionType, enumerable: true, configurable: true })\n Object.defineProperty(wrapper, 'meta', { get: () => inner.meta, enumerable: true, configurable: true })\n Object.defineProperty(wrapper, 'unsubscribe', { value: () => inner.unsubscribe(), enumerable: true, configurable: true })\n return wrapper\n }\n}\n"],"names":["DispatcherCore","resolvePath","setByPath","ApiStatus","FINALIZE","Symbol","RESERVED_NAMES","Set","isWrapper","value","Dispatcher","storage","options","handler","inner","params","undefined","description","_storage","payload","accessor","path","write","request","s","init","error","key","config","middlewares","seen","Map","name","Object","Error","wrapper","registry","group","w"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import type { IStorage } from '../../core';
|
|
3
3
|
import { TypedAction } from '../effects';
|
|
4
|
-
import type { ActionExecutionOptions
|
|
4
|
+
import type { ActionExecutionOptions } from './standalone';
|
|
5
5
|
/**
|
|
6
6
|
* Расширенное API для middleware
|
|
7
7
|
*/
|
|
@@ -33,7 +33,7 @@ export interface Action<T = unknown> {
|
|
|
33
33
|
* Параметры для создания действия
|
|
34
34
|
*/
|
|
35
35
|
export interface ActionDefinition<TParams, TResult> {
|
|
36
|
-
/** Тип действия для идентификации в потоке и эффектах. Если не указан — будет выведен из имени
|
|
36
|
+
/** Тип действия для идентификации в потоке и эффектах. Если не указан — будет выведен из имени поля при финализации `Dispatcher`. */
|
|
37
37
|
type?: string;
|
|
38
38
|
/** Функция, выполняющая действие и возвращающая результат (payload) */
|
|
39
39
|
action: (params: TParams) => Promise<TResult> | TResult;
|
|
@@ -44,7 +44,7 @@ export interface ActionDefinition<TParams, TResult> {
|
|
|
44
44
|
* Определение типа для watcher'а
|
|
45
45
|
*/
|
|
46
46
|
interface WatcherDefinition<T, R> {
|
|
47
|
-
/** Тип watcher'а для идентификации в потоке. Если не указан — будет выведен из имени
|
|
47
|
+
/** Тип watcher'а для идентификации в потоке. Если не указан — будет выведен из имени поля при финализации `Dispatcher`. */
|
|
48
48
|
type?: string;
|
|
49
49
|
selector: (state: T) => R;
|
|
50
50
|
meta?: Record<string, any>;
|
|
@@ -60,13 +60,6 @@ export interface WatcherFunction<R> {
|
|
|
60
60
|
meta?: Record<string, any>;
|
|
61
61
|
unsubscribe: VoidFunction;
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Расширенный тип для функции настройки действий с поддержкой дополнительных утилит
|
|
65
|
-
*/
|
|
66
|
-
export type ActionsSetupWithUtils<T extends Record<string, any>> = (storage: IStorage<T>, utils: {
|
|
67
|
-
createAction: ActionCreatorFactory;
|
|
68
|
-
createWatcher: <R>(config: WatcherDefinition<T, R>) => WatcherFunction<R>;
|
|
69
|
-
}) => Record<string, DispatchFunction<any, any> | WatcherFunction<any> | ActionRecipe<T, any, any> | WatcherRecipe<T, any>>;
|
|
70
63
|
/**
|
|
71
64
|
* Расширенная функция диспетчеризации
|
|
72
65
|
*/
|
|
@@ -92,20 +85,6 @@ export type ExtractResultType<T> = T extends DispatchFunction<any, infer R> ? R
|
|
|
92
85
|
* Извлекает типы из функции настройки действий
|
|
93
86
|
*/
|
|
94
87
|
export type ActionsResult<F> = F extends (create: ActionCreatorFactory, storage: any, ...args: any[]) => infer R ? R : Record<string, DispatchFunction<any, any>>;
|
|
95
|
-
/**
|
|
96
|
-
* Типизированный объект действий
|
|
97
|
-
*/
|
|
98
|
-
type ResolveDispatch<T> = T extends DispatchFunction<any, any> ? T : T extends ActionRecipe<any, infer P, infer R> ? DispatchFunction<P, R> : never;
|
|
99
|
-
export type DispatchActions<T> = {
|
|
100
|
-
[K in keyof T]: ResolveDispatch<T[K]>;
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* Типизированный объект watchers
|
|
104
|
-
*/
|
|
105
|
-
type ResolveWatcher<T> = T extends WatcherFunction<any> ? T : T extends WatcherRecipe<any, infer R> ? WatcherFunction<R> : never;
|
|
106
|
-
export type WatcherActions<T> = {
|
|
107
|
-
[K in keyof T]: ResolveWatcher<T[K]>;
|
|
108
|
-
};
|
|
109
88
|
/**
|
|
110
89
|
* Параметры для Dispatcher
|
|
111
90
|
*/
|
|
@@ -114,9 +93,16 @@ interface DispatcherOptions<T extends Record<string, any>> {
|
|
|
114
93
|
middlewares?: EnhancedMiddleware<T>[];
|
|
115
94
|
}
|
|
116
95
|
/**
|
|
117
|
-
*
|
|
96
|
+
* Внутренний движок диспетчера для интеграции хранилищ с реактивной системой.
|
|
97
|
+
*
|
|
98
|
+
* Прежнее имя — `Dispatcher`. Переименован в `DispatcherCore`, поскольку публичным
|
|
99
|
+
* `Dispatcher` теперь является abstract class-based слой (`dispatcher.base.ts`),
|
|
100
|
+
* который строится поверх этого движка.
|
|
101
|
+
*
|
|
102
|
+
* `TActionsFn` — фантомный слот для вывода форм экшенов (`ActionsResult`); сам движок
|
|
103
|
+
* его не использует в рантайме.
|
|
118
104
|
*/
|
|
119
|
-
export declare class
|
|
105
|
+
export declare class DispatcherCore<T extends Record<string, any>, TActionsFn extends (...args: any[]) => any = (...args: any[]) => Record<string, DispatchFunction<any, any>>> {
|
|
120
106
|
private actions$;
|
|
121
107
|
readonly actions: Observable<Action>;
|
|
122
108
|
dispatch: Record<string, DispatchFunction<any, any>>;
|
|
@@ -151,14 +137,6 @@ export declare class Dispatcher<T extends Record<string, any>, TActionsFn extend
|
|
|
151
137
|
* Получает все действия с улучшенной типизацией
|
|
152
138
|
*/
|
|
153
139
|
getActions(): ActionsResult<TActionsFn>;
|
|
154
|
-
/**
|
|
155
|
-
* Получает типизированные действия диспетчера
|
|
156
|
-
*/
|
|
157
|
-
getTypedDispatch<A extends Record<string, any>>(): DispatchActions<A>;
|
|
158
|
-
/**
|
|
159
|
-
* Получает типизированные watcher'ы
|
|
160
|
-
*/
|
|
161
|
-
getTypedWatchers<A extends Record<string, any>>(): WatcherActions<A>;
|
|
162
140
|
/**
|
|
163
141
|
* Находит действие по типу
|
|
164
142
|
*/
|
|
@@ -180,37 +158,4 @@ export declare class Dispatcher<T extends Record<string, any>, TActionsFn extend
|
|
|
180
158
|
*/
|
|
181
159
|
createWatcher<R>(config: WatcherDefinition<T, R>): WatcherFunction<R>;
|
|
182
160
|
}
|
|
183
|
-
/**
|
|
184
|
-
* Функция для создания типизированного диспетчера.
|
|
185
|
-
*
|
|
186
|
-
* Поддерживает два варианта:
|
|
187
|
-
* 1. Объект standalone-рецептов (ActionRecipe / WatcherRecipe)
|
|
188
|
-
* 2. Setup-функция с доступом к createAction / createWatcher (inline-определение)
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```ts
|
|
192
|
-
* // Вариант 1: объект рецептов (рекомендуемый)
|
|
193
|
-
* createDispatcher({ storage }, {
|
|
194
|
-
* loadList,
|
|
195
|
-
* loadListLoading: listRequest.loading,
|
|
196
|
-
* watchCount,
|
|
197
|
-
* })
|
|
198
|
-
*
|
|
199
|
-
* // Вариант 2: setup-функция (для смешанного использования)
|
|
200
|
-
* createDispatcher({ storage }, (storage, { createAction }) => ({
|
|
201
|
-
* loadList,
|
|
202
|
-
* custom: createAction({ action: () => { ... } }),
|
|
203
|
-
* }))
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
export declare function createDispatcher<TState extends Record<string, any>, TRecord extends Record<string, ActionRecipe<TState, any, any> | WatcherRecipe<TState, any>>>(options: DispatcherOptions<TState>, actions: TRecord): Dispatcher<TState> & {
|
|
207
|
-
dispatch: DispatchActions<TRecord>;
|
|
208
|
-
watchers: WatcherActions<TRecord>;
|
|
209
|
-
};
|
|
210
|
-
export declare function createDispatcher<TState extends Record<string, any>, TActions extends ActionsSetupWithUtils<TState>>(options: DispatcherOptions<TState>, actionsSetup: TActions): Dispatcher<TState, TActions> & {
|
|
211
|
-
dispatch: DispatchActions<ReturnType<TActions>>;
|
|
212
|
-
watchers: WatcherActions<ReturnType<TActions>>;
|
|
213
|
-
};
|
|
214
|
-
export type CreateDispatcherType = ReturnType<typeof createDispatcher>;
|
|
215
161
|
export {};
|
|
216
|
-
//# sourceMappingURL=dispatcher.module.d.ts.map
|