@fozy-labs/rx-toolkit 0.5.3-rc.2 → 0.5.4

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.
Files changed (196) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +143 -137
  3. package/dist/common/devtools/combineDevtools.js +3 -3
  4. package/dist/common/devtools/index.d.ts +3 -3
  5. package/dist/common/devtools/index.js +3 -3
  6. package/dist/common/devtools/reduxDevtools.d.ts +1 -1
  7. package/dist/common/devtools/reduxDevtools.js +17 -17
  8. package/dist/common/devtools/types.d.ts +0 -6
  9. package/dist/common/options/SharedOptions.d.ts +1 -0
  10. package/dist/common/options/SharedOptions.js +6 -0
  11. package/dist/common/options/index.d.ts +1 -1
  12. package/dist/common/options/index.js +1 -1
  13. package/dist/common/react/index.d.ts +2 -2
  14. package/dist/common/react/index.js +2 -2
  15. package/dist/common/react/useConstant.js +1 -1
  16. package/dist/common/utils/deepEqual.js +1 -1
  17. package/dist/common/utils/index.d.ts +3 -3
  18. package/dist/common/utils/index.js +3 -3
  19. package/dist/common/utils/shallowEqual.js +1 -1
  20. package/dist/index.d.ts +8 -7
  21. package/dist/index.js +8 -7
  22. package/dist/query/SKIP_TOKEN.js +1 -1
  23. package/dist/query/api/createCommand.d.ts +1 -1
  24. package/dist/query/api/createOperation.d.ts +1 -1
  25. package/dist/query/api/createOperation.js +1 -1
  26. package/dist/query/api/createResource.d.ts +1 -1
  27. package/dist/query/api/createResourceDuplicator.d.ts +1 -1
  28. package/dist/query/core/Command/Command.d.ts +7 -7
  29. package/dist/query/core/Command/Command.js +2 -2
  30. package/dist/query/core/Command/CommandAgent.d.ts +1 -1
  31. package/dist/query/core/Command/index.d.ts +2 -2
  32. package/dist/query/core/Command/index.js +2 -2
  33. package/dist/query/core/{Opertation → Operation}/Operation.d.ts +2 -2
  34. package/dist/query/core/{Opertation → Operation}/Operation.js +1 -1
  35. package/dist/query/core/{Opertation → Operation}/OperationAgent.d.ts +1 -1
  36. package/dist/query/core/{Opertation → Operation}/OperationAgent.js +1 -1
  37. package/dist/query/core/QueriesCache.d.ts +1 -1
  38. package/dist/query/core/QueriesCache.js +1 -1
  39. package/dist/query/core/QueriesLifetimeHooks.js +7 -7
  40. package/dist/query/core/Resource/Resource.d.ts +15 -15
  41. package/dist/query/core/Resource/Resource.js +7 -7
  42. package/dist/query/core/Resource/ResourceAgent.d.ts +1 -1
  43. package/dist/query/core/Resource/ResourceAgent.js +2 -2
  44. package/dist/query/core/Resource/ResourceDuplicator.d.ts +16 -16
  45. package/dist/query/core/Resource/ResourceDuplicator.js +18 -20
  46. package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +5 -5
  47. package/dist/query/core/Resource/ResourceDuplicatorAgent.js +2 -2
  48. package/dist/query/core/Resource/ResourceRef.d.ts +2 -2
  49. package/dist/query/core/Resource/ResourceRef.js +12 -12
  50. package/dist/query/index.d.ts +11 -10
  51. package/dist/query/index.js +11 -10
  52. package/dist/query/lib/IndirectMap.js +4 -4
  53. package/dist/query/react/useCommandAgent.d.ts +2 -2
  54. package/dist/query/react/useOperationAgent.d.ts +1 -1
  55. package/dist/query/react/useOperationAgent.js +1 -1
  56. package/dist/query/react/useResourceAgent.d.ts +3 -3
  57. package/dist/query/react/useResourceAgent.js +1 -1
  58. package/dist/query/react/useResourceRef.d.ts +3 -3
  59. package/dist/query/react/useResourceRef.js +7 -2
  60. package/dist/query/types/Command.types.d.ts +1 -1
  61. package/dist/query/types/Operation.types.d.ts +1 -1
  62. package/dist/query/types/Resource.types.d.ts +7 -5
  63. package/dist/query/types/index.d.ts +4 -4
  64. package/dist/query/types/index.js +4 -4
  65. package/dist/query-v2/api/createApi.d.ts +10 -0
  66. package/dist/query-v2/api/createApi.js +83 -0
  67. package/dist/query-v2/core/common/CacheEntry.d.ts +29 -0
  68. package/dist/query-v2/core/common/CacheEntry.js +71 -0
  69. package/dist/query-v2/core/common/CacheMap.d.ts +38 -0
  70. package/dist/query-v2/core/common/CacheMap.js +127 -0
  71. package/dist/query-v2/core/common/LifecycleHooks.d.ts +22 -0
  72. package/dist/query-v2/core/common/LifecycleHooks.js +104 -0
  73. package/dist/query-v2/core/common/index.d.ts +3 -0
  74. package/dist/query-v2/core/common/index.js +3 -0
  75. package/dist/query-v2/core/index.d.ts +3 -0
  76. package/dist/query-v2/core/index.js +3 -0
  77. package/dist/query-v2/core/machines/Machine.d.ts +14 -0
  78. package/dist/query-v2/core/machines/Machine.js +33 -0
  79. package/dist/query-v2/core/machines/MachineError.d.ts +11 -0
  80. package/dist/query-v2/core/machines/MachineError.js +26 -0
  81. package/dist/query-v2/core/machines/MachineIdle.d.ts +8 -0
  82. package/dist/query-v2/core/machines/MachineIdle.js +19 -0
  83. package/dist/query-v2/core/machines/MachinePending.d.ts +12 -0
  84. package/dist/query-v2/core/machines/MachinePending.js +29 -0
  85. package/dist/query-v2/core/machines/MachineRefreshing.d.ts +14 -0
  86. package/dist/query-v2/core/machines/MachineRefreshing.js +46 -0
  87. package/dist/query-v2/core/machines/MachineSuccess.d.ts +16 -0
  88. package/dist/query-v2/core/machines/MachineSuccess.js +42 -0
  89. package/dist/query-v2/core/machines/MachineWithData.d.ts +18 -0
  90. package/dist/query-v2/core/machines/MachineWithData.js +40 -0
  91. package/dist/query-v2/core/machines/Patcher.d.ts +20 -0
  92. package/dist/query-v2/core/machines/Patcher.js +104 -0
  93. package/dist/query-v2/core/machines/index.d.ts +8 -0
  94. package/dist/query-v2/core/machines/index.js +8 -0
  95. package/dist/query-v2/core/resource/ResourceV2.d.ts +120 -0
  96. package/dist/query-v2/core/resource/ResourceV2.js +464 -0
  97. package/dist/query-v2/core/resource/ResourceV2Agent.d.ts +26 -0
  98. package/dist/query-v2/core/resource/ResourceV2Agent.js +132 -0
  99. package/dist/query-v2/core/resource/index.d.ts +2 -0
  100. package/dist/query-v2/core/resource/index.js +2 -0
  101. package/dist/query-v2/index.d.ts +11 -0
  102. package/dist/query-v2/index.js +17 -0
  103. package/dist/query-v2/lib/NO_VALUE.d.ts +2 -0
  104. package/dist/query-v2/lib/NO_VALUE.js +1 -0
  105. package/dist/query-v2/lib/SKIP_TOKEN.d.ts +2 -0
  106. package/dist/query-v2/lib/SKIP_TOKEN.js +1 -0
  107. package/dist/query-v2/lib/index.d.ts +4 -0
  108. package/dist/query-v2/lib/index.js +3 -0
  109. package/dist/query-v2/lib/stableStringify.d.ts +8 -0
  110. package/dist/query-v2/lib/stableStringify.js +23 -0
  111. package/dist/query-v2/plugins/ReactHooksPlugin.d.ts +25 -0
  112. package/dist/query-v2/plugins/ReactHooksPlugin.js +19 -0
  113. package/dist/query-v2/plugins/types.d.ts +1 -0
  114. package/dist/query-v2/plugins/types.js +1 -0
  115. package/dist/query-v2/react/__tests__/helpers.d.ts +12 -0
  116. package/dist/query-v2/react/__tests__/helpers.js +33 -0
  117. package/dist/query-v2/react/index.d.ts +2 -0
  118. package/dist/query-v2/react/index.js +2 -0
  119. package/dist/query-v2/react/useResourceV2Agent.d.ts +12 -0
  120. package/dist/query-v2/react/useResourceV2Agent.js +36 -0
  121. package/dist/query-v2/react/useResourceV2Ref.d.ts +12 -0
  122. package/dist/query-v2/react/useResourceV2Ref.js +57 -0
  123. package/dist/query-v2/snapshot/Snapshot.d.ts +13 -0
  124. package/dist/query-v2/snapshot/Snapshot.js +76 -0
  125. package/dist/query-v2/types/agent.types.d.ts +54 -0
  126. package/dist/query-v2/types/agent.types.js +1 -0
  127. package/dist/query-v2/types/api.types.d.ts +22 -0
  128. package/dist/query-v2/types/api.types.js +1 -0
  129. package/dist/query-v2/types/cache.types.d.ts +37 -0
  130. package/dist/query-v2/types/cache.types.js +1 -0
  131. package/dist/query-v2/types/index.d.ts +9 -0
  132. package/dist/query-v2/types/index.js +9 -0
  133. package/dist/query-v2/types/lifecycle.types.d.ts +25 -0
  134. package/dist/query-v2/types/lifecycle.types.js +1 -0
  135. package/dist/query-v2/types/machine.types.d.ts +67 -0
  136. package/dist/query-v2/types/machine.types.js +1 -0
  137. package/dist/query-v2/types/plugin.types.d.ts +38 -0
  138. package/dist/query-v2/types/plugin.types.js +1 -0
  139. package/dist/query-v2/types/resource.types.d.ts +35 -0
  140. package/dist/query-v2/types/resource.types.js +1 -0
  141. package/dist/query-v2/types/shared.types.d.ts +20 -0
  142. package/dist/query-v2/types/shared.types.js +1 -0
  143. package/dist/query-v2/types/snapshot.types.d.ts +21 -0
  144. package/dist/query-v2/types/snapshot.types.js +1 -0
  145. package/dist/signals/base/Batcher.js +9 -5
  146. package/dist/signals/base/ComputeCache.js +3 -3
  147. package/dist/signals/base/DependencyTracker.js +1 -1
  148. package/dist/signals/base/Devtools.d.ts +3 -2
  149. package/dist/signals/base/Devtools.js +54 -27
  150. package/dist/signals/base/Indexer.js +1 -1
  151. package/dist/signals/base/ReadonlySignal.js +1 -1
  152. package/dist/signals/base/SyncObservable.d.ts +1 -2
  153. package/dist/signals/base/SyncObservable.js +2 -5
  154. package/dist/signals/base/index.d.ts +6 -6
  155. package/dist/signals/base/index.js +6 -6
  156. package/dist/signals/index.d.ts +5 -4
  157. package/dist/signals/index.js +5 -4
  158. package/dist/signals/operators/index.d.ts +1 -1
  159. package/dist/signals/operators/index.js +1 -1
  160. package/dist/signals/react/index.d.ts +1 -1
  161. package/dist/signals/react/index.js +1 -1
  162. package/dist/signals/signals/Computed.d.ts +3 -4
  163. package/dist/signals/signals/Computed.js +18 -10
  164. package/dist/signals/signals/Effect.js +2 -1
  165. package/dist/signals/signals/LocalState.d.ts +3 -4
  166. package/dist/signals/signals/LocalState.js +8 -8
  167. package/dist/signals/signals/Signal.d.ts +7 -6
  168. package/dist/signals/signals/Signal.js +4 -1
  169. package/dist/signals/signals/State.d.ts +4 -5
  170. package/dist/signals/signals/State.js +23 -9
  171. package/dist/signals/signals/index.d.ts +5 -5
  172. package/dist/signals/signals/index.js +5 -6
  173. package/dist/signals/types/SignalOptions.d.ts +16 -0
  174. package/dist/signals/types/SignalOptions.js +1 -0
  175. package/dist/signals/types/index.d.ts +3 -1
  176. package/dist/signals/types/index.js +3 -1
  177. package/dist/signals/types/normalizeSignalOptions.d.ts +2 -0
  178. package/dist/signals/types/normalizeSignalOptions.js +10 -0
  179. package/dist/signals/types/signals.types.d.ts +2 -3
  180. package/docs/CHANGELOG.md +95 -90
  181. package/docs/CONTRIBUTING.md +230 -0
  182. package/docs/contributing/ai-assisted-development.md +47 -0
  183. package/docs/contributing/query-v2/README.md +379 -0
  184. package/docs/{release → contributing/release}/README.md +59 -59
  185. package/docs/devtools/README.md +228 -228
  186. package/docs/migrations/0.5.0.md +58 -58
  187. package/docs/migrations/query-v2.md +171 -0
  188. package/docs/options/README.md +92 -92
  189. package/docs/query/README.md +575 -573
  190. package/docs/query-v2/README.md +280 -0
  191. package/docs/query-v2/api-reference.md +235 -0
  192. package/docs/query-v2/optimistic-updates.md +148 -0
  193. package/docs/query-v2/ssr.md +130 -0
  194. package/docs/signals/README.md +300 -300
  195. package/docs/usage/react/README.md +309 -309
  196. package/package.json +85 -63
