@fozy-labs/rx-toolkit 0.5.3-rc.1 → 0.5.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/LICENSE +21 -21
- package/README.md +143 -137
- package/dist/common/devtools/combineDevtools.js +3 -3
- package/dist/common/devtools/index.d.ts +3 -3
- package/dist/common/devtools/index.js +3 -3
- package/dist/common/devtools/reduxDevtools.d.ts +1 -1
- package/dist/common/devtools/reduxDevtools.js +17 -17
- package/dist/common/devtools/types.d.ts +0 -6
- package/dist/common/options/DefaultOptions.d.ts +1 -1
- package/dist/common/options/SharedOptions.d.ts +3 -2
- package/dist/common/options/SharedOptions.js +6 -0
- package/dist/common/options/index.d.ts +1 -1
- package/dist/common/options/index.js +1 -1
- package/dist/common/react/index.d.ts +2 -2
- package/dist/common/react/index.js +2 -2
- package/dist/common/react/useConstant.js +1 -1
- package/dist/common/utils/deepEqual.js +1 -1
- package/dist/common/utils/index.d.ts +3 -3
- package/dist/common/utils/index.js +3 -3
- package/dist/common/utils/shallowEqual.js +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -7
- package/dist/query/SKIP_TOKEN.js +1 -1
- package/dist/query/api/createCommand.d.ts +21 -0
- package/dist/query/api/createCommand.js +20 -0
- package/dist/query/api/createOperation.d.ts +5 -3
- package/dist/query/api/createOperation.js +6 -2
- package/dist/query/api/createResource.d.ts +2 -2
- package/dist/query/api/createResourceDuplicator.d.ts +2 -2
- package/dist/query/core/Command/Command.d.ts +35 -0
- package/dist/query/core/{Opertation/Operation.js → Command/Command.js} +13 -14
- package/dist/query/core/Command/CommandAgent.d.ts +19 -0
- package/dist/query/core/{Opertation/OperationAgent.js → Command/CommandAgent.js} +13 -13
- package/dist/query/core/Command/index.d.ts +2 -0
- package/dist/query/core/Command/index.js +2 -0
- package/dist/query/core/Operation/Operation.d.ts +8 -0
- package/dist/query/core/Operation/Operation.js +4 -0
- package/dist/query/core/Operation/OperationAgent.d.ts +4 -0
- package/dist/query/core/Operation/OperationAgent.js +4 -0
- package/dist/query/core/QueriesCache.d.ts +2 -2
- package/dist/query/core/QueriesCache.js +1 -1
- package/dist/query/core/QueriesLifetimeHooks.d.ts +1 -1
- package/dist/query/core/QueriesLifetimeHooks.js +7 -7
- package/dist/query/core/Resource/Resource.d.ts +16 -16
- package/dist/query/core/Resource/Resource.js +7 -7
- package/dist/query/core/Resource/ResourceAgent.d.ts +2 -2
- package/dist/query/core/Resource/ResourceAgent.js +3 -3
- package/dist/query/core/Resource/ResourceDuplicator.d.ts +17 -17
- package/dist/query/core/Resource/ResourceDuplicator.js +18 -20
- package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +6 -6
- package/dist/query/core/Resource/ResourceDuplicatorAgent.js +3 -3
- package/dist/query/core/Resource/ResourceRef.d.ts +2 -2
- package/dist/query/core/Resource/ResourceRef.js +12 -12
- package/dist/query/index.d.ts +11 -8
- package/dist/query/index.js +14 -8
- package/dist/query/lib/IndirectMap.js +4 -4
- package/dist/query/lib/ReactiveCache.d.ts +1 -1
- package/dist/query/react/useCommandAgent.d.ts +24 -0
- package/dist/query/react/useCommandAgent.js +39 -0
- package/dist/query/react/useOperationAgent.d.ts +6 -8
- package/dist/query/react/useOperationAgent.js +6 -23
- package/dist/query/react/useResourceAgent.d.ts +4 -4
- package/dist/query/react/useResourceAgent.js +1 -1
- package/dist/query/react/useResourceRef.d.ts +3 -3
- package/dist/query/react/useResourceRef.js +7 -2
- package/dist/query/types/Command.types.d.ts +154 -0
- package/dist/query/types/Command.types.js +1 -0
- package/dist/query/types/Operation.types.d.ts +13 -154
- package/dist/query/types/Resource.types.d.ts +7 -5
- package/dist/query/types/index.d.ts +4 -3
- package/dist/query/types/index.js +5 -3
- package/dist/query-v2/api/createApi.d.ts +10 -0
- package/dist/query-v2/api/createApi.js +83 -0
- package/dist/query-v2/core/common/CacheEntry.d.ts +29 -0
- package/dist/query-v2/core/common/CacheEntry.js +71 -0
- package/dist/query-v2/core/common/CacheMap.d.ts +38 -0
- package/dist/query-v2/core/common/CacheMap.js +127 -0
- package/dist/query-v2/core/common/LifecycleHooks.d.ts +22 -0
- package/dist/query-v2/core/common/LifecycleHooks.js +104 -0
- package/dist/query-v2/core/common/index.d.ts +3 -0
- package/dist/query-v2/core/common/index.js +3 -0
- package/dist/query-v2/core/index.d.ts +3 -0
- package/dist/query-v2/core/index.js +3 -0
- package/dist/query-v2/core/machines/Machine.d.ts +14 -0
- package/dist/query-v2/core/machines/Machine.js +33 -0
- package/dist/query-v2/core/machines/MachineError.d.ts +11 -0
- package/dist/query-v2/core/machines/MachineError.js +26 -0
- package/dist/query-v2/core/machines/MachineIdle.d.ts +8 -0
- package/dist/query-v2/core/machines/MachineIdle.js +19 -0
- package/dist/query-v2/core/machines/MachinePending.d.ts +12 -0
- package/dist/query-v2/core/machines/MachinePending.js +29 -0
- package/dist/query-v2/core/machines/MachineRefreshing.d.ts +14 -0
- package/dist/query-v2/core/machines/MachineRefreshing.js +46 -0
- package/dist/query-v2/core/machines/MachineSuccess.d.ts +16 -0
- package/dist/query-v2/core/machines/MachineSuccess.js +42 -0
- package/dist/query-v2/core/machines/MachineWithData.d.ts +18 -0
- package/dist/query-v2/core/machines/MachineWithData.js +40 -0
- package/dist/query-v2/core/machines/Patcher.d.ts +20 -0
- package/dist/query-v2/core/machines/Patcher.js +104 -0
- package/dist/query-v2/core/machines/index.d.ts +8 -0
- package/dist/query-v2/core/machines/index.js +8 -0
- package/dist/query-v2/core/resource/ResourceV2.d.ts +120 -0
- package/dist/query-v2/core/resource/ResourceV2.js +464 -0
- package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +26 -0
- package/dist/query-v2/core/resource/ResourceV2Agent.js +132 -0
- package/dist/query-v2/core/resource/index.d.ts +2 -0
- package/dist/query-v2/core/resource/index.js +2 -0
- package/dist/query-v2/index.d.ts +11 -0
- package/dist/query-v2/index.js +17 -0
- package/dist/query-v2/lib/NO_VALUE.d.ts +2 -0
- package/dist/query-v2/lib/NO_VALUE.js +1 -0
- package/dist/query-v2/lib/SKIP_TOKEN.d.ts +2 -0
- package/dist/query-v2/lib/SKIP_TOKEN.js +1 -0
- package/dist/query-v2/lib/index.d.ts +4 -0
- package/dist/query-v2/lib/index.js +3 -0
- package/dist/query-v2/lib/stableStringify.d.ts +8 -0
- package/dist/query-v2/lib/stableStringify.js +23 -0
- package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +25 -0
- package/dist/query-v2/plugins/ReactHooksPlugin.js +19 -0
- package/dist/query-v2/plugins/types.d.ts +1 -0
- package/dist/query-v2/plugins/types.js +1 -0
- package/dist/query-v2/react/__tests__/helpers.d.ts +12 -0
- package/dist/query-v2/react/__tests__/helpers.js +33 -0
- package/dist/query-v2/react/index.d.ts +2 -0
- package/dist/query-v2/react/index.js +2 -0
- package/dist/query-v2/react/useResourceV2Agent.d.ts +12 -0
- package/dist/query-v2/react/useResourceV2Agent.js +36 -0
- package/dist/query-v2/react/useResourceV2Ref.d.ts +12 -0
- package/dist/query-v2/react/useResourceV2Ref.js +57 -0
- package/dist/query-v2/snapshot/Snapshot.d.ts +13 -0
- package/dist/query-v2/snapshot/Snapshot.js +76 -0
- package/dist/query-v2/types/agent.types.d.ts +54 -0
- package/dist/query-v2/types/agent.types.js +1 -0
- package/dist/query-v2/types/api.types.d.ts +22 -0
- package/dist/query-v2/types/api.types.js +1 -0
- package/dist/query-v2/types/cache.types.d.ts +37 -0
- package/dist/query-v2/types/cache.types.js +1 -0
- package/dist/query-v2/types/index.d.ts +9 -0
- package/dist/query-v2/types/index.js +9 -0
- package/dist/query-v2/types/lifecycle.types.d.ts +25 -0
- package/dist/query-v2/types/lifecycle.types.js +1 -0
- package/dist/query-v2/types/machine.types.d.ts +67 -0
- package/dist/query-v2/types/machine.types.js +1 -0
- package/dist/query-v2/types/plugin.types.d.ts +38 -0
- package/dist/query-v2/types/plugin.types.js +1 -0
- package/dist/query-v2/types/resource.types.d.ts +35 -0
- package/dist/query-v2/types/resource.types.js +1 -0
- package/dist/query-v2/types/shared.types.d.ts +20 -0
- package/dist/query-v2/types/shared.types.js +1 -0
- package/dist/query-v2/types/snapshot.types.d.ts +21 -0
- package/dist/query-v2/types/snapshot.types.js +1 -0
- package/dist/signals/base/Batcher.js +9 -5
- package/dist/signals/base/ComputeCache.js +3 -3
- package/dist/signals/base/DependencyTracker.js +1 -1
- package/dist/signals/base/Devtools.d.ts +3 -2
- package/dist/signals/base/Devtools.js +54 -27
- package/dist/signals/base/Indexer.js +1 -1
- package/dist/signals/base/ReadonlySignal.js +1 -1
- package/dist/signals/base/SyncObservable.d.ts +1 -2
- package/dist/signals/base/SyncObservable.js +2 -5
- package/dist/signals/base/index.d.ts +6 -6
- package/dist/signals/base/index.js +6 -6
- package/dist/signals/index.d.ts +5 -4
- package/dist/signals/index.js +5 -4
- package/dist/signals/operators/index.d.ts +1 -1
- package/dist/signals/operators/index.js +1 -1
- package/dist/signals/operators/signalize.d.ts +1 -1
- package/dist/signals/react/index.d.ts +1 -1
- package/dist/signals/react/index.js +1 -1
- package/dist/signals/signals/Computed.d.ts +3 -4
- package/dist/signals/signals/Computed.js +18 -10
- package/dist/signals/signals/Effect.js +2 -1
- package/dist/signals/signals/LocalState.d.ts +44 -0
- package/dist/signals/signals/{LocalSignal.js → LocalState.js} +62 -28
- package/dist/signals/signals/Signal.d.ts +8 -7
- package/dist/signals/signals/Signal.js +4 -1
- package/dist/signals/signals/State.d.ts +4 -5
- package/dist/signals/signals/State.js +23 -9
- package/dist/signals/signals/index.d.ts +5 -5
- package/dist/signals/signals/index.js +5 -6
- package/dist/signals/types/SignalOptions.d.ts +16 -0
- package/dist/signals/types/SignalOptions.js +1 -0
- package/dist/signals/types/index.d.ts +3 -1
- package/dist/signals/types/index.js +3 -1
- package/dist/signals/types/normalizeSignalOptions.d.ts +2 -0
- package/dist/signals/types/normalizeSignalOptions.js +10 -0
- package/dist/signals/types/signals.types.d.ts +6 -2
- package/docs/CHANGELOG.md +111 -32
- package/docs/CONTRIBUTING.md +230 -0
- package/docs/contributing/ai-assisted-development.md +47 -0
- package/docs/contributing/query-v2/README.md +379 -0
- package/docs/{release → contributing/release}/README.md +59 -59
- package/docs/devtools/README.md +228 -228
- package/docs/migrations/0.5.0.md +58 -58
- package/docs/migrations/query-v2.md +171 -0
- package/docs/options/README.md +92 -90
- package/docs/query/README.md +575 -571
- package/docs/query-v2/README.md +280 -0
- package/docs/query-v2/api-reference.md +235 -0
- package/docs/query-v2/optimistic-updates.md +148 -0
- package/docs/query-v2/ssr.md +130 -0
- package/docs/signals/README.md +300 -295
- package/docs/usage/react/README.md +309 -307
- package/package.json +86 -63
- package/dist/query/core/Opertation/Operation.d.ts +0 -35
- package/dist/query/core/Opertation/OperationAgent.d.ts +0 -19
- package/dist/signals/signals/LocalSignal.d.ts +0 -32
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { distinctUntilChanged,
|
|
1
|
+
import { distinctUntilChanged, finalize, map, ReplaySubject, share } from "rxjs";
|
|
2
|
+
import { normalizeSignalOptions } from "../../signals/types";
|
|
2
3
|
import { ComputeCache, DependencyTracker } from "../base";
|
|
3
4
|
import { Effect } from "./Effect";
|
|
4
|
-
import {
|
|
5
|
+
import { State } from "./State";
|
|
5
6
|
export class Computed {
|
|
6
7
|
_computeFn;
|
|
7
8
|
_state$;
|
|
@@ -13,12 +14,19 @@ export class Computed {
|
|
|
13
14
|
_computeCache = new ComputeCache();
|
|
14
15
|
constructor(_computeFn, options) {
|
|
15
16
|
this._computeFn = _computeFn;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const opts = normalizeSignalOptions(options);
|
|
18
|
+
const stateOptions = {
|
|
19
|
+
key: opts.key,
|
|
20
|
+
name: opts.name,
|
|
21
|
+
base: opts.base ?? Computed.name,
|
|
22
|
+
isDisabled: opts.isDisabled,
|
|
23
|
+
beforeDevtoolsPush: (value, push) => {
|
|
24
|
+
if (value !== Computed._EMPTY) {
|
|
25
|
+
push(value);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
20
28
|
};
|
|
21
|
-
this._state$ =
|
|
29
|
+
this._state$ = State.create(Computed._EMPTY, stateOptions);
|
|
22
30
|
this.obs = this._state$.obs.pipe(map((value) => {
|
|
23
31
|
if (value === Computed._EMPTY) {
|
|
24
32
|
return this._start();
|
|
@@ -36,7 +44,7 @@ export class Computed {
|
|
|
36
44
|
DependencyTracker.track({
|
|
37
45
|
getRang: () => {
|
|
38
46
|
if (!this._effect) {
|
|
39
|
-
throw new Error(
|
|
47
|
+
throw new Error("Effect in not started. Possibly maximum call stack size exceeded.");
|
|
40
48
|
}
|
|
41
49
|
return this._effect._getRang();
|
|
42
50
|
},
|
|
@@ -65,7 +73,7 @@ export class Computed {
|
|
|
65
73
|
});
|
|
66
74
|
this._computeCache.clear();
|
|
67
75
|
if (initialValue === Computed._EMPTY) {
|
|
68
|
-
throw new Error(
|
|
76
|
+
throw new Error("Computed value is not initialized");
|
|
69
77
|
}
|
|
70
78
|
return initialValue;
|
|
71
79
|
}
|
|
@@ -77,7 +85,7 @@ export class Computed {
|
|
|
77
85
|
this._state$.set(Computed._EMPTY);
|
|
78
86
|
}
|
|
79
87
|
// === static ===
|
|
80
|
-
static _EMPTY = Symbol(
|
|
88
|
+
static _EMPTY = Symbol("empty");
|
|
81
89
|
static create(computeFn, options) {
|
|
82
90
|
const lc = new Computed(computeFn, options);
|
|
83
91
|
function computedFn() {
|
|
@@ -15,6 +15,7 @@ export class Effect {
|
|
|
15
15
|
this._rang = 0;
|
|
16
16
|
const legacySubscriptions = this._subscriptions;
|
|
17
17
|
this._subscriptions = new Map();
|
|
18
|
+
// eslint-disable-next-line prefer-const -- assigned after closure capture
|
|
18
19
|
let scheduler;
|
|
19
20
|
// Стабильная функция для планирования выполнения эффекта
|
|
20
21
|
const scheduledFn = () => {
|
|
@@ -52,7 +53,7 @@ export class Effect {
|
|
|
52
53
|
stopTracking();
|
|
53
54
|
isTrackedContext = false;
|
|
54
55
|
// Сохраняем teardown функцию, если она была возвращена
|
|
55
|
-
if (typeof optionalTeardown ===
|
|
56
|
+
if (typeof optionalTeardown === "function") {
|
|
56
57
|
this._teardown = optionalTeardown;
|
|
57
58
|
}
|
|
58
59
|
scheduler = Batcher.scheduler(this._rang);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Observable } from "rxjs";
|
|
2
|
+
import { ZodType } from "zod/v4";
|
|
3
|
+
import { type SignalOptionsOrKey, type StatefulSignalFn } from "../../signals/types";
|
|
4
|
+
type StorageLike = {
|
|
5
|
+
getItem(key: string): string | null;
|
|
6
|
+
setItem(key: string, value: string): void;
|
|
7
|
+
removeItem(key: string): void;
|
|
8
|
+
};
|
|
9
|
+
type Options<T> = {
|
|
10
|
+
zodSchema?: ZodType<T>;
|
|
11
|
+
key: string;
|
|
12
|
+
userId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated use checkEffect instead
|
|
15
|
+
*/
|
|
16
|
+
validator$?: Observable<(value: T) => boolean>;
|
|
17
|
+
checkEffect?: (value: T) => boolean;
|
|
18
|
+
driver?: StorageLike;
|
|
19
|
+
defaultValue: T;
|
|
20
|
+
devtoolsOptions?: SignalOptionsOrKey;
|
|
21
|
+
};
|
|
22
|
+
export declare class LocalState<T = string | null | number | undefined> {
|
|
23
|
+
private _state$;
|
|
24
|
+
private _computed;
|
|
25
|
+
private readonly _options;
|
|
26
|
+
readonly obs: Observable<T>;
|
|
27
|
+
private get _driver();
|
|
28
|
+
constructor(options: Options<T>);
|
|
29
|
+
set(value: T): void;
|
|
30
|
+
peek(): T;
|
|
31
|
+
get(): T;
|
|
32
|
+
clear(): void;
|
|
33
|
+
private _getStorageValue;
|
|
34
|
+
private _setStorageValue;
|
|
35
|
+
private _deleteStorageValue;
|
|
36
|
+
static KEY_PREFIX: string;
|
|
37
|
+
static DEFAULT_DRIVER: Storage;
|
|
38
|
+
static create<T = string | null | number | undefined>(options: Options<T>): StatefulSignalFn<T>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated use LocalState instead
|
|
42
|
+
*/
|
|
43
|
+
export declare const LocalSignal: typeof LocalState;
|
|
44
|
+
export {};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { signalize } from "../operators";
|
|
3
3
|
import { Computed } from "./Computed";
|
|
4
|
-
import { State } from "
|
|
5
|
-
const NONE = Symbol(
|
|
6
|
-
export class
|
|
4
|
+
import { State } from "./State";
|
|
5
|
+
const NONE = Symbol("NONE");
|
|
6
|
+
export class LocalState {
|
|
7
7
|
_state$;
|
|
8
8
|
_computed;
|
|
9
9
|
_options;
|
|
10
10
|
obs;
|
|
11
|
+
get _driver() {
|
|
12
|
+
return this._options.driver || LocalState.DEFAULT_DRIVER;
|
|
13
|
+
}
|
|
11
14
|
constructor(options) {
|
|
12
|
-
|
|
15
|
+
this._options = options;
|
|
16
|
+
let initialValue = this._getStorageValue(options);
|
|
13
17
|
if (initialValue === NONE) {
|
|
14
18
|
initialValue = options.defaultValue;
|
|
15
19
|
}
|
|
@@ -29,10 +33,9 @@ export class LocalSignal {
|
|
|
29
33
|
return value;
|
|
30
34
|
}, options.devtoolsOptions);
|
|
31
35
|
this.obs = this._computed.obs;
|
|
32
|
-
this._options = options;
|
|
33
36
|
}
|
|
34
37
|
set(value) {
|
|
35
|
-
|
|
38
|
+
this._setStorageValue(this._options, value);
|
|
36
39
|
this._state$.set(value);
|
|
37
40
|
}
|
|
38
41
|
peek() {
|
|
@@ -41,23 +44,13 @@ export class LocalSignal {
|
|
|
41
44
|
get() {
|
|
42
45
|
return this._computed.get();
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
static create(options) {
|
|
48
|
-
const localSignal = new LocalSignal(options);
|
|
49
|
-
function signalFn() {
|
|
50
|
-
return localSignal.get();
|
|
51
|
-
}
|
|
52
|
-
signalFn.peek = () => localSignal.peek();
|
|
53
|
-
signalFn.get = () => localSignal.get();
|
|
54
|
-
signalFn.set = (value) => localSignal.set(value);
|
|
55
|
-
signalFn.obs = localSignal.obs;
|
|
56
|
-
return signalFn;
|
|
47
|
+
clear() {
|
|
48
|
+
this._deleteStorageValue(this._options);
|
|
49
|
+
this._state$.set(this._options.defaultValue);
|
|
57
50
|
}
|
|
58
|
-
|
|
59
|
-
const storageKey = `${
|
|
60
|
-
const item =
|
|
51
|
+
_getStorageValue(options) {
|
|
52
|
+
const storageKey = `${LocalState.KEY_PREFIX}:${options.key}`;
|
|
53
|
+
const item = this._driver.getItem(storageKey);
|
|
61
54
|
if (!item)
|
|
62
55
|
return NONE;
|
|
63
56
|
const schema = z.record(z.string(), options.zodSchema || z.any());
|
|
@@ -66,23 +59,64 @@ export class LocalSignal {
|
|
|
66
59
|
console.warn(`Invalid value for key "${options.key}" in localStorage`, parsed.error);
|
|
67
60
|
return NONE;
|
|
68
61
|
}
|
|
69
|
-
const subKey = options.userId ? `user:${options.userId}` :
|
|
62
|
+
const subKey = options.userId ? `user:${options.userId}` : "common";
|
|
70
63
|
if (!(subKey in parsed.data)) {
|
|
71
64
|
return NONE;
|
|
72
65
|
}
|
|
73
66
|
return parsed.data[subKey];
|
|
74
67
|
}
|
|
75
|
-
|
|
76
|
-
const storageKey = `${
|
|
77
|
-
const item =
|
|
68
|
+
_setStorageValue(options, value) {
|
|
69
|
+
const storageKey = `${LocalState.KEY_PREFIX}:${options.key}`;
|
|
70
|
+
const item = this._driver.getItem(storageKey) || "{}";
|
|
78
71
|
const schema = z.record(z.string(), options.zodSchema || z.any());
|
|
79
72
|
const parsed = schema.safeParse(JSON.parse(item));
|
|
80
73
|
let data = parsed.data ?? {};
|
|
81
74
|
if (!parsed.success) {
|
|
82
75
|
data = {};
|
|
83
76
|
}
|
|
84
|
-
const subKey = options.userId ? `user:${options.userId}` :
|
|
77
|
+
const subKey = options.userId ? `user:${options.userId}` : "common";
|
|
85
78
|
data[subKey] = value;
|
|
86
|
-
|
|
79
|
+
this._driver.setItem(storageKey, JSON.stringify(data));
|
|
80
|
+
}
|
|
81
|
+
_deleteStorageValue(options) {
|
|
82
|
+
const storageKey = `${LocalState.KEY_PREFIX}:${options.key}`;
|
|
83
|
+
const item = this._driver.getItem(storageKey);
|
|
84
|
+
if (!item)
|
|
85
|
+
return;
|
|
86
|
+
const schema = z.record(z.string(), options.zodSchema || z.any());
|
|
87
|
+
const parsed = schema.safeParse(JSON.parse(item));
|
|
88
|
+
const data = parsed.data ?? {};
|
|
89
|
+
if (!parsed.success) {
|
|
90
|
+
this._driver.removeItem(storageKey);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const subKey = options.userId ? `user:${options.userId}` : "common";
|
|
94
|
+
if (!data[subKey])
|
|
95
|
+
return;
|
|
96
|
+
delete data[subKey];
|
|
97
|
+
if (Object.keys(data).length === 0) {
|
|
98
|
+
this._driver.removeItem(storageKey);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this._driver.setItem(storageKey, JSON.stringify(data));
|
|
102
|
+
}
|
|
103
|
+
// === static ===
|
|
104
|
+
static KEY_PREFIX = "__LSValue__";
|
|
105
|
+
static DEFAULT_DRIVER = localStorage;
|
|
106
|
+
static create(options) {
|
|
107
|
+
const localState = new LocalState(options);
|
|
108
|
+
function signalFn() {
|
|
109
|
+
return localState.get();
|
|
110
|
+
}
|
|
111
|
+
signalFn.peek = () => localState.peek();
|
|
112
|
+
signalFn.get = () => localState.get();
|
|
113
|
+
signalFn.set = (value) => localState.set(value);
|
|
114
|
+
signalFn.clear = () => localState.clear();
|
|
115
|
+
signalFn.obs = localState.obs;
|
|
116
|
+
return signalFn;
|
|
87
117
|
}
|
|
88
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* @deprecated use LocalState instead
|
|
121
|
+
*/
|
|
122
|
+
export const LocalSignal = LocalState;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { SignalFn } from "
|
|
3
|
-
import { Effect
|
|
1
|
+
import type { SignalOptionsOrKey } from "../../signals/types";
|
|
2
|
+
import { SignalFn } from "../../signals/types";
|
|
3
|
+
import { Effect } from "./Effect";
|
|
4
|
+
import { State } from "./State";
|
|
4
5
|
export declare class Signal<T> extends State<T> {
|
|
5
6
|
/** @deprecated use `State` instead */
|
|
6
|
-
constructor(initialValue: T, options?:
|
|
7
|
+
constructor(initialValue: T, options?: SignalOptionsOrKey<T>);
|
|
7
8
|
/** @deprecated use `state` instead */
|
|
8
|
-
static create<T>(initialValue: T, options?:
|
|
9
|
-
static state<T>(initialValue: T, options?:
|
|
10
|
-
static compute<T>(computeFn: () => T, options?:
|
|
9
|
+
static create<T>(initialValue: T, options?: SignalOptionsOrKey<T>): SignalFn<T>;
|
|
10
|
+
static state<T>(initialValue: T, options?: SignalOptionsOrKey<T>): SignalFn<T>;
|
|
11
|
+
static compute<T>(computeFn: () => T, options?: SignalOptionsOrKey<T>): import("../../signals/types").ComputeFn<T>;
|
|
11
12
|
static effect(effectFn: () => void): Effect;
|
|
12
13
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { Computed
|
|
1
|
+
import { Computed } from "./Computed";
|
|
2
|
+
import { Effect } from "./Effect";
|
|
3
|
+
import { State } from "./State";
|
|
2
4
|
export class Signal extends State {
|
|
3
5
|
/** @deprecated use `State` instead */
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
|
4
7
|
constructor(initialValue, options) {
|
|
5
8
|
super(initialValue, options);
|
|
6
9
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
|
-
import {
|
|
3
|
-
import { SignalFn } from "@/signals/types";
|
|
2
|
+
import { SignalFn, SignalOptionsOrKey } from "../../signals/types";
|
|
4
3
|
export declare class State<T> {
|
|
5
|
-
private readonly
|
|
4
|
+
private readonly _hooks;
|
|
6
5
|
private _rang;
|
|
7
6
|
protected readonly bs$: BehaviorSubject<T>;
|
|
8
7
|
readonly obs: import("rxjs").Observable<T>;
|
|
9
|
-
constructor(initialValue: T, options?:
|
|
8
|
+
constructor(initialValue: T, options?: SignalOptionsOrKey<T>);
|
|
10
9
|
peek(): T;
|
|
11
10
|
set(value: T): void;
|
|
12
11
|
get(): T;
|
|
13
12
|
private static _finalizationRegistry;
|
|
14
|
-
static create<T>(initialValue: T, options?:
|
|
13
|
+
static create<T>(initialValue: T, options?: SignalOptionsOrKey<T>): SignalFn<T>;
|
|
15
14
|
}
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { normalizeSignalOptions } from "../../signals/types";
|
|
2
3
|
import { Batcher, DependencyTracker, Devtools } from "../base";
|
|
3
4
|
export class State {
|
|
4
|
-
|
|
5
|
+
_hooks;
|
|
5
6
|
_rang = 0;
|
|
6
7
|
bs$;
|
|
7
8
|
obs;
|
|
8
9
|
constructor(initialValue, options) {
|
|
9
10
|
this.bs$ = new BehaviorSubject(initialValue);
|
|
10
11
|
this.obs = this.bs$.asObservable();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const opts = normalizeSignalOptions(options);
|
|
13
|
+
const hooks = [];
|
|
14
|
+
const devtoolsHook = Devtools.createSignalHooks(initialValue, {
|
|
15
|
+
...opts,
|
|
16
|
+
base: opts.base ?? State.name,
|
|
14
17
|
});
|
|
15
|
-
if (
|
|
16
|
-
|
|
18
|
+
if (devtoolsHook)
|
|
19
|
+
hooks.push(devtoolsHook);
|
|
20
|
+
if (opts.hooks)
|
|
21
|
+
hooks.push(...opts.hooks);
|
|
22
|
+
this._hooks = hooks.length > 0 ? hooks : null;
|
|
23
|
+
if (this._hooks) {
|
|
24
|
+
State._finalizationRegistry.register(this, this._hooks);
|
|
17
25
|
}
|
|
18
26
|
}
|
|
19
27
|
peek() {
|
|
@@ -24,7 +32,11 @@ export class State {
|
|
|
24
32
|
return;
|
|
25
33
|
}
|
|
26
34
|
Batcher.run(() => {
|
|
27
|
-
this.
|
|
35
|
+
if (this._hooks) {
|
|
36
|
+
for (const hook of this._hooks) {
|
|
37
|
+
hook.onChange?.(value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
28
40
|
this.bs$.next(value);
|
|
29
41
|
});
|
|
30
42
|
}
|
|
@@ -37,8 +49,10 @@ export class State {
|
|
|
37
49
|
return this.bs$.getValue();
|
|
38
50
|
}
|
|
39
51
|
// === static ===
|
|
40
|
-
static _finalizationRegistry = new FinalizationRegistry((
|
|
41
|
-
|
|
52
|
+
static _finalizationRegistry = new FinalizationRegistry((hooks) => {
|
|
53
|
+
for (const hook of hooks) {
|
|
54
|
+
hook.onDispose?.();
|
|
55
|
+
}
|
|
42
56
|
});
|
|
43
57
|
static create(initialValue, options) {
|
|
44
58
|
const ls = new State(initialValue, options);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
1
|
+
export * from "./State";
|
|
2
|
+
export * from "./Computed";
|
|
3
|
+
export * from "./Effect";
|
|
4
|
+
export * from "./LocalState";
|
|
5
|
+
export * from "./Signal";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from './LocalSignal';
|
|
1
|
+
export * from "./State";
|
|
2
|
+
export * from "./Computed";
|
|
3
|
+
export * from "./Effect";
|
|
4
|
+
export * from "./LocalState";
|
|
5
|
+
export * from "./Signal";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SignalLifecycleHook<T = any> {
|
|
2
|
+
onInit?: (value: T) => void;
|
|
3
|
+
onChange?: (newValue: T) => void;
|
|
4
|
+
onDispose?: () => void;
|
|
5
|
+
}
|
|
6
|
+
export type TBeforeDevtoolsPushFn<T = any> = (newValue: T, push: (v: T) => void) => void;
|
|
7
|
+
export interface SignalOptions<T = any> {
|
|
8
|
+
key?: string;
|
|
9
|
+
/** @deprecated use key */
|
|
10
|
+
name?: string;
|
|
11
|
+
base?: string;
|
|
12
|
+
isDisabled?: boolean;
|
|
13
|
+
beforeDevtoolsPush?: TBeforeDevtoolsPushFn<T>;
|
|
14
|
+
hooks?: SignalLifecycleHook<T>[];
|
|
15
|
+
}
|
|
16
|
+
export type SignalOptionsOrKey<T = any> = SignalOptions<T> | string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -10,7 +10,11 @@ export interface ReadableSignalFnLike<T> extends ReadableSignalLike<T> {
|
|
|
10
10
|
export interface WriteableSignalLike<T> {
|
|
11
11
|
set(value: T): void;
|
|
12
12
|
}
|
|
13
|
-
export interface
|
|
13
|
+
export interface ClearableSignalLike<_T> {
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
export interface StatefulSignalFn<T> extends ReadableSignalFnLike<T>, WriteableSignalLike<T>, ClearableSignalLike<T> {
|
|
14
17
|
}
|
|
15
|
-
export interface
|
|
18
|
+
export interface SignalFn<T> extends ReadableSignalFnLike<T>, WriteableSignalLike<T> {
|
|
16
19
|
}
|
|
20
|
+
export type ComputeFn<T> = ReadableSignalFnLike<T>;
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,32 +1,111 @@
|
|
|
1
|
-
# CHANGELOG
|
|
2
|
-
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
###
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Fixed `useResourceRef` memoization for object arguments — ref no longer recreated every render
|
|
7
|
+
- Fixed missing type exports from `src/query/` — consumers can now import `ResourceDefinition`, `CommandDefinition`, etc.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `ResourceRefInstanse` renamed to `ResourceRefInstance` (deprecated alias preserved)
|
|
11
|
+
- `FrowardInfo` renamed to `ForwardInfo` (internal type)
|
|
12
|
+
- `Opertation/` directory renamed to `Operation/`
|
|
13
|
+
- Replaced `any` types with proper types in `useResourceAgent` and `ResourceDuplicator`
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Unit tests for query core modules
|
|
17
|
+
- Smoke tests for React hooks
|
|
18
|
+
- Integration tests for query exports
|
|
19
|
+
|
|
20
|
+
### Deprecated
|
|
21
|
+
- `ResourceRefInstanse` — use `ResourceRefInstance` (will be removed in v0.6.0)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## [0.5.3-rc.2] — 2026-02-23
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `createCommand()` — создание команды (мутации/действия), заменяет `createOperation()`
|
|
29
|
+
- `useCommandAgent()` — React-хук для работы с командой
|
|
30
|
+
- `LocalState` — замена `LocalSignal` с новыми возможностями
|
|
31
|
+
- `LocalState.clear()` — метод удаления значения из хранилища и сброса к значению по умолчанию
|
|
32
|
+
- Опция `driver` для `LocalState` — возможность подключить кастомное хранилище (вместо `localStorage`)
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- `LocalSignal` переименован в `LocalState`
|
|
37
|
+
- Все вызовы `Signal.create()` в кодовой базе заменены на `Signal.state()` (внутренний рефакторинг)
|
|
38
|
+
|
|
39
|
+
### Deprecated
|
|
40
|
+
|
|
41
|
+
- `createOperation()` → используйте `createCommand()` (будет удалён в v0.6.0)
|
|
42
|
+
- `useOperationAgent()` → используйте `useCommandAgent()` (будет удалён в v0.6.0)
|
|
43
|
+
- Все Operation-типы переименованы в Command-типы: `OperationDefinition` → `CommandDefinition`, `OperationInstance` → `CommandInstance`, `OperationCreateOptions` → `CommandCreateOptions`, `OperationCreateFn` → `CommandCreateFn`, `OperationQueryState` → `CommandQueryState`
|
|
44
|
+
- `OperationAgentInstanse` (с опечаткой) → `CommandAgentInstance` — исправлена опечатка в имени типа
|
|
45
|
+
- `LocalSignal` → используйте `LocalState`
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Исправления в документации и демо-примерах
|
|
50
|
+
|
|
51
|
+
## [0.5.3-rc.1] — 2026-02-22
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- Новый примитив **State** — замена `Signal` с идентичным API
|
|
56
|
+
- `Signal.state()` — рекомендуемый статический метод создания сигнала
|
|
57
|
+
|
|
58
|
+
### Deprecated
|
|
59
|
+
|
|
60
|
+
- `Signal` помечен как `@deprecated` — используйте `State` вместо него
|
|
61
|
+
- `Signal.create()` помечен как `@deprecated` — используйте `Signal.state()` / `State.create()`
|
|
62
|
+
|
|
63
|
+
## [0.5.2] — 2025-12-19
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- Исправлена работа `SKIP_TOKEN`
|
|
68
|
+
|
|
69
|
+
## [0.5.1] — 2025-12-19
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- Исправление типизации
|
|
74
|
+
|
|
75
|
+
## [0.5.0] — 2025-12-18
|
|
76
|
+
|
|
77
|
+
[Гайд по миграции с 0.4.x](./migrations/0.5.0.md)
|
|
78
|
+
|
|
79
|
+
### Breaking Changes
|
|
80
|
+
|
|
81
|
+
- Удалены хуки `useObservable` и `useSyncObservable`
|
|
82
|
+
- Сигналы больше не наследуют `Observable` — используйте `.obs` для подписки
|
|
83
|
+
- Удалены `.value`, `.getValue()`, `.next()` — заменены на `signal()`, `.get()`, `.set()`
|
|
84
|
+
- Нет необходимости вызывать `complete()` для Signal и Computed
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
#### Signals
|
|
89
|
+
- **Функциональный API**: `Signal.create()`, `Signal.compute()`, `Signal.effect()`
|
|
90
|
+
- **Ленивый Computed**: вычисление только при наличии подписок
|
|
91
|
+
- Cleanup-функции в `Effect` (возврат teardown)
|
|
92
|
+
|
|
93
|
+
#### Query
|
|
94
|
+
- **Расширенные состояния**: `isInitialLoading`, `isReloading`, `isLocked`
|
|
95
|
+
- **ResourceRef API**: низкоуровневый доступ к кэшу с поддержкой транзакций (patch с commit/abort)
|
|
96
|
+
- **Lifecycle хуки**: `onCacheEntryAdded`, `onQueryStarted`
|
|
97
|
+
- `resetAllQueriesCache()` — сброс всего кэша
|
|
98
|
+
|
|
99
|
+
#### React
|
|
100
|
+
- `useResourceRef` — хук для работы с ResourceRef
|
|
101
|
+
|
|
102
|
+
### Changed
|
|
103
|
+
|
|
104
|
+
- **BatchStrategy**: настройка стратегии обновлений (`'sync'`, `'microtask'`, `'task'`)
|
|
105
|
+
- **DefaultOptions**: расширенная конфигурация (`onQueryError`, `getScopeName`)
|
|
106
|
+
|
|
107
|
+
[0.5.3-rc.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.3-rc.1...v0.5.3-rc.2
|
|
108
|
+
[0.5.3-rc.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.2...v0.5.3-rc.1
|
|
109
|
+
[0.5.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.1...v0.5.2
|
|
110
|
+
[0.5.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.0...v0.5.1
|
|
111
|
+
[0.5.0]: https://github.com/fozy-labs/rx-toolkit/compare/v0.4.18...v0.5.0
|