@yiin/reactive-proxy-state 1.0.36 → 1.0.38

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/dist/index.cjs CHANGED
@@ -2340,6 +2340,7 @@ __export(exports_src, {
2340
2340
  toRaw: () => toRaw,
2341
2341
  setActiveEffect: () => setActiveEffect,
2342
2342
  runCleanupFunctions: () => runCleanupFunctions,
2343
+ resetProxyStats: () => resetProxyStats,
2343
2344
  ref: () => ref,
2344
2345
  reactive: () => reactive,
2345
2346
  markRaw: () => markRaw,
@@ -2347,6 +2348,7 @@ __export(exports_src, {
2347
2348
  isRef: () => isRef,
2348
2349
  isReactive: () => isReactive,
2349
2350
  isComputed: () => isComputed,
2351
+ getProxyStats: () => getProxyStats,
2350
2352
  deepToRaw: () => deepToRaw,
2351
2353
  deepEqual: () => deepEqual,
2352
2354
  deepClone: () => deepClone,
@@ -2368,6 +2370,25 @@ var pathConcatCache = new Map;
2368
2370
  var MAX_PATH_CACHE_SIZE = 1000;
2369
2371
  var globalSeen = new WeakMap;
2370
2372
  var wrapperCache = new WeakMap;
2373
+ var proxyStats = {
2374
+ created: 0,
2375
+ arrays: 0,
2376
+ maps: 0,
2377
+ sets: 0,
2378
+ objects: 0,
2379
+ staleEvicted: 0
2380
+ };
2381
+ function getProxyStats() {
2382
+ return { ...proxyStats, pathConcatCacheSize: pathConcatCache.size };
2383
+ }
2384
+ function resetProxyStats() {
2385
+ proxyStats.created = 0;
2386
+ proxyStats.arrays = 0;
2387
+ proxyStats.maps = 0;
2388
+ proxyStats.sets = 0;
2389
+ proxyStats.objects = 0;
2390
+ proxyStats.staleEvicted = 0;
2391
+ }
2371
2392
  function cleanupPathCache(root) {
2372
2393
  const cache = pathCache.get(root);
2373
2394
  if (cache && pathCacheSize.get(root) > MAX_CACHE_SIZE) {
@@ -3154,6 +3175,8 @@ function wrapSet(set, emit, path = []) {
3154
3175
  });
3155
3176
  globalSeen.set(set, proxy);
3156
3177
  wrapperCache.set(set, proxy);
3178
+ proxyStats.created++;
3179
+ proxyStats.sets++;
3157
3180
  return proxy;
3158
3181
  }
3159
3182
 
@@ -3395,6 +3418,8 @@ function wrapMap(map, emit, path = []) {
3395
3418
  });
3396
3419
  globalSeen.set(map, proxy);
3397
3420
  wrapperCache.set(map, proxy);
3421
+ proxyStats.created++;
3422
+ proxyStats.maps++;
3398
3423
  return proxy;
3399
3424
  }
3400
3425
 
@@ -3692,6 +3717,8 @@ function wrapArray(arr, emit, path = []) {
3692
3717
  });
3693
3718
  globalSeen.set(arr, proxy);
3694
3719
  wrapperCache.set(arr, proxy);
3720
+ proxyStats.created++;
3721
+ proxyStats.arrays++;
3695
3722
  return proxy;
3696
3723
  }
3697
3724
 
@@ -3813,6 +3840,11 @@ function reactive(obj, emit, path = [], options) {
3813
3840
  };
3814
3841
  emit?.(event);
3815
3842
  trigger(target, prop);
3843
+ if (isObject3(oldValue) && oldValue !== value) {
3844
+ globalSeen.delete(oldValue);
3845
+ wrapperCache.delete(oldValue);
3846
+ proxyStats.staleEvicted++;
3847
+ }
3816
3848
  }
3817
3849
  return result;
3818
3850
  },
@@ -3835,11 +3867,18 @@ function reactive(obj, emit, path = [], options) {
3835
3867
  };
