@fozy-labs/rx-toolkit 0.4.2 → 0.4.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 (81) hide show
  1. package/README.md +4 -5
  2. package/dist/{devtools → common/devtools}/combineDevtools.d.ts +1 -1
  3. package/dist/{devtools → common/devtools}/index.d.ts +1 -0
  4. package/dist/{devtools → common/devtools}/index.js +1 -0
  5. package/dist/common/devtools/reduxDevtools.d.ts +16 -0
  6. package/dist/{devtools → common/devtools}/reduxDevtools.js +7 -4
  7. package/dist/{query/api → common/options}/DefaultOptions.d.ts +1 -1
  8. package/dist/{query/api → common/options}/DefaultOptions.js +1 -1
  9. package/dist/{query/core → common/options}/SharedOptions.d.ts +1 -1
  10. package/dist/common/options/index.d.ts +1 -0
  11. package/dist/common/options/index.js +1 -0
  12. package/dist/{react-hooks → common/react}/index.d.ts +2 -3
  13. package/dist/{react-hooks → common/react}/index.js +2 -3
  14. package/dist/{react-hooks → common/react}/useObservable.js +2 -2
  15. package/dist/{react-hooks → common/react}/useSyncObservable.js +2 -1
  16. package/dist/common/utils/PromiseResolver.d.ts +7 -0
  17. package/dist/common/utils/PromiseResolver.js +14 -0
  18. package/dist/common/utils/index.d.ts +1 -0
  19. package/dist/common/utils/index.js +1 -0
  20. package/dist/index.d.ts +3 -2
  21. package/dist/index.js +3 -2
  22. package/dist/query/api/createOperation.d.ts +1 -5
  23. package/dist/query/api/createOperation.js +0 -4
  24. package/dist/query/api/createResource.d.ts +1 -1
  25. package/dist/query/core/Opertation/Operation.d.ts +2 -3
  26. package/dist/query/core/Opertation/Operation.js +6 -18
  27. package/dist/query/core/Opertation/OperationAgent.d.ts +2 -2
  28. package/dist/query/core/Opertation/OperationAgent.js +1 -1
  29. package/dist/query/core/QueriesCache.d.ts +2 -1
  30. package/dist/query/core/QueriesCache.js +19 -16
  31. package/dist/query/core/Resource/Resource.d.ts +3 -9
  32. package/dist/query/core/Resource/Resource.js +79 -26
  33. package/dist/query/core/Resource/ResourceAgent.d.ts +2 -2
  34. package/dist/query/core/Resource/ResourceAgent.js +5 -4
  35. package/dist/query/core/Resource/ResourceRef.d.ts +1 -4
  36. package/dist/query/core/Resource/ResourceRef.js +10 -20
  37. package/dist/query/index.d.ts +0 -1
  38. package/dist/query/index.js +0 -1
  39. package/dist/query/lib/IndirectMap.js +1 -1
  40. package/dist/query/lib/ReactiveCache.d.ts +6 -22
  41. package/dist/query/lib/ReactiveCache.js +19 -39
  42. package/dist/query/react/useOperationAgent.d.ts +1 -2
  43. package/dist/query/react/useOperationAgent.js +2 -1
  44. package/dist/query/react/useResourceAgent.d.ts +3 -7
  45. package/dist/query/react/useResourceAgent.js +7 -3
  46. package/dist/query/react/useResourceRef.d.ts +1 -2
  47. package/dist/query/react/useResourceRef.js +1 -1
  48. package/dist/query/types/Operation.types.d.ts +1 -1
  49. package/dist/query/types/Resource.types.d.ts +29 -10
  50. package/dist/query/types/index.d.ts +3 -0
  51. package/dist/query/types/index.js +3 -0
  52. package/dist/signals/base/Computed.js +1 -2
  53. package/dist/signals/base/Effect.js +3 -2
  54. package/dist/signals/base/ReadonlySignal.d.ts +2 -3
  55. package/dist/signals/base/ReadonlySignal.js +2 -11
  56. package/dist/signals/base/Signal.d.ts +2 -2
  57. package/dist/signals/base/Signal.js +1 -1
  58. package/dist/signals/base/Tracker.d.ts +0 -4
  59. package/dist/signals/base/Tracker.js +0 -6
  60. package/dist/signals/base/types.d.ts +9 -0
  61. package/dist/signals/index.d.ts +1 -0
  62. package/dist/signals/index.js +1 -0
  63. package/dist/signals/react/index.d.ts +1 -0
  64. package/dist/signals/react/index.js +1 -0
  65. package/dist/{react-hooks → signals/react}/useSignal.d.ts +1 -1
  66. package/dist/{react-hooks → signals/react}/useSignal.js +1 -1
  67. package/docs/signals/README.md +1 -1
  68. package/package.json +1 -1
  69. package/dist/devtools/reduxDevtools.d.ts +0 -2
  70. package/dist/query/api/createSubResource.d.ts +0 -0
  71. package/dist/query/api/createSubResource.js +0 -1
  72. /package/dist/{devtools → common/devtools}/combineDevtools.js +0 -0
  73. /package/dist/{query/types/devtools.d.ts → common/devtools/types.d.ts} +0 -0
  74. /package/dist/{query/types/devtools.js → common/devtools/types.js} +0 -0
  75. /package/dist/{query/core → common/options}/SharedOptions.js +0 -0
  76. /package/dist/{react-hooks → common/react}/useConstant.d.ts +0 -0
  77. /package/dist/{react-hooks → common/react}/useConstant.js +0 -0
  78. /package/dist/{react-hooks → common/react}/useEventHandler.d.ts +0 -0
  79. /package/dist/{react-hooks → common/react}/useEventHandler.js +0 -0
  80. /package/dist/{react-hooks → common/react}/useObservable.d.ts +0 -0
  81. /package/dist/{react-hooks → common/react}/useSyncObservable.d.ts +0 -0
