@fozy-labs/rx-toolkit 0.4.11 → 0.4.13

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 (33) hide show
  1. package/dist/common/devtools/reduxDevtools.js +17 -2
  2. package/dist/common/devtools/types.d.ts +5 -0
  3. package/dist/common/options/DefaultOptions.d.ts +3 -0
  4. package/dist/common/options/DefaultOptions.js +4 -0
  5. package/dist/common/options/SharedOptions.d.ts +3 -0
  6. package/dist/common/options/SharedOptions.js +2 -0
  7. package/dist/query/core/Opertation/Operation.js +5 -1
  8. package/dist/query/core/Opertation/OperationAgent.js +2 -2
  9. package/dist/query/core/QueriesLifetimeHooks.d.ts +2 -1
  10. package/dist/query/core/QueriesLifetimeHooks.js +19 -19
  11. package/dist/query/core/Resource/Resource.js +5 -1
  12. package/dist/query/core/Resource/ResourceAgent.js +2 -2
  13. package/dist/query/types/Operation.types.d.ts +2 -2
  14. package/dist/query/types/Resource.types.d.ts +2 -2
  15. package/dist/signals/base/Devtools.d.ts +5 -0
  16. package/dist/signals/base/Devtools.js +35 -0
  17. package/dist/signals/base/index.d.ts +1 -3
  18. package/dist/signals/base/index.js +1 -3
  19. package/dist/signals/index.d.ts +1 -1
  20. package/dist/signals/index.js +1 -1
  21. package/dist/signals/{base → signals}/Computed.d.ts +3 -5
  22. package/dist/signals/{base → signals}/Computed.js +2 -2
  23. package/dist/signals/{base → signals}/Effect.js +1 -2
  24. package/dist/signals/{extends → signals}/LocalSignal.d.ts +2 -2
  25. package/dist/signals/{extends → signals}/LocalSignal.js +7 -2
  26. package/dist/signals/{base → signals}/Signal.d.ts +4 -8
  27. package/dist/signals/{base → signals}/Signal.js +8 -13
  28. package/dist/signals/signals/index.d.ts +4 -0
  29. package/dist/signals/signals/index.js +4 -0
  30. package/package.json +1 -1
  31. package/dist/signals/extends/index.d.ts +0 -1
  32. package/dist/signals/extends/index.js +0 -1
  33. /package/dist/signals/{base → signals}/Effect.d.ts +0 -0
@@ -22,7 +22,8 @@ export function reduxDevtools(options = {}) {
22
22
  };
23
23
  return {
24
24
  state(name, initState) {
25
- state = { ...state, [name]: initState };
25
+ const keys = name.split('/');
26
+ state = applyState(keys, initState, state);
26
27
  scheduler.schedule(createFn());
27
28
  return (newState) => {
28
29
  if (newState === '$COMPLETE' || newState === '$CLEANED') {
@@ -30,9 +31,23 @@ export function reduxDevtools(options = {}) {
30
31
  clearFn();
31
32
  return;
32
33
  }
33
- state = { ...state, [name]: newState };
34
+ state = applyState(keys, newState, state);
34
35
  scheduler.schedule(updateFn);
35
36
  };
36
37
  }
37
38
  };
38
39
  }