3836
3868
  emit?.(event);
3837
3869
  trigger(target, prop);
3870
+ if (isObject3(oldValue)) {
3871
+ globalSeen.delete(oldValue);
3872
+ wrapperCache.delete(oldValue);
3873
+ proxyStats.staleEvicted++;
3874
+ }
3838
3875
  }
3839
3876
  return result;
3840
3877
  }
3841
3878
  });
3842
3879
  globalSeen.set(obj, proxy);
3880
+ proxyStats.created++;
3881
+ proxyStats.objects++;
3843
3882
  return proxy;
3844
3883
  }
3845
3884
  // src/ref.ts
@@ -4039,6 +4078,7 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
4039
4078
  const prev = {};
4040
4079
  const pathStack = [];
4041
4080
  const keyStops = new Map;
4081
+ let rootStop = null;
4042
4082
  for (const k of Object.keys(vueState)) {
4043
4083
  prev[k] = deepClone(vueState[k]);
4044
4084
  }
@@ -4066,41 +4106,63 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
4066
4106
  }, { flush: "sync" });
4067
4107
  keyStops.set(k, stop);
4068
4108
  }
4069
- for (const k of Object.keys(prev)) {
4070
- createKeyEffect(k);
4071
- }
4072
- const stopRoot = import_vue.watchEffect(() => {
4073
- const currKeys = Object.keys(vueState);
4074
- const currKeySet = new Set(currKeys);
4075
- const prevKeySet = new Set(Object.keys(prev));
4076
- for (const k of currKeys) {
4077
- if (!prevKeySet.has(k)) {
4078
- import_reactivity.pauseTracking();
4079
- const cloned = deepClone(vueState[k]);
4080
- import_reactivity.resetTracking();
4081
- pathStack.push(k);
4082
- emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4083
- pathStack.pop();
4084
- prev[k] = cloned;
4085
- createKeyEffect(k);
4086
- }
4087
- }
4088
- for (const k of prevKeySet) {
4089
- if (!currKeySet.has(k)) {
4090
- pathStack.push(k);
4091
- emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4092
- pathStack.pop();
4093
- delete prev[k];
4094
- keyStops.get(k)?.();
4095
- keyStops.delete(k);
4096
- }
4097
- }
4098
- }, { flush: "sync" });
4099
- return () => {
4100
- stopRoot();
4109
+ function createRootEffect() {
4110
+ rootStop = import_vue.watchEffect(() => {
4111
+ const currKeys = Object.keys(vueState);
4112
+ const currKeySet = new Set(currKeys);
4113
+ const prevKeySet = new Set(Object.keys(prev));
4114
+ for (const k of currKeys) {
4115
+ if (!prevKeySet.has(k)) {
4116
+ import_reactivity.pauseTracking();
4117
+ const cloned = deepClone(vueState[k]);
4118
+ import_reactivity.resetTracking();
4119
+ pathStack.push(k);
4120
+ emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4121
+ pathStack.pop();
4122
+ prev[k] = cloned;
4123
+ createKeyEffect(k);
4124
+ }
4125
+ }
4126
+ for (const k of prevKeySet) {
4127
+ if (!currKeySet.has(k)) {
4128
+ pathStack.push(k);
4129
+ emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4130
+ pathStack.pop();
4131
+ delete prev[k];
4132
+ keyStops.get(k)?.();
4133
+ keyStops.delete(k);
4134
+ }
4135
+ }
4136
+ }, { flush: "sync" });
4137
+ }
4138
+ function stopAll() {
4139
+ rootStop?.();
4140
+ rootStop = null;
4101
4141
  for (const stop of keyStops.values())
4102
4142
  stop();
4103
4143
  keyStops.clear();
4144
+ }
4145
+ function startAll() {
4146
+ for (const k of Object.keys(prev)) {
4147
+ createKeyEffect(k);
4148
+ }
4149
+ createRootEffect();
4150
+ }
4151
+ startAll();
4152
+ return {
4153
+ stop: stopAll,
4154
+ pause: stopAll,
4155
+ resume() {
4156
+ const currentKeys = new Set(Object.keys(vueState));
4157
+ for (const k of Object.keys(prev)) {
4158
+ if (!currentKeys.has(k))
4159
+ delete prev[k];
4160
+ }
4161
+ for (const k of currentKeys) {
4162
+ prev[k] = deepClone(vueState[k]);
4163
+ }
4164
+ startAll();
4165
+ }
4104
4166
  };
4105
4167
  }