@@ -29,22 +29,6 @@ export class ResourceRef {
29
29
  unlockOne() {
30
30
  this._cacheItem = this._resource.decrementLock(this._args, { cache: this._cacheItem });
31
31
  }
32
- update(updateFn) {
33
- const cacheItem = this._cacheItem ?? this._resource.getQueryCache(this._args);
34
- if (!cacheItem) {
35
- console.warn('Trying to update non-existing cache item');
36
- return {
37
- rollback: () => { }
38
- };
39
- }
40
- const value = cacheItem.value;
41
- this._resource.updateData_legacy(this._args, updateFn, { cache: cacheItem });
42
- return {
43
- rollback: () => {
44
- this._resource.updateData_legacy(this._args, () => value.data, { cache: cacheItem });
45
- }
46
- };
47
- }
48
32
  patch(patchFn) {
49
33
  let isSkipped = true;
50
34
  const reapplyFn = (data, savedData, transactions) => {
@@ -56,12 +40,14 @@ export class ResourceRef {
56
40
  // Все pending - применяем и оставляем в очереди
57
41
  // Все commited (которые после pending) - применяем, но оставляем в очереди
58
42
  // Все aborted (которые после pending) - откатываем, но оставляем в очереди
43
+ // Если после aborted нет pending - пропускаем и убираем из очереди
59
44
  // Те после применения всех транзакций, очередь должна начинаться с первой pending транзакции (если есть), включая все, что после неё.
60
45
  let newSavedData = savedData ?? data;
61
46
  let currentData = savedData ?? data;
62
47
  const remainingTransactions = [];
63
48
  let foundPending = false;
64
- transactions.forEach((transaction) => {
49
+ const lastPendingIndex = transactions.findLastIndex(t => t.status === 'pending');
50
+ transactions.forEach((transaction, index) => {
65
51
  if (transaction.status === 'pending') {
66
52
  foundPending = true;
67
53
  // Применяем pending транзакцию и оставляем в очереди
@@ -76,9 +62,13 @@ export class ResourceRef {
76
62
  remainingTransactions.push(transaction);
77
63
  }
78
64
  else if (transaction.status === 'aborted') {
79
- // Откатываем и оставляем в очереди
80
- currentData = applyPatches(currentData, transaction.inversePatches);
81
- remainingTransactions.push(transaction);
65
+ // Проверяем, есть ли pending после текущей aborted
66
+ const hasPendingAfter = index < lastPendingIndex;
67
+ if (hasPendingAfter) {
68
+ currentData = applyPatches(currentData, transaction.inversePatches);
69
+ remainingTransactions.push(transaction);
70
+ }
71
+ // Если pending нет - пропускаем и убираем из очереди
82
72
  }
83
73
  }
84
74
  else {
@@ -1,6 +1,5 @@
1
1
  export * from './api/createResource';
2
2
  export * from './api/createOperation';
3
- export * from './api/DefaultOptions';
4
3
  export * from './SKIP_TOKEN';
5
4
  export * from './react/useResourceAgent';
6
5
  export * from './react/useResourceRef';
@@ -1,6 +1,5 @@
1
1
  export * from './api/createResource';
2
2
  export * from './api/createOperation';
3
- export * from './api/DefaultOptions';
4
3
  export * from './SKIP_TOKEN';
5
4
  export * from './react/useResourceAgent';
6
5
  export * from './react/useResourceRef';
@@ -1,4 +1,4 @@
1
- import { shallowEqual } from "../../query/lib/shallowEqual";
1
+ import { shallowEqual } from "./shallowEqual";
2
2
  export class IndirectMap {
3
3
  _compareObjectsFn;
4
4
  _compareCache = new WeakMap();
@@ -1,4 +1,5 @@
1
1
  import { Observable, Subject } from "rxjs";
2
+ import { ReadableSignalLike } from "../../signals";
2
3
  type Options<VALUE> = {
3
4
  /**
4
5
  * Начальное состояние кэша
@@ -6,9 +7,11 @@ type Options<VALUE> = {
6
7
  initialState: VALUE;
7
8
  /**
8
9
  * Время жизни кэша в миллисекундах (пока нет подписок на кеш)
10
+ * Если указано `false`, кэш не будет очищаться автоматически.
11
+ * Если указано `0` или меньше, кэш будет очищаться сразу после отписки от него.
9
12
  * @default 60_000 (1 минута)
10
13
  */
11
- cacheLifeTime?: number;
14
+ cacheLifeTime?: number | false;
12
15
  };
13
16
  /**
14
17
  * Класс `ReactiveCache` представляет собой реактивный кэш,
@@ -17,26 +20,15 @@ type Options<VALUE> = {
17
20
  * @template VALUE Тип значения, хранимого в кэше.
18
21
  */
19
22
  export declare class ReactiveCache<VALUE> {
20
- /**
21
- * Время жизни кэша в миллисекундах.
22
- * Если значение больше 0, то кэш очищается через указанное время после отписки.
23
- * @private
24
- */
25
- private readonly _cacheLifeTime;
26
23
  /**
27
24
  * Внутренний `BehaviorSubject`, хранящий текущее состояние кэша.
28
25
  * @private
29
26
  */
30
27
  private _state$;
31
- /**
32
- * Текущее значение.
33
- * @private
34
- */
35
- private _value;
36
28
  /**
37
29
  * Реактивное значене (Observable)
38
30
  */
39
- value$: Observable<VALUE>;
31
+ value$: ReadableSignalLike<VALUE>;
40
32
  /**
41
33
  * Значение без сайд-эффектов (для использования в DevTools)
42
34
  */
@@ -53,16 +45,8 @@ export declare class ReactiveCache<VALUE> {
53
45
  * @param options.cacheLifeTime Время жизни кэша в миллисекундах (по умолчанию 60_000).
54
46
  */
55
47
  constructor(options: Options<VALUE>);
56
- /**
57
- * Возвращает текущее значение кэша.
58
- * @returns {VALUE} Текущее значение кэша.
59
- */
48
+ private _getOnRefCountZero;
60
49
  get value(): VALUE;
61
- /**
62
- * Возвращает текущее значение кэша.
63
- * @returns {VALUE} Текущее значение кэша.
64
- */
65
- peek(): VALUE;
66
50
  /**
67
51
  * Устанавливает новое значение в кэш и обновляет поток состояния.
68
52
  *
@@ -1,5 +1,5 @@
1
- import { finalize, ReplaySubject, share, Subject, takeUntil, timer } from "rxjs";
2
- import { Signal } from "../../signals";
1
+ import { BehaviorSubject, finalize, ReplaySubject, share, Subject, takeUntil, timer } from "rxjs";
2
+ import { signalize } from "../../signals";
3
3
  /**
4
4
  * Класс `ReactiveCache` представляет собой реактивный кэш,
5
5
  * который позволяет управлять состоянием и временем жизни кэшированных данных.
@@ -7,22 +7,11 @@ import { Signal } from "../../signals";
7
7
  * @template VALUE Тип значения, хранимого в кэше.
8
8
  */
9
9
  export class ReactiveCache {
10
- /**
11
- * Время жизни кэша в миллисекундах.
12
- * Если значение больше 0, то кэш очищается через указанное время после отписки.
13
- * @private
14
- */
15
- _cacheLifeTime;
16
10
  /**
17
11
  * Внутренний `BehaviorSubject`, хранящий текущее состояние кэша.
18
12
  * @private
19
13
  */
20
14
  _state$;
21
- /**
22
- * Текущее значение.
23
- * @private
24
- */
25
- _value;
26
15
  /**
27
16
  * Реактивное значене (Observable)
28
17
  */
@@ -43,46 +32,37 @@ export class ReactiveCache {
43
32
  * @param options.cacheLifeTime Время жизни кэша в миллисекундах (по умолчанию 60_000).
44
33
  */
45
34
  constructor(options) {
46
- this._cacheLifeTime = options.cacheLifeTime || 60_000;
47
- this._state$ = new Signal(options.initialState, { disableDevtools: true });
48
- this._value = options.initialState;
35
+ const cacheLifeTime = options.cacheLifeTime ?? 60_000;
36
+ this._state$ = new BehaviorSubject(options.initialState);
49
37
  this.spy$ = this._state$.pipe(takeUntil(this.onClean$));
50
- this.value$ = this._state$.pipe(finalize(() => {
38
+ this.value$ = signalize(this._state$.pipe(finalize(() => {
51
39
  this.complete();
52
40
  }), share({
53
41
  connector: () => new ReplaySubject(1),
54
- /**
55
- * Если lifetime больше 0,
56
- * то очистим кэш значения по истечении этого времени,
57
- * иначе очищаем сразу после отписки.
58
- */
59
- resetOnRefCountZero: this._cacheLifeTime > 0
60
- ? () => timer(this._cacheLifeTime)
61
- : true,
42
+ resetOnRefCountZero: this._getOnRefCountZero(cacheLifeTime),
62
43
  resetOnComplete: true,
63
- }));
44
+ })));
45
+ }
46
+ _getOnRefCountZero(cacheLifeTime) {
47
+ if (cacheLifeTime === false) {
48
+ return false;
49
+ }
50
+ if (cacheLifeTime <= 0) {
51
+ return true;
52
+ }
53
+ return () => {
54
+ return timer(cacheLifeTime);
55
+ };
64
56
  }
65
- /**
66
- * Возвращает текущее значение кэша.
67
- * @returns {VALUE} Текущее значение кэша.
68
- */
69
57
  get value() {
70
58
  return this._state$.value;
71
59
  }
72
- /**
73
- * Возвращает текущее значение кэша.
74
- * @returns {VALUE} Текущее значение кэша.
75
- */
76
- peek() {
77
- return this._value;
78
- }
79
60
  /**
80
61
  * Устанавливает новое значение в кэш и обновляет поток состояния.
81
62
  *
82
63
  * @param value Новое значение для кэша.
83
64
  */
84
65
  next(value) {
85
- this._value = value;
86
66
  this._state$.next(value);
87
67
  }
88
68
  /**
@@ -90,7 +70,7 @@ export class ReactiveCache {
90
70
  */
91
71
  complete() {
92
72
  this._state$.complete();
93
- this.onClean$.next(this._value);
73
+ this.onClean$.next(this._state$.value);
94
74
  this.onClean$.complete();
95
75
  }
96
76
  }
@@ -1,5 +1,4 @@
1
- import { OperationAgentInstanse, OperationDefinition, OperationQueryState } from "../types/Operation.types";
2
- import { Prettify } from "../types/shared.types";
1
+ import type { Prettify, OperationAgentInstanse, OperationDefinition, OperationQueryState } from "../../query/types";
3
2
  type WithAgent<D extends OperationDefinition> = {
4
3
  createAgent: () => OperationAgentInstanse<D>;
5
4
  };
@@ -1,4 +1,5 @@
1
- import { useConstant, useEventHandler, useSignal } from "../../react-hooks";
1
+ import { useConstant, useEventHandler } from "../../common/react";
2
+ import { useSignal } from "../../signals/react";
2
3
  export function useOperationAgent(op) {
3
4
  const agent = useConstant(() => op.createAgent());
4
5
  const state = useSignal(agent.state$);
@@ -1,9 +1,5 @@
1
- import { ResourceAgentInstance, ResourceDefinition, ResourceQueryState } from "../types/Resource.types";
2
- import { Prettify } from "../types/shared.types";
3
- import { SKIP } from "../SKIP_TOKEN";
4
- type WithAgent<D extends ResourceDefinition> = {
5
- createAgent: () => ResourceAgentInstance<D>;
6
- };
1
+ import { Prettify, ResourceDefinition, ResourceInstance, ResourceQueryState } from "../../query/types";
2
+ import { SKIP } from "../../query/SKIP_TOKEN";
7
3
  type Result<D extends ResourceDefinition> = Prettify<ResourceQueryState<D>>;
8
- export declare function useResourceAgent<D extends ResourceDefinition>(res: WithAgent<D>, ...argss: D['Args'] extends void ? [] | [typeof SKIP] : [D['Args'] | typeof SKIP]): Result<D>;
4
+ export declare function useResourceAgent<D extends ResourceDefinition>(res: ResourceInstance<D>, ...argss: D['Args'] extends void ? [] | [typeof SKIP] : [D['Args'] | typeof SKIP]): Result<D>;
9
5
  export {};
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
- import { useConstant, useSignal } from "../../react-hooks";
3
- import { shallowEqual } from "../lib/shallowEqual";
4
- import { SKIP } from "../SKIP_TOKEN";
2
+ import { useConstant } from "../../common/react";
3
+ import { useSignal } from "../../signals/react";
4
+ import { shallowEqual } from "../../query/lib/shallowEqual";
5
+ import { SKIP } from "../../query/SKIP_TOKEN";
5
6
  export function useResourceAgent(res, ...argss) {
6
7
  const args = (argss[0] === SKIP ? SKIP : argss[0]);
7
8
  const agent = useConstant(() => {
@@ -21,5 +22,8 @@ export function useResourceAgent(res, ...argss) {
21
22
  }
22
23
  agent.initiate(args);
23
24
  }, [args]);
25
+ React.useEffect(() => () => {
26
+ agent.complete();
27
+ }, []);
24
28
  return useSignal(agent.state$);
25
29
  }
@@ -1,6 +1,5 @@
1
1
  import { SKIP } from "../../query/SKIP_TOKEN";
2
- import { ResourceDefinition, ResourceInstance, ResourceRefInstanse } from "../../query/types/Resource.types";
3
- import { Prettify } from "../../query/types/shared.types";
2
+ import type { Prettify, ResourceDefinition, ResourceInstance, ResourceRefInstanse } from "../../query/types";
4
3
  type Result<D extends ResourceDefinition> = Prettify<ResourceRefInstanse<D>> | null;
5
4
  export declare function useResourceRef<D extends ResourceDefinition>(res: ResourceInstance<D>, ...argss: D['Args'] extends void ? [] | [typeof SKIP] : [D['Args'] | typeof SKIP]): Result<D>;
6
5
  export {};
@@ -1,5 +1,5 @@
1
- import { SKIP } from "../../query/SKIP_TOKEN";
2
1
  import React from "react";
2
+ import { SKIP } from "../../query/SKIP_TOKEN";
3
3
  export function useResourceRef(res, ...argss) {
4
4
  const args = (argss[0] === SKIP ? SKIP : argss[0]);
5
5
  return React.useMemo(() => {
@@ -1,5 +1,5 @@
1
1
  import { ReadableSignalLike } from "../../signals";
2
- import { FallbackOnNever } from "../../query/types/shared.types";
2
+ import { FallbackOnNever } from "./shared.types";
3
3
  import { ResourceDefinition, ResourceInstance } from "./Resource.types";
4
4
  /**
5
5
  * Функция создания операции
@@ -1,6 +1,6 @@
1
- import { ReadableSignalLike } from "../../signals";
2
- import { FallbackOnNever } from "../../query/types/shared.types";
3
1
  import { Patch as ImmerPatch } from "immer";
2
+ import { ReadableSignalLike } from "../../signals";
3
+ import { FallbackOnNever } from "./shared.types";
4
4
  /**
5
5
  * Функция создания ресурса
6
6
  */
@@ -13,6 +13,31 @@ export type ResourceCreateOptions<D extends ResourceDefinition> = {
13
13
  select?: (data: D["Result"]) => D["Selected"];
14
14
  /** Функция запроса данных */
15
15
  queryFn: (args: D["Args"], tools: ResourceQueryFnTools) => Promise<D["Result"]>;
16
+ /**
17
+ * Время жизни кеша в миллисекундах. По умолчанию 60_000 (1 минута).
18
+ * Если указано false - кеш не удаляется автоматически.
19
+ */
20
+ cacheLifetime?: number | false;
21
+ onCacheEntryAdded?: (args: D["Args"], tools: CacheEntryAddedTools<D>) => void;
22
+ onQueryStarted?: (args: D["Args"], tools: QueryStartedTools<D>) => void;
23
+ };
24
+ export type CacheEntryAddedTools<D extends ResourceDefinition> = {
25
+ /** Функция для ожидания загрузки данных в кеш */
26
+ $cacheDataLoaded: Promise<void>;
27
+ /** Функция для ожидания удаления кеша */
28
+ $cacheEntryRemoved: Promise<void>;
29
+ };
30
+ export type QueryStartedTools<D extends ResourceDefinition> = {
31
+ /** Функция для уведомления об успешном завершении запроса */
32
+ $queryFulfilled: Promise<{
33
+ data: D["Result"];
34
+ error: undefined;
35
+ isError: false;
36
+ } | {
37
+ data: undefined;
38
+ error: unknown;
39
+ isError: true;
40
+ }>;
16
41
  };
17
42
  /**
18
43
  * Определение типов ресурса
@@ -45,8 +70,8 @@ export type ResourceAgentInstance<D extends ResourceDefinition> = {
45
70
  state$: ReadableSignalLike<ResourceQueryState<D>>;
46
71
  /** Инициирует запрос с указанными аргументами */
47
72
  initiate(args: D["Args"], force?: boolean): void;
48
- /** Создает новый агент */
49
- createAgent(): ResourceAgentInstance<D>;
73
+ /** Завершает работу агента, позволяя освободить ресурсы */
74
+ complete(): void;
50
75
  };
51
76
  /**
52
77
  * Состояние запроса ресурса
@@ -93,12 +118,6 @@ export type ResourceRefInstanse<D extends ResourceDefinition> = {
93
118
  unlock: () => void;
94
119
  };
95
120
  unlockOne(): void;
96
- /**
97
- * @deprecated
98
- */
99
- update(updateFn: (data: D['Data']) => D['Data']): {
100
- rollback: () => void;
101
- };
102
121
  patch(patchFn: (data: D['Data']) => void): ResourceTransaction | null;
103
122
  invalidate(): void;
104
123
  create(data: D['Data']): void;
@@ -0,0 +1,3 @@
1
+ export * from './Operation.types';
2
+ export * from './Resource.types';
3
+ export * from './shared.types';
@@ -0,0 +1,3 @@
1
+ export * from './Operation.types';
2
+ export * from './Resource.types';
3
+ export * from './shared.types';
@@ -20,8 +20,7 @@ export class Computed extends Signal {
20
20
  this._effect = effect;
21
21
  }
22
22
  unsubscribe() {
23
- this._effect.unsubscribe();
24
- super.unsubscribe();
23
+ this.complete();
25
24
  }
26
25
  complete() {
27
26
  this._effect.unsubscribe();
@@ -11,10 +11,10 @@ export class Effect {
11
11
  * Выполняет функцию в tracked-контексте, подписываясь на Tracker.
12
12
  */
13
13
  _runInTrackedContext(effectFn, isAsyncRun = false) {
14
- // Отписываемся от предыдущих подписок
14
+ let prevSubscriptions;
15
15
  if (!isAsyncRun) {
16
16
  this._rang = 0;
17
- this._subscriptions.forEach((sub) => sub.unsubscribe());
17
+ prevSubscriptions = this._subscriptions;
18
18
  this._subscriptions = [];
19
19
  }
20
20
  let isTrackedContext = true;
@@ -43,6 +43,7 @@ export class Effect {
43
43
  trackerSub.unsubscribe();
44
44
  isTrackedContext = false;
45
45
  scheduler = Batcher.scheduler(this._rang);
46
+ prevSubscriptions?.forEach((sub) => sub.unsubscribe());
46
47
  }
47
48
  unsubscribe() {
48
49
  this.closed = true;
@@ -1,9 +1,8 @@
1
1
  import { Observable, Subscriber, TeardownLogic } from "rxjs";
2
- import { SyncObservable } from "./SyncObservable";
3
2
  import type { ReadableSignalLike } from "./types";
3
+ import { SyncObservable } from "./SyncObservable";
4
4
  export declare class ReadonlySignal<T> extends SyncObservable<T> implements ReadableSignalLike<T> {
5
- private readonly _devtools;
6
- private static _logIdIndex;
5
+ protected rang: number;
7
6
  constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic);
8
7
  get value(): T;
9
8
  peek(): T;
@@ -1,21 +1,12 @@
1
- import { SharedOptions } from "../../query/core/SharedOptions";
2
1
  import { SyncObservable } from "./SyncObservable";
3
2
  import { Tracker } from "./Tracker";
4
3
  export class ReadonlySignal extends SyncObservable {
5
- _devtools;
6
- static _logIdIndex = 0;
4
+ rang = 0;
7
5
  constructor(subscribe) {
8
6
  super(subscribe);
9
- const stateDevtools = SharedOptions.DEVTOOLS?.state;
10
- if (stateDevtools) {
11
- const id = ReadonlySignal._logIdIndex++;
12
- const key = `ReadonlySignal:i=${id}`;
13
- const initialValue = this.peek();
14
- this._devtools = stateDevtools(key, initialValue);
15
- }
16
7
  }
17
8
  get value() {
18
- Tracker.next_legacy(this);
9
+ Tracker.next(this.rang, this);
19
10
  return super.value;
20
11
  }
21
12
  peek() {
@@ -1,10 +1,10 @@
1
1
  import { BehaviorSubject, Observable } from "rxjs";
2
- import { type ReadableSignalLike, UnaryFunction } from "./types";
2
+ import type { ReadableSignalLike, SignalLike, UnaryFunction } from "./types";
3
3
  type SignalOptions = {
4
4
  disableDevtools?: boolean;
5
5
  devtoolsName?: string;
6
6
  };
7
- export declare class Signal<T> extends BehaviorSubject<T> implements ReadableSignalLike<T> {
7
+ export declare class Signal<T> extends BehaviorSubject<T> implements SignalLike<T> {
8
8
  private readonly _devtools;
9
9
  protected _rang: number;
10
10
  constructor(initialValue: T, options?: SignalOptions);
@@ -1,5 +1,5 @@
1
- import { SharedOptions } from "../../query/core/SharedOptions";
2
1
  import { BehaviorSubject } from "rxjs";
2
+ import { SharedOptions } from "../../common/options/SharedOptions";
3
3
  import { Batcher } from "./Batcher";
4
4
  import { Indexer } from "./Indexer";
5
5
  import { Tracker } from "./Tracker";
@@ -4,10 +4,6 @@ type TrackedValue = {
4
4
  obsv$: Observable<unknown>;
5
5
  };
6
6
  export declare const Tracker: {
7
- /** @deprecated */
8
- tracked_legacy$: Subject<Observable<unknown>>;
9
- /** @deprecated */
10
- next_legacy(value: Observable<unknown>): void;
11
7
  tracked$: Subject<TrackedValue>;
12
8
  next(rang: number, observable: Observable<unknown>): void;
13
9
  };
@@ -1,11 +1,5 @@
1
1
  import { Subject } from "rxjs";
2
2
  export const Tracker = {
3
- /** @deprecated */
4
- tracked_legacy$: new Subject(),
5
- /** @deprecated */
6
- next_legacy(value) {
7
- Tracker.tracked_legacy$.next(value);
8
- },
9
3
  tracked$: new Subject(),
10
4
  next(rang, observable) {
11
5
  Tracker.tracked$.next({ rang, obsv$: observable, });
@@ -7,6 +7,15 @@ export interface ReadableSignalLike<T = unknown> extends Observable<T> {
7
7
  */
8
8
  get(): T;
9
9
  }
10
+ export interface SignalLike<T = unknown> extends ReadableSignalLike<T> {
11
+ set value(value: T);
12
+ next(value: T): void;
13
+ asReadonly(): ReadableSignalLike<T>;
14
+ /**
15
+ * @deprecated use `value` instead.
16
+ */
17
+ set(value: T): void;
18
+ }
10
19
  export interface UnaryFunction<T, R> {
11
20
  (source: T): R;
12
21
  }
@@ -1,3 +1,4 @@
1
1
  export * from './base';
2
2
  export * from './extends';
3
3
  export * from './operators';
4
+ export * from './react';
@@ -1,3 +1,4 @@
1
1
  export * from './base';
2
2
  export * from './extends';
3
3
  export * from './operators';
4
+ export * from './react';
@@ -0,0 +1 @@
1
+ export * from './useSignal';
@@ -0,0 +1 @@
1
+ export * from './useSignal';
@@ -1,2 +1,2 @@
1
- import { ReadableSignalLike } from "../signals";
1
+ import { ReadableSignalLike } from "../../signals";
2
2
  export declare function useSignal<T>(signal$: ReadableSignalLike<T>): T;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { useEventHandler } from "../react-hooks";
2
+ import { useEventHandler } from "../../common/react";
3
3
  export function useSignal(signal$) {
4
4
  const subscribe = React.useCallback((update) => {
5
5
  const subscription = signal$.subscribe(update);
@@ -17,7 +17,7 @@ const age = new Signal(25);
17
17
  // Подписка на изменения
18
18
  const subscription = name.subscribe(newName => {
19
19
  console.log(`Name changed to: ${newName}`);
20
- });
20
+ }); // Выведет: "Name changed to: John" при инициализации
21
21
 
22
22
  name.value = 'Jane'; // Выведет: "Name changed to: Jane"
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fozy-labs/rx-toolkit",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -1,2 +0,0 @@
1
- import { DevtoolsLike } from "../query/types/devtools";
2
- export declare function reduxDevtools(): DevtoolsLike;
File without changes
@@ -1 +0,0 @@
1
- "use strict";