40
+ function applyState(keys, newState, state) {
41
+ const acc = { ...state };
42
+ let current = acc;
43
+ keys.forEach((key, i, arr) => {
44
+ if (i === arr.length - 1) {
45
+ current[key] = newState;
46
+ }
47
+ else {
48
+ current[key] = { ...(current[key] ?? {}) };
49
+ current = current[key];
50
+ }
51
+ });
52
+ return acc;
53
+ }
@@ -4,3 +4,8 @@ export interface DevtoolsStateLike<T = any> {
4
4
  export interface DevtoolsLike {
5
5
  state<T>(name: string, initState: T): DevtoolsStateLike<T>;
6
6
  }
7
+ export type StateDevtoolsOptions = {
8
+ isDisabled?: boolean;
9
+ name?: string;
10
+ base?: string;
11
+ } | string;
@@ -1,7 +1,10 @@
1
1
  import type { DevtoolsLike } from "../../common/devtools";
2
+ import { Observable } from "rxjs";
2
3
  type Update = Partial<{
3
4
  DEVTOOLS: DevtoolsLike | null;
4
5
  onQueryError: (error: unknown) => void;
6
+ getScopeName: () => string | null;
7
+ getScopeDestroyed$: () => Observable<void> | null;
5
8
  }>;
6
9
  export declare class DefaultOptions {
7
10
  static update(part: Update): void;
@@ -5,5 +5,9 @@ export class DefaultOptions {
5
5
  SharedOptions.DEVTOOLS = part.DEVTOOLS;
6
6
  if (part.onQueryError !== undefined)
7
7
  SharedOptions.onQueryError = part.onQueryError;
8
+ if (part.getScopeName !== undefined)
9
+ SharedOptions.getScopeName = part.getScopeName;
10
+ if (part.getScopeDestroyed$ !== undefined)
11
+ SharedOptions.getScopeDestroyed$ = part.getScopeDestroyed$;
8
12
  }
9
13
  }
@@ -1,5 +1,8 @@
1
1
  import { DevtoolsLike } from "../../common/devtools";
2
+ import { Observable } from "rxjs";
2
3
  export declare class SharedOptions {
3
4
  static DEVTOOLS: DevtoolsLike | null;
4
5
  static onQueryError: ((error: unknown) => void) | null;
6
+ static getScopeName: () => string | null;
7
+ static getScopeDestroyed$: () => Observable<void> | null;
5
8
  }
@@ -1,4 +1,6 @@
1
1
  export class SharedOptions {
2
2
  static DEVTOOLS = null;
3
3
  static onQueryError = null;
4
+ static getScopeName;
5
+ static getScopeDestroyed$;
4
6
  }
@@ -59,7 +59,11 @@ export class Operation {
59
59
  constructor(_options) {
60
60
  this._options = _options;
61
61
  this._queriesCache = new QueriesCache(this._options.cacheLifetime ?? this._DEFAULT_CACHE_LIFETIME);
62
- this._hooks = new QueriesLifetimeHooks(_options, _options.devtoolsName ?? 'Operation');
62
+ this._hooks = new QueriesLifetimeHooks({
63
+ onCacheEntryAdded: _options.onCacheEntryAdded,
64
+ onQueryStarted: _options.onQueryStarted,
65
+ devtoolsName: _options.devtoolsName,
66
+ });
63
67
  this._createLinks();
64
68
  }
65
69
  _createLinks() {
@@ -3,7 +3,7 @@ export class OperationAgent {
3
3
  _operation;
4
4
  _operations$ = new Signal({
5
5
  current$: null,
6
- }, { disableDevtools: true });
6
+ }, { isDisabled: true });
7
7
  state$ = new Computed(() => {
8
8
  const operations = this._operations$.value;
9
9
  const currState = operations.current$?.value$.value;
@@ -28,7 +28,7 @@ export class OperationAgent {
28
28
  data: currState.data ?? undefined,
29
29
  args: currState.arg,
30
30
  };
31
- }, { disableDevtools: true });
31
+ }, { isDisabled: true });
32
32
  constructor(_operation) {
33
33
  this._operation = _operation;
34
34
  }
@@ -3,11 +3,12 @@ import { OnCacheEntryAdded, OnQueryStarted } from "../../query/types";
3
3
  type Options<ARGS, DATA> = {
4
4
  onCacheEntryAdded?: OnCacheEntryAdded<ARGS, DATA>;
5
5
  onQueryStarted?: OnQueryStarted<ARGS, DATA>;
6
+ devtoolsName?: string | false;
6
7
  };