4106
4168
  function typeTag(v) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './types';
2
- export { deepClone, deepEqual } from './utils';
2
+ export { deepClone, deepEqual, getProxyStats, resetProxyStats } from './utils';
3
3
  export * from './state';
4
4
  export * from './reactive';
5
5
  export * from './watch';
package/dist/index.js CHANGED
@@ -2308,6 +2308,25 @@ var pathConcatCache = new Map;
2308
2308
  var MAX_PATH_CACHE_SIZE = 1000;
2309
2309
  var globalSeen = new WeakMap;
2310
2310
  var wrapperCache = new WeakMap;
2311
+ var proxyStats = {
2312
+ created: 0,
2313
+ arrays: 0,
2314
+ maps: 0,
2315
+ sets: 0,
2316
+ objects: 0,
2317
+ staleEvicted: 0
2318
+ };
2319
+ function getProxyStats() {
2320
+ return { ...proxyStats, pathConcatCacheSize: pathConcatCache.size };
2321
+ }
2322
+ function resetProxyStats() {
2323
+ proxyStats.created = 0;
2324
+ proxyStats.arrays = 0;
2325
+ proxyStats.maps = 0;
2326
+ proxyStats.sets = 0;
2327
+ proxyStats.objects = 0;
2328
+ proxyStats.staleEvicted = 0;
2329
+ }
2311
2330
  function cleanupPathCache(root) {
2312
2331
  const cache = pathCache.get(root);
2313
2332
  if (cache && pathCacheSize.get(root) > MAX_CACHE_SIZE) {
@@ -3094,6 +3113,8 @@ function wrapSet(set, emit, path = []) {
3094
3113
  });
3095
3114
  globalSeen.set(set, proxy);
3096
3115
  wrapperCache.set(set, proxy);
3116
+ proxyStats.created++;
3117
+ proxyStats.sets++;
3097
3118
  return proxy;
3098
3119
  }
3099
3120
 
@@ -3335,6 +3356,8 @@ function wrapMap(map, emit, path = []) {
3335
3356
  });
3336
3357
  globalSeen.set(map, proxy);
3337
3358
  wrapperCache.set(map, proxy);
3359
+ proxyStats.created++;
3360
+ proxyStats.maps++;
3338
3361
  return proxy;
3339
3362
  }
3340
3363
 
@@ -3632,6 +3655,8 @@ function wrapArray(arr, emit, path = []) {
3632
3655
  });
3633
3656
  globalSeen.set(arr, proxy);
3634
3657
  wrapperCache.set(arr, proxy);
3658
+ proxyStats.created++;
3659
+ proxyStats.arrays++;
3635
3660
  return proxy;
3636
3661
  }
3637
3662
 
@@ -3753,6 +3778,11 @@ function reactive(obj, emit, path = [], options) {
3753
3778
  };
3754
3779
  emit?.(event);
3755
3780
  trigger(target, prop);
3781
+ if (isObject3(oldValue) && oldValue !== value) {
3782
+ globalSeen.delete(oldValue);
3783
+ wrapperCache.delete(oldValue);
3784
+ proxyStats.staleEvicted++;
3785
+ }
3756
3786
  }
3757
3787
  return result;
3758
3788
  },
@@ -3775,11 +3805,18 @@ function reactive(obj, emit, path = [], options) {
3775
3805
  };
3776
3806
  emit?.(event);
3777
3807
  trigger(target, prop);