@@ -1,7 +1,8 @@
1
- import { distinctUntilChanged, ReplaySubject, share, map, finalize } from "rxjs";
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 { Signal } from "./Signal";
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 lsOptions = {
17
- base: Computed.name,
18
- ...(typeof options === 'string' ? { name: options } : options),
19
- _skipValues: [Computed._EMPTY],
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$ = Signal.state(Computed._EMPTY, lsOptions);
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('Effect in not started. Possibly maximum call stack size exceeded.');
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('Computed value is not initialized');
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('empty');
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 === 'function') {
56
+ if (typeof optionalTeardown === "function") {
56
57
  this._teardown = optionalTeardown;
57
58
  }
58
59
  scheduler = Batcher.scheduler(this._rang);
@@ -1,7 +1,6 @@
1
- import { ZodType } from "zod/v4";
2
1
  import { Observable } from "rxjs";
3
- import { type StatefulSignalFn } from "../../signals/types";
4
- import { type StateDevtoolsOptions } from "../../common/devtools";
2
+ import { ZodType } from "zod/v4";
3
+ import { type SignalOptionsOrKey, type StatefulSignalFn } from "../../signals/types";
5
4
  type StorageLike = {
6
5
  getItem(key: string): string | null;
7
6
  setItem(key: string, value: string): void;
@@ -18,7 +17,7 @@ type Options<T> = {
18
17
  checkEffect?: (value: T) => boolean;
19
18
  driver?: StorageLike;
20
19
  defaultValue: T;
21
- devtoolsOptions?: StateDevtoolsOptions;
20
+ devtoolsOptions?: SignalOptionsOrKey;
22
21
  };
23
22
  export declare class LocalState<T = string | null | number | undefined> {
24
23
  private _state$;
@@ -1,8 +1,8 @@
1
1
  import { z } from "zod/v4";
2
2
  import { signalize } from "../operators";
3
3
  import { Computed } from "./Computed";
4
- import { State } from "../../signals/signals/State";
5
- const NONE = Symbol('NONE');
4
+ import { State } from "./State";
5
+ const NONE = Symbol("NONE");
6
6
  export class LocalState {
7
7
  _state$;
8
8
  _computed;
@@ -59,7 +59,7 @@ export class LocalState {
59
59
  console.warn(`Invalid value for key "${options.key}" in localStorage`, parsed.error);
60
60
  return NONE;
61
61
  }
62
- const subKey = options.userId ? `user:${options.userId}` : 'common';
62
+ const subKey = options.userId ? `user:${options.userId}` : "common";
63
63
  if (!(subKey in parsed.data)) {
64
64
  return NONE;
65
65
  }
@@ -67,14 +67,14 @@ export class LocalState {
67
67
  }
68
68
  _setStorageValue(options, value) {
69
69
  const storageKey = `${LocalState.KEY_PREFIX}:${options.key}`;
70
- const item = this._driver.getItem(storageKey) || '{}';
70
+ const item = this._driver.getItem(storageKey) || "{}";
71
71
  const schema = z.record(z.string(), options.zodSchema || z.any());
72
72
  const parsed = schema.safeParse(JSON.parse(item));
73
73
  let data = parsed.data ?? {};
74
74
  if (!parsed.success) {
75
75
  data = {};
76
76
  }
77
- const subKey = options.userId ? `user:${options.userId}` : 'common';
77
+ const subKey = options.userId ? `user:${options.userId}` : "common";
78
78
  data[subKey] = value;
79
79
  this._driver.setItem(storageKey, JSON.stringify(data));
80
80
  }
@@ -85,12 +85,12 @@ export class LocalState {
85
85
  return;
86
86
  const schema = z.record(z.string(), options.zodSchema || z.any());
87
87
  const parsed = schema.safeParse(JSON.parse(item));
88
- let data = parsed.data ?? {};
88
+ const data = parsed.data ?? {};
89
89
  if (!parsed.success) {
90
90
  this._driver.removeItem(storageKey);
91
91
  return;
92
92
  }
93
- const subKey = options.userId ? `user:${options.userId}` : 'common';
93
+ const subKey = options.userId ? `user:${options.userId}` : "common";
94
94
  if (!data[subKey])
95
95
  return;
96
96
  delete data[subKey];
@@ -101,7 +101,7 @@ export class LocalState {
101
101
  this._driver.setItem(storageKey, JSON.stringify(data));
102
102
  }
103
103
  // === static ===
104
- static KEY_PREFIX = '__LSValue__';
104
+ static KEY_PREFIX = "__LSValue__";
105
105
  static DEFAULT_DRIVER = localStorage;
106
106
  static create(options) {
107
107
  const localState = new LocalState(options);
@@ -1,12 +1,13 @@
1
- import type { StateDevtoolsOptions } from "../../common/devtools";
1
+ import type { SignalOptionsOrKey } from "../../signals/types";
2
2
  import { SignalFn } from "../../signals/types";
3
- import { Effect, State } from "../../signals/signals";
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?: StateDevtoolsOptions);
7
+ constructor(initialValue: T, options?: SignalOptionsOrKey<T>);
7
8
  /** @deprecated use `state` instead */
8
- static create<T>(initialValue: T, options?: StateDevtoolsOptions): SignalFn<T>;
9
- static state<T>(initialValue: T, options?: StateDevtoolsOptions): SignalFn<T>;
10
- static compute<T>(computeFn: () => T, options?: StateDevtoolsOptions): import("../../signals/types").ComputeFn<T>;
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, Effect, State } from "../../signals/signals";
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 { StateDevtoolsOptions } from "../../common/devtools";
3
- import { SignalFn } from "../../signals/types";
2
+ import { SignalFn, SignalOptionsOrKey } from "../../signals/types";
4
3
  export declare class State<T> {
5
- private readonly _stateDevtools;
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?: StateDevtoolsOptions);
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?: StateDevtoolsOptions): SignalFn<T>;
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
- _stateDevtools;
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
- this._stateDevtools = Devtools.createState(initialValue, {
12
- base: State.name,
13
- ...(typeof options === 'string' ? { name: options } : options)
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 (this._stateDevtools) {
16
- State._finalizationRegistry.register(this, this._stateDevtools);
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._stateDevtools?.(value);
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((heldValue) => {
41
- heldValue('$COMPLETED');
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 './State';
2
- export * from './Computed';
3
- export * from './Effect';
4
- export * from './Signal';
5
- export * from './LocalState';
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 './State';
3
- export * from './Computed';
4
- export * from './Effect';
5
- export * from './Signal';
6
- export * from './LocalState';
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 {};
@@ -1 +1,3 @@
1
- export * from './signals.types';
1
+ export * from "./signals.types";
2
+ export * from "./SignalOptions";
3
+ export * from "./normalizeSignalOptions";
@@ -1 +1,3 @@
1
- export * from './signals.types';
1
+ export * from "./signals.types";
2
+ export * from "./SignalOptions";
3
+ export * from "./normalizeSignalOptions";
@@ -0,0 +1,2 @@
1
+ import { SignalOptions, SignalOptionsOrKey } from "./SignalOptions";
2
+ export declare function normalizeSignalOptions<T>(options?: SignalOptionsOrKey<T>): SignalOptions<T>;
@@ -0,0 +1,10 @@
1
+ export function normalizeSignalOptions(options) {
2
+ if (!options)
3
+ return {};
4
+ if (typeof options === "string")
5
+ return { key: options };
6
+ if (options.name && !options.key) {
7
+ return { ...options, key: options.name };
8
+ }
9
+ return options;
10
+ }
@@ -10,12 +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 ClearableSignalLike<T> {
13
+ export interface ClearableSignalLike<_T> {
14
14
  clear(): void;
15
15
  }
16
16
  export interface StatefulSignalFn<T> extends ReadableSignalFnLike<T>, WriteableSignalLike<T>, ClearableSignalLike<T> {
17
17
  }
18
18
  export interface SignalFn<T> extends ReadableSignalFnLike<T>, WriteableSignalLike<T> {
19
19
  }
20
- export interface ComputeFn<T> extends ReadableSignalFnLike<T> {
21
- }
20
+ export type ComputeFn<T> = ReadableSignalFnLike<T>;
package/docs/CHANGELOG.md CHANGED
@@ -1,90 +1,95 @@
1
- # CHANGELOG
2
-
3
- ## [0.5.3-rc.2] 2026-02-23
4
-
5
- ### Added
6
-
7
- - `createCommand()` — создание команды (мутации/действия), заменяет `createOperation()`
8
- - `useCommandAgent()` React-хук для работы с командой
9
- - `LocalState` — замена `LocalSignal` с новыми возможностями
10
- - `LocalState.clear()` — метод удаления значения из хранилища и сброса к значению по умолчанию
11
- - Опция `driver` для `LocalState`возможность подключить кастомное хранилище (вместо `localStorage`)
12
-
13
- ### Changed
14
-
15
- - `LocalSignal` переименован в `LocalState`
16
- - Все вызовы `Signal.create()` в кодовой базе заменены на `Signal.state()` (внутренний рефакторинг)
17
-
18
- ### Deprecated
19
-
20
- - `createOperation()` используйте `createCommand()` (будет удалён в v0.6.0)
21
- - `useOperationAgent()` используйте `useCommandAgent()` (будет удалён в v0.6.0)
22
- - Все Operation-типы переименованы в Command-типы: `OperationDefinition` → `CommandDefinition`, `OperationInstance` → `CommandInstance`, `OperationCreateOptions` → `CommandCreateOptions`, `OperationCreateFn` → `CommandCreateFn`, `OperationQueryState` → `CommandQueryState`
23
- - `OperationAgentInstanse` (с опечаткой) → `CommandAgentInstance` — исправлена опечатка в имени типа
24
- - `LocalSignal` используйте `LocalState`
25
-
26
- ### Fixed
27
-
28
- - Исправления в документации и демо-примерах
29
-
30
- ## [0.5.3-rc.1]2026-02-22
31
-
32
- ### Added
33
-
34
- - Новый примитив **State** — замена `Signal` с идентичным API
35
- - `Signal.state()` — рекомендуемый статический метод создания сигнала
36
-
37
- ### Deprecated
38
-
39
- - `Signal` помечен как `@deprecated` используйте `State` вместо него
40
- - `Signal.create()` помечен как `@deprecated` используйте `Signal.state()` / `State.create()`
41
-
42
- ## [0.5.2] 2025-12-19
43
-
44
- ### Fixed
45
-
46
- - Исправлена работа `SKIP_TOKEN`
47
-
48
- ## [0.5.1] — 2025-12-19
49
-
50
- ### Fixed
51
-
52
- - Исправление типизации
53
-
54
- ## [0.5.0] — 2025-12-18
55
-
56
- [Гайд по миграции с 0.4.x](./migrations/0.5.0.md)
57
-
58
- ### Breaking Changes
59
-
60
- - Удалены хуки `useObservable` и `useSyncObservable`
61
- - Сигналы больше не наследуют `Observable` — используйте `.obs` для подписки
62
- - Удалены `.value`, `.getValue()`, `.next()` — заменены на `signal()`, `.get()`, `.set()`
63
- - Нет необходимости вызывать `complete()` для Signal и Computed
64
-
65
- ### Added
66
-
67
- #### Signals
68
- - **Функциональный API**: `Signal.create()`, `Signal.compute()`, `Signal.effect()`
69
- - **Ленивый Computed**: вычисление только при наличии подписок
70
- - Cleanup-функции в `Effect` (возврат teardown)
71
-
72
- #### Query
73
- - **Расширенные состояния**: `isInitialLoading`, `isReloading`, `isLocked`
74
- - **ResourceRef API**: низкоуровневый доступ к кэшу с поддержкой транзакций (patch с commit/abort)
75
- - **Lifecycle хуки**: `onCacheEntryAdded`, `onQueryStarted`
76
- - `resetAllQueriesCache()` — сброс всего кэша
77
-
78
- #### React
79
- - `useResourceRef` хук для работы с ResourceRef
80
-
81
- ### Changed
82
-
83
- - **BatchStrategy**: настройка стратегии обновлений (`'sync'`, `'microtask'`, `'task'`)
84
- - **DefaultOptions**: расширенная конфигурация (`onQueryError`, `getScopeName`)
85
-
86
- [0.5.3-rc.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.3-rc.1...v0.5.3-rc.2
87
- [0.5.3-rc.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.2...v0.5.3-rc.1
88
- [0.5.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.1...v0.5.2
89
- [0.5.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.0...v0.5.1
90
- [0.5.0]: https://github.com/fozy-labs/rx-toolkit/compare/v0.4.18...v0.5.0
1
+ # CHANGELOG
2
+
3
+ ## [0.5.4] - 2026-03-21
4
+
5
+ ### Fixed
6
+ - Removed unused `observable-hooks` dependency from `package.json`
7
+
8
+ ## [0.5.3] - 2026-03-21
9
+
10
+ ### Fixed
11
+ - Fixed `useResourceRef` memoization for object arguments ref no longer recreated every render
12
+ - Fixed missing type exports from `src/query/` — consumers can now import `ResourceDefinition`, `CommandDefinition`, etc.
13
+ - Исправления в документации и демо-примерах
14
+
15
+ ### Changed
16
+ - `ResourceRefInstanse` renamed to `ResourceRefInstance` (deprecated alias preserved)
17
+ - `FrowardInfo` renamed to `ForwardInfo` (internal type)
18
+ - `Opertation/` directory renamed to `Operation/`
19
+ - Replaced `any` types with proper types in `useResourceAgent` and `ResourceDuplicator`
20
+ - `LocalSignal` переименован в `LocalState`
21
+ - Все вызовы `Signal.create()` в кодовой базе заменены на `Signal.state()` (внутренний рефакторинг)
22
+
23
+ ### Added
24
+ - Unit tests for query core modules
25
+ - Smoke tests for React hooks
26
+ - Integration tests for query exports
27
+ - `createCommand()` — создание команды (мутации/действия), заменяет `createOperation()`
28
+ - `useCommandAgent()` React-хук для работы с командой
29
+ - `LocalState` — замена `LocalSignal` с новыми возможностями
30
+ - `LocalState.clear()`метод удаления значения из хранилища и сброса к значению по умолчанию
31
+ - Опция `driver` для `LocalState` — возможность подключить кастомное хранилище (вместо `localStorage`)
32
+ - Новый примитив **State** — замена `Signal` с идентичным API
33
+ - `Signal.state()` — рекомендуемый статический метод создания сигнала
34
+
35
+
36
+ ### Deprecated
37
+ - `ResourceRefInstanse` — use `ResourceRefInstance` (will be removed in v0.6.0)
38
+ - `createOperation()` → используйте `createCommand()` (будет удалён в v0.6.0)
39
+ - `useOperationAgent()` используйте `useCommandAgent()` (будет удалён в v0.6.0)
40
+ - Все Operation-типы переименованы в Command-типы: `OperationDefinition` `CommandDefinition`, `OperationInstance` `CommandInstance`, `OperationCreateOptions` `CommandCreateOptions`, `OperationCreateFn` → `CommandCreateFn`, `OperationQueryState` → `CommandQueryState`
41
+ - `OperationAgentInstanse` (с опечаткой) → `CommandAgentInstance` — исправлена опечатка в имени типа
42
+ - `LocalSignal` используйте `LocalState`
43
+ - `Signal` помечен как `@deprecated` — используйте `State` вместо него
44
+ - `Signal.create()` помечен как `@deprecated` — используйте `Signal.state()` / `State.create()`
45
+
46
+
47
+ ## [0.5.2] — 2025-12-19
48
+
49
+ ### Fixed
50
+
51
+ - Исправлена работа `SKIP_TOKEN`
52
+
53
+ ## [0.5.1] — 2025-12-19
54
+
55
+ ### Fixed
56
+
57
+ - Исправление типизации
58
+
59
+ ## [0.5.0] — 2025-12-18
60
+
61
+ [Гайд по миграции с 0.4.x](./migrations/0.5.0.md)
62
+
63
+ ### Breaking Changes
64
+
65
+ - Удалены хуки `useObservable` и `useSyncObservable`
66
+ - Сигналы больше не наследуют `Observable` — используйте `.obs` для подписки
67
+ - Удалены `.value`, `.getValue()`, `.next()` — заменены на `signal()`, `.get()`, `.set()`
68
+ - Нет необходимости вызывать `complete()` для Signal и Computed
69
+
70
+ ### Added
71
+
72
+ #### Signals
73
+ - **Функциональный API**: `Signal.create()`, `Signal.compute()`, `Signal.effect()`
74
+ - **Ленивый Computed**: вычисление только при наличии подписок
75
+ - Cleanup-функции в `Effect` (возврат teardown)
76
+
77
+ #### Query
78
+ - **Расширенные состояния**: `isInitialLoading`, `isReloading`, `isLocked`
79
+ - **ResourceRef API**: низкоуровневый доступ к кэшу с поддержкой транзакций (patch с commit/abort)
80
+ - **Lifecycle хуки**: `onCacheEntryAdded`, `onQueryStarted`
81
+ - `resetAllQueriesCache()` — сброс всего кэша
82
+
83
+ #### React
84
+ - `useResourceRef` хук для работы с ResourceRef
85
+
86
+ ### Changed
87
+
88
+ - **BatchStrategy**: настройка стратегии обновлений (`'sync'`, `'microtask'`, `'task'`)
89
+ - **DefaultOptions**: расширенная конфигурация (`onQueryError`, `getScopeName`)
90
+
91
+ [0.5.3-rc.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.3-rc.1...v0.5.3-rc.2
92
+ [0.5.3-rc.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.2...v0.5.3-rc.1
93
+ [0.5.2]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.1...v0.5.2
94
+ [0.5.1]: https://github.com/fozy-labs/rx-toolkit/compare/v0.5.0...v0.5.1
95
+ [0.5.0]: https://github.com/fozy-labs/rx-toolkit/compare/v0.4.18...v0.5.0