7
8
  export declare class QueriesLifetimeHooks<ARGS, DATA> {
8
9
  private onCacheEntryAddedListeners;
9
10
  private onQueryStartedListeners;
10
- constructor(options: Options<ARGS, DATA> | undefined, devtoolName: string | undefined);
11
+ constructor(options: Options<ARGS, DATA> | undefined);
11
12
  onCacheEntryAdded: (args: ARGS) => {
12
13
  cacheDataLoaded: () => void;
13
14
  cacheEntryRemoved: () => void;
@@ -1,35 +1,35 @@
1
1
  import { Subject } from "rxjs";
2
2
  import { SharedOptions } from "../../common/options/SharedOptions";
3
3
  import { PromiseResolver } from "../../common/utils";
4
- import { Indexer } from "../../signals/base/Indexer";
4
+ import { Devtools } from "../../signals";
5
5
  export class QueriesLifetimeHooks {
6
6
  onCacheEntryAddedListeners = [];
7
7
  onQueryStartedListeners = [];
8
- constructor(options, devtoolName) {
8
+ constructor(options) {
9
9
  if (options?.onCacheEntryAdded) {
10
10
  this.onCacheEntryAddedListeners.push(options.onCacheEntryAdded);
11
11
  }
12
12
  if (options?.onQueryStarted) {
13
13
  this.onQueryStartedListeners.push(options.onQueryStarted);
14
14
  }
15
- if (devtoolName) {
16
- const stateDevtools = SharedOptions.DEVTOOLS?.state;
17
- if (stateDevtools) {
18
- this.onCacheEntryAddedListeners.push(async (args, { $cacheEntryRemoved, dataChanged$ }) => {
19
- const key = `${devtoolName}:${JSON.stringify(args)}:i=${Indexer.getIndex()}`;
20
- let devtools = null;
21
- dataChanged$.subscribe((state) => {
22
- if (!devtools) {
23
- devtools = stateDevtools(key, state);
24
- return;
25
- }
26
- devtools(state);
27
- });
28
- $cacheEntryRemoved.then(() => {
29
- devtools('$CLEANED');
30
- });
15
+ const devtoolsName = options?.devtoolsName;
16
+ if (devtoolsName !== false && Devtools.hasDevtools) {
17
+ this.onCacheEntryAddedListeners.push(async (_, { $cacheEntryRemoved, dataChanged$ }) => {
18
+ let stateDevtools = null;
19
+ dataChanged$.subscribe((state) => {
20
+ if (!stateDevtools) {
21
+ stateDevtools = Devtools.createState(state, {
22
+ base: 'Queries',
23
+ name: devtoolsName || '',
24
+ });
25
+ return;
26
+ }
27
+ stateDevtools(state);
31
28
  });
32
- }
29
+ $cacheEntryRemoved.then(() => {
30
+ stateDevtools('$CLEANED');
31
+ });
32
+ });
33
33
  }
34
34
  if (SharedOptions.onQueryError) {
35
35
  this.onQueryStartedListeners.push(async (_, { $queryFulfilled }) => {
@@ -108,7 +108,11 @@ export class Resource {
108
108
  _DEFAULT_CACHE_LIFETIME = 60_000;
109
109
  constructor(_options) {
110
110
  this._options = _options;
111
- this._hooks = new QueriesLifetimeHooks(_options, _options.devtoolsName ?? 'Resource');
111
+ this._hooks = new QueriesLifetimeHooks({
112
+ onCacheEntryAdded: _options.onCacheEntryAdded,
113
+ onQueryStarted: _options.onQueryStarted,
114
+ devtoolsName: _options.devtoolsName,
115
+ });
112
116
  this._queriesCache = new QueriesCache(_options.cacheLifetime ?? this._DEFAULT_CACHE_LIFETIME);
113
117
  }
114
118
  createAgent = () => {
@@ -4,7 +4,7 @@ export class ResourceAgent {
4
4
  _resources$ = new Signal({
5
5
  previous$: null,
6
6
  current$: null,
7
- }, { disableDevtools: true });
7
+ }, { isDisabled: true });
8
8
  state$ = new Computed(() => {
9
9
  const resources = this._resources$.value;
10
10
  let prevState;
@@ -41,7 +41,7 @@ export class ResourceAgent {
41
41
  data: isShowPrev ? prevState.data ?? undefined : currState.data ?? undefined,
42
42
  args: currState.args ?? undefined,
43
43
  };
44
- }, { disableDevtools: true });
44
+ }, { isDisabled: true });
45
45
  constructor(_resource) {
46
46
  this._resource = _resource;
47
47
  }
@@ -34,9 +34,9 @@ export type OperationCreateOptions<D extends OperationDefinition> = {
34
34
  */
35
35
  onQueryStarted?: OnQueryStarted<D["Args"], D["Result"]>;
36
36
  /**
37
- * Имя для инструментов разработчика (DevTools)
37
+ * Настройка отображения в devtools
38
38
  */
39
- devtoolsName?: string | undefined | null;
39
+ devtoolsName?: string | false;
40
40
  };
41
41
  /**
42
42
  * Настройки связи операции с ресурсом
@@ -32,9 +32,9 @@ export type ResourceCreateOptions<D extends ResourceDefinition> = {
32
32
  */
33
33
  onQueryStarted?: OnQueryStarted<D["Args"], D["Result"]>;
34
34
  /**
35
- * Имя ресурса в инструментах разработчика
35
+ * Настройка отображения в devtools
36
36
  */
37
- devtoolsName?: string | undefined | null;
37
+ devtoolsName?: string | false;
38
38
  };
39
39
  /**
40
40
  * Определение типов ресурса
@@ -0,0 +1,5 @@
1
+ import { StateDevtoolsOptions } from "../../common/devtools";
2
+ export declare const Devtools: {
3
+ createState<T>(initialValue: T, optionsDry?: StateDevtoolsOptions): import("../../common/devtools").DevtoolsStateLike<T> | null;
4
+ readonly hasDevtools: boolean;
5
+ };
@@ -0,0 +1,35 @@
1
+ import { SharedOptions } from "../../common/options/SharedOptions";
2
+ import { Indexer } from "./Indexer";
3
+ export const Devtools = {
4
+ createState(initialValue, optionsDry = {}) {
5
+ const options = typeof optionsDry === 'string'
6
+ ? { name: optionsDry }
7
+ : optionsDry;
8
+ if (options.isDisabled)
9
+ return null;
10
+ let createStateDevtools = SharedOptions.DEVTOOLS?.state;
11
+ if (!createStateDevtools)
12
+ return null;
13
+ const key = createKey(options.name, options.base);
14
+ return createStateDevtools(key, initialValue);
15
+ },
16
+ get hasDevtools() {
17
+ return !!SharedOptions.DEVTOOLS?.state;
18
+ },
19
+ };
20
+ function createKey(name, base) {
21
+ const i = Indexer.getIndex();
22
+ let key = '';
23
+ if (name?.includes('{scope}')) {
24
+ const scopeName = SharedOptions.getScopeName?.() || '#global';
25
+ name = name.replace('{scope}', scopeName);
26
+ }
27
+ if (base && name)
28
+ key += name.replace('{base}', base);
29
+ else if (!base && name)
30
+ key += name;
31
+ else if (base && !name)
32
+ key += `${base}/`;
33
+ key += `#i=${i}`;
34
+ return key;
35
+ }
@@ -1,8 +1,6 @@
1
1
  export * from './Batcher';
2
- export * from './Computed';
3
- export * from './Effect';
2
+ export * from './Devtools';
4
3
  export * from './ReadonlySignal';
5
- export * from './Signal';
6
4
  export * from './SyncObservable';
7
5
  export * from './Tracker';
8
6
  export * from './types';
@@ -1,8 +1,6 @@
1
1
  export * from './Batcher';
2
- export * from './Computed';
3
- export * from './Effect';
2
+ export * from './Devtools';
4
3
  export * from './ReadonlySignal';
5
- export * from './Signal';
6
4
  export * from './SyncObservable';
7
5
  export * from './Tracker';
8
6
  export * from './types';
@@ -1,4 +1,4 @@
1
1
  export * from './base';
2
- export * from './extends';
3
2
  export * from './operators';
4
3
  export * from './react';
4
+ export * from './signals';
@@ -1,4 +1,4 @@
1
1
  export * from './base';
2
- export * from './extends';
3
2
  export * from './operators';
4
3
  export * from './react';
4
+ export * from './signals';
@@ -1,13 +1,11 @@
1
1
  import { SubscriptionLike } from "rxjs";
2
- import { ReadableSignalLike } from "./types";
2
+ import { ReadableSignalLike } from "../base";
3
3
  import { Signal } from "./Signal";
4
+ import { StateDevtoolsOptions } from "../../common/devtools";
4
5
  export declare class Computed<T> extends Signal<T> implements SubscriptionLike, ReadableSignalLike<T> {
5
6
  private static _EMPTY;
6
7
  private _effect;
7
- constructor(computeFn: () => T, options?: {
8
- disableDevtools?: boolean;
9
- devtoolsName?: string;
10
- });
8
+ constructor(computeFn: () => T, options?: StateDevtoolsOptions);
11
9
  complete(): void;
12
10
  /**
13
11
  * @deprecated use 'complete()' instead
@@ -16,8 +16,8 @@ export class Computed extends Signal {
16
16
  this.complete();
17
17
  });
18
18
  super(initialValue, {
19
- devtoolsName: 'Computed',
20
- ...options,
19
+ base: 'Computed',
20
+ ...(typeof options === 'string' ? { name: options } : options)
21
21
  });
22
22
  this._effect = effect;
23
23
  }
@@ -1,5 +1,4 @@
1
- import { Batcher } from "./Batcher";
2
- import { Tracker } from "./Tracker";
1
+ import { Batcher, Tracker } from "../base";
3
2
  export class Effect {
4
3
  _onComplete;
5
4
  _subscriptions = [];
@@ -1,6 +1,6 @@
1
1
  import { ZodType } from "zod/v4";
2
2
  import { Observable } from "rxjs";
3
- import { Computed } from "../base";
3
+ import { Computed } from "../signals";
4
4
  type Options<T> = {
5
5
  zodSchema?: ZodType<T>;
6
6
  key: string;
@@ -11,7 +11,7 @@ type Options<T> = {
11
11
  validator$?: Observable<(value: T) => boolean>;
12
12
  checkEffect?: (value: T) => boolean;
13
13
  defaultValue: T;
14
- devtoolsName?: string;
14
+ devtoolsName?: string | false;
15
15
  };
16
16
  export declare class LocalSignal<T = string | null | number | undefined> extends Computed<T> {
17
17
  private _options;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod/v4";
2
- import { Computed } from "../base";
2
+ import { Computed } from "../signals";
3
3
  import { signalize } from "../operators";
4
4
  const NullOrString = z.string().nullable();
5
5
  const NONE = Symbol('NONE');
@@ -41,6 +41,7 @@ export class LocalSignal extends Computed {
41
41
  const validator$ = _options.validator$;
42
42
  const checkEffect = _options.checkEffect;
43
43
  const defaultValue = _options.defaultValue;
44
+ const devtoolsName = _options.devtoolsName;
44
45
  const validatorSignal$ = validator$ && signalize(validator$);
45
46
  super(() => {
46
47
  const value = LocalSignal._getStorageValue(_options);
@@ -56,7 +57,11 @@ export class LocalSignal extends Computed {
56
57
  return checkEffect(value) ? value : defaultValue;
57
58
  }
58
59
  return value;
59
- }, { devtoolsName: _options.devtoolsName ?? 'LocalSignal' });
60
+ }, {
61
+ isDisabled: devtoolsName === false,
62
+ base: 'LocalSignals',
63
+ name: devtoolsName || undefined,
64
+ });
60
65
  this._options = _options;
61
66
  }
62
67
  _onChange(value) {
@@ -1,13 +1,10 @@
1
1
  import { BehaviorSubject, Observable, SubscriptionLike } from "rxjs";
2
- import type { ReadableSignalLike, SignalLike, UnaryFunction } from "./types";
3
- type SignalOptions = {
4
- disableDevtools?: boolean;
5
- devtoolsName?: string;
6
- };
2
+ import { ReadableSignalLike, SignalLike, UnaryFunction } from "../base";
3
+ import { StateDevtoolsOptions } from "../../common/devtools";
7
4
  export declare class Signal<T> extends BehaviorSubject<T> implements SubscriptionLike, SignalLike<T> {
8
- private readonly _devtools;
5
+ private readonly _stateDevtools;
9
6
  protected _rang: number;
10
- constructor(initialValue: T, options?: SignalOptions);
7
+ constructor(initialValue: T, options?: StateDevtoolsOptions);
11
8
  protected _onChange(value: T): void;
12
9
  get value(): T;
13
10
  set value(value: T);
@@ -43,4 +40,3 @@ export declare class Signal<T> extends BehaviorSubject<T> implements Subscriptio
43
40
  pipe<A extends Observable<any>, B extends Observable<any>, C extends Observable<any>, D extends Observable<any>, E extends Observable<any>, F extends Observable<any>, G extends Observable<any>, H extends Observable<any>, I extends Observable<any>>(op1: UnaryFunction<Signal<T>, A>, op2: UnaryFunction<A, B>, op3: UnaryFunction<B, C>, op4: UnaryFunction<C, D>, op5: UnaryFunction<D, E>, op6: UnaryFunction<E, F>, op7: UnaryFunction<F, G>, op8: UnaryFunction<G, H>, op9: UnaryFunction<H, I>): I;
44
41
  pipe<A extends Observable<any>, B extends Observable<any>, C extends Observable<any>, D extends Observable<any>, E extends Observable<any>, F extends Observable<any>, G extends Observable<any>, H extends Observable<any>, I extends Observable<any>>(op1: UnaryFunction<Signal<T>, A>, op2: UnaryFunction<A, B>, op3: UnaryFunction<B, C>, op4: UnaryFunction<C, D>, op5: UnaryFunction<D, E>, op6: UnaryFunction<E, F>, op7: UnaryFunction<F, G>, op8: UnaryFunction<G, H>, op9: UnaryFunction<H, I>, ...operations: UnaryFunction<Observable<any>, Observable<any>>[]): Observable<unknown>;
45
42
  }
46
- export {};
@@ -1,23 +1,18 @@
1
1
  import { BehaviorSubject } from "rxjs";
2
- import { SharedOptions } from "../../common/options/SharedOptions";
3
- import { Batcher } from "./Batcher";
4
- import { Indexer } from "./Indexer";
5
- import { Tracker } from "./Tracker";
2
+ import { Batcher, Tracker, Devtools } from "../base";
6
3
  export class Signal extends BehaviorSubject {
7
- _devtools;
4
+ _stateDevtools;
8
5
  _rang = 0;
9
6
  constructor(initialValue, options) {
10
7
  super(initialValue);
11
- const stateDevtools = SharedOptions.DEVTOOLS?.state;
12
- if (stateDevtools && options?.disableDevtools !== true) {
13
- const id = Indexer.getIndex();
14
- const key = `${options?.devtoolsName || 'Signal'}:i=${id}`;
15
- this._devtools = stateDevtools(key, initialValue);
16
- }
8
+ this._stateDevtools = Devtools.createState(initialValue, {
9
+ base: 'Signals',
10
+ ...(typeof options === 'string' ? { name: options } : options)
11
+ });
17
12
  }
18
13
  _onChange(value) {
19
14
  Batcher.batch(() => {
20
- this._devtools?.(value);
15
+ this._stateDevtools?.(value);
21
16
  super.next(value);
22
17
  });
23
18
  }
@@ -53,7 +48,7 @@ export class Signal extends BehaviorSubject {
53
48
  return this.next(value);
54
49
  }
55
50
  complete() {
56
- this._devtools?.('$COMPLETE');
51
+ this._stateDevtools?.('$COMPLETE');
57
52
  super.complete();
58
53
  }
59
54
  /**
@@ -0,0 +1,4 @@
1
+ export * from './Computed';
2
+ export * from './Effect';
3
+ export * from './LocalSignal';
4
+ export * from './Signal';
@@ -0,0 +1,4 @@
1
+ export * from './Computed';
2
+ export * from './Effect';
3
+ export * from './LocalSignal';
4
+ export * from './Signal';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fozy-labs/rx-toolkit",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- export * from './LocalSignal';
@@ -1 +0,0 @@
1
- export * from './LocalSignal';
File without changes