3808
+ if (isObject3(oldValue)) {
3809
+ globalSeen.delete(oldValue);
3810
+ wrapperCache.delete(oldValue);
3811
+ proxyStats.staleEvicted++;
3812
+ }
3778
3813
  }
3779
3814
  return result;
3780
3815
  }
3781
3816
  });
3782
3817
  globalSeen.set(obj, proxy);
3818
+ proxyStats.created++;
3819
+ proxyStats.objects++;
3783
3820
  return proxy;
3784
3821
  }
3785
3822
  // src/ref.ts
@@ -3979,6 +4016,7 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
3979
4016
  const prev = {};
3980
4017
  const pathStack = [];
3981
4018
  const keyStops = new Map;
4019
+ let rootStop = null;
3982
4020
  for (const k of Object.keys(vueState)) {
3983
4021
  prev[k] = deepClone(vueState[k]);
3984
4022
  }
@@ -4006,41 +4044,63 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
4006
4044
  }, { flush: "sync" });
4007
4045
  keyStops.set(k, stop);
4008
4046
  }
4009
- for (const k of Object.keys(prev)) {
4010
- createKeyEffect(k);
4011
- }
4012
- const stopRoot = watchEffect2(() => {
4013
- const currKeys = Object.keys(vueState);
4014
- const currKeySet = new Set(currKeys);
4015
- const prevKeySet = new Set(Object.keys(prev));
4016
- for (const k of currKeys) {
4017
- if (!prevKeySet.has(k)) {
4018
- import_reactivity.pauseTracking();
4019
- const cloned = deepClone(vueState[k]);
4020
- import_reactivity.resetTracking();
4021
- pathStack.push(k);
4022
- emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4023
- pathStack.pop();
4024
- prev[k] = cloned;
4025
- createKeyEffect(k);
4026
- }
4027
- }
4028
- for (const k of prevKeySet) {
4029
- if (!currKeySet.has(k)) {
4030
- pathStack.push(k);
4031
- emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4032
- pathStack.pop();
4033
- delete prev[k];
4034
- keyStops.get(k)?.();
4035
- keyStops.delete(k);
4036
- }
4037
- }
4038
- }, { flush: "sync" });
4039
- return () => {
4040
- stopRoot();
4047
+ function createRootEffect() {
4048
+ rootStop = watchEffect2(() => {
4049
+ const currKeys = Object.keys(vueState);
4050
+ const currKeySet = new Set(currKeys);
4051
+ const prevKeySet = new Set(Object.keys(prev));
4052
+ for (const k of currKeys) {
4053
+ if (!prevKeySet.has(k)) {
4054
+ import_reactivity.pauseTracking();
4055
+ const cloned = deepClone(vueState[k]);
4056
+ import_reactivity.resetTracking();
4057
+ pathStack.push(k);
4058
+ emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4059
+ pathStack.pop();
4060
+ prev[k] = cloned;
4061
+ createKeyEffect(k);
4062
+ }
4063
+ }
4064
+ for (const k of prevKeySet) {
4065
+ if (!currKeySet.has(k)) {
4066
+ pathStack.push(k);
4067
+ emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4068
+ pathStack.pop();
4069
+ delete prev[k];
4070
+ keyStops.get(k)?.();
4071
+ keyStops.delete(k);
4072
+ }
4073
+ }
4074
+ }, { flush: "sync" });
4075
+ }
4076
+ function stopAll() {
4077
+ rootStop?.();
4078
+ rootStop = null;
4041
4079
  for (const stop of keyStops.values())
4042
4080
  stop();
4043
4081
  keyStops.clear();
4082
+ }
4083
+ function startAll() {
4084
+ for (const k of Object.keys(prev)) {
4085
+ createKeyEffect(k);
4086
+ }
4087
+ createRootEffect();
4088
+ }
4089
+ startAll();
4090
+ return {
4091
+ stop: stopAll,
4092
+ pause: stopAll,
4093
+ resume() {
4094
+ const currentKeys = new Set(Object.keys(vueState));
4095
+ for (const k of Object.keys(prev)) {
4096
+ if (!currentKeys.has(k))
4097
+ delete prev[k];
4098
+ }
4099
+ for (const k of currentKeys) {
4100
+ prev[k] = deepClone(vueState[k]);
4101
+ }
4102
+ startAll();
4103
+ }
4044
4104
  };
4045
4105
  }
4046
4106
  function typeTag(v) {
@@ -4390,6 +4450,7 @@ export {
4390
4450
  toRaw,
4391
4451
  setActiveEffect,
4392
4452
  runCleanupFunctions,
4453
+ resetProxyStats,
4393
4454
  ref,
4394
4455
  reactive,
4395
4456
  markRaw,
@@ -4397,6 +4458,7 @@ export {
4397
4458
  isRef,
4398
4459
  isReactive,
4399
4460
  isComputed,
4461
+ getProxyStats,
4400
4462
  deepToRaw,
4401
4463
  deepEqual,
4402
4464
  deepClone,
@@ -8,6 +8,14 @@ export type TrackVueReactiveEventsOptions = {
8
8
  emitInitialReplace?: boolean;
9
9
  onDiffError?: (ctx: DiffErrorContext) => void;
10
10
  };
11
+ export type VueTrackingControl = {
12
+ /** Stop all effects permanently. */
13
+ stop: () => void;
14
+ /** Stop all effects temporarily. No diffing overhead while paused. */
15
+ pause: () => void;
16
+ /** Rebuild snapshots from current state and re-create effects. */
17
+ resume: () => void;
18
+ };
11
19
  /**
12
20
  * Observe a Vue 3 reactive object and emit RPS-compatible StateEvents
13
21
  * for each mutation performed through Vue reactivity.
@@ -16,6 +24,7 @@ export type TrackVueReactiveEventsOptions = {
16
24
  * only the affected subtree is diffed on mutation. A root structural effect
17
25
  * tracks Object.keys() for key add/delete at the top level.
18
26
  *
19
- * Returns a stop() function to tear down all effects.
27
+ * Returns a control object with stop/pause/resume. Use pause/resume to
28
+ * suppress diffing while applying external mutations (e.g. server events).
20
29
  */
21
- export declare function trackVueReactiveEvents<T extends object>(vueState: T, emit: (event: StateEvent) => void, options?: TrackVueReactiveEventsOptions): () => void;
30
+ export declare function trackVueReactiveEvents<T extends object>(vueState: T, emit: (event: StateEvent) => void, options?: TrackVueReactiveEventsOptions): VueTrackingControl;
package/dist/utils.d.ts CHANGED
@@ -2,6 +2,26 @@ export declare const pathCache: WeakMap<object, Map<string, any>>;
2
2
  export declare const pathConcatCache: Map<string, any[]>;
3
3
  export declare const globalSeen: WeakMap<any, any>;
4
4
  export declare const wrapperCache: WeakMap<object, object>;
5
+ export declare const proxyStats: {
6
+ created: number;
7
+ arrays: number;
8
+ maps: number;
9
+ sets: number;
10
+ objects: number;
11
+ /** Number of old proxied values evicted when replaced via set trap */
12
+ staleEvicted: number;
13
+ };
14
+ export declare function getProxyStats(): {
15
+ pathConcatCacheSize: number;
16
+ created: number;
17
+ arrays: number;
18
+ maps: number;
19
+ sets: number;
20
+ objects: number;
21
+ /** Number of old proxied values evicted when replaced via set trap */
22
+ staleEvicted: number;
23
+ };
24
+ export declare function resetProxyStats(): void;
5
25
  export declare function deepEqual(a: any, b: any, seen?: WeakMap<any, any>): boolean;
6
26
  export declare function getFromPathCache(root: object, pathKey: string): any | undefined;
7
27
  export declare function setInPathCache(root: object, pathKey: string, value: any): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yiin/reactive-proxy-state",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
4
4
  "author": "Yiin <stanislovas@yiin.lt>",
5
5
  "repository": {
6
6
  "type": "git",