@yiin/reactive-proxy-state 1.0.35 → 1.0.37

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
@@ -4030,7 +4030,7 @@ function markRaw(obj) {
4030
4030
  var import_vue = require("vue");
4031
4031
  var import_reactivity = __toESM(require_reactivity_cjs(), 1);
4032
4032
  function trackVueReactiveEvents(vueState, emit, options = {}) {
4033
- const { emitInitialReplace = true } = options;
4033
+ const { emitInitialReplace = true, onDiffError } = options;
4034
4034
  if (emitInitialReplace) {
4035
4035
  try {
4036
4036
  emit({ action: "replace", path: [], newValue: deepClone(vueState) });
@@ -4039,6 +4039,7 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
4039
4039
  const prev = {};
4040
4040
  const pathStack = [];
4041
4041
  const keyStops = new Map;
4042
+ let rootStop = null;
4042
4043
  for (const k of Object.keys(vueState)) {
4043
4044
  prev[k] = deepClone(vueState[k]);
4044
4045
  }
@@ -4054,50 +4055,75 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
4054
4055
  prev[k] = result;
4055
4056
  }
4056
4057
  } catch (e) {
4057
- console.error("[trackVueReactiveEvents] diffAndClone threw for key", k, e);
4058
+ const errorPath = pathStack.slice();
4058
4059
  pathStack.length = 0;
4059
4060
  prev[k] = deepClone(vueState[k]);
4061
+ if (onDiffError) {
4062
+ onDiffError({ key: k, path: errorPath, error: e });
4063
+ }
4060
4064
  return;
4061
4065
  }
4062
4066
  pathStack.pop();
4063
4067
  }, { flush: "sync" });
4064
4068
  keyStops.set(k, stop);
4065
4069
  }
4066
- for (const k of Object.keys(prev)) {
4067
- createKeyEffect(k);
4068
- }
4069
- const stopRoot = import_vue.watchEffect(() => {
4070
- const currKeys = Object.keys(vueState);
4071
- const currKeySet = new Set(currKeys);
4072
- const prevKeySet = new Set(Object.keys(prev));
4073
- for (const k of currKeys) {
4074
- if (!prevKeySet.has(k)) {
4075
- import_reactivity.pauseTracking();
4076
- const cloned = deepClone(vueState[k]);
4077
- import_reactivity.resetTracking();
4078
- pathStack.push(k);
4079
- emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4080
- pathStack.pop();
4081
- prev[k] = cloned;
4082
- createKeyEffect(k);
4083
- }
4084
- }
4085
- for (const k of prevKeySet) {
4086
- if (!currKeySet.has(k)) {
4087
- pathStack.push(k);
4088
- emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4089
- pathStack.pop();
4090
- delete prev[k];
4091
- keyStops.get(k)?.();
4092
- keyStops.delete(k);
4093
- }
4094
- }
4095
- }, { flush: "sync" });
4096
- return () => {
4097
- stopRoot();
4070
+ function createRootEffect() {
4071
+ rootStop = import_vue.watchEffect(() => {
4072
+ const currKeys = Object.keys(vueState);
4073
+ const currKeySet = new Set(currKeys);
4074
+ const prevKeySet = new Set(Object.keys(prev));
4075
+ for (const k of currKeys) {
4076
+ if (!prevKeySet.has(k)) {
4077
+ import_reactivity.pauseTracking();
4078
+ const cloned = deepClone(vueState[k]);
4079
+ import_reactivity.resetTracking();
4080
+ pathStack.push(k);
4081
+ emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4082
+ pathStack.pop();
4083
+ prev[k] = cloned;
4084
+ createKeyEffect(k);
4085
+ }
4086
+ }
4087
+ for (const k of prevKeySet) {
4088
+ if (!currKeySet.has(k)) {
4089
+ pathStack.push(k);
4090
+ emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4091
+ pathStack.pop();
4092
+ delete prev[k];
4093
+ keyStops.get(k)?.();
4094
+ keyStops.delete(k);
4095
+ }
4096
+ }
4097
+ }, { flush: "sync" });
4098
+ }
4099
+ function stopAll() {
4100
+ rootStop?.();
4101
+ rootStop = null;
4098
4102
  for (const stop of keyStops.values())
4099
4103
  stop();
4100
4104
  keyStops.clear();
4105
+ }
4106
+ function startAll() {
4107
+ for (const k of Object.keys(prev)) {
4108
+ createKeyEffect(k);
4109
+ }
4110
+ createRootEffect();
4111
+ }
4112
+ startAll();
4113
+ return {
4114
+ stop: stopAll,
4115
+ pause: stopAll,
4116
+ resume() {
4117
+ const currentKeys = new Set(Object.keys(vueState));
4118
+ for (const k of Object.keys(prev)) {
4119
+ if (!currentKeys.has(k))
4120
+ delete prev[k];
4121
+ }
4122
+ for (const k of currentKeys) {
4123
+ prev[k] = deepClone(vueState[k]);
4124
+ }
4125
+ startAll();
4126
+ }
4101
4127
  };
4102
4128
  }
4103
4129
  function typeTag(v) {
package/dist/index.js CHANGED
@@ -3970,7 +3970,7 @@ function markRaw(obj) {
3970
3970
  var import_reactivity = __toESM(require_reactivity_cjs(), 1);
3971
3971
  import { watchEffect as watchEffect2 } from "vue";
3972
3972
  function trackVueReactiveEvents(vueState, emit, options = {}) {
3973
- const { emitInitialReplace = true } = options;
3973
+ const { emitInitialReplace = true, onDiffError } = options;
3974
3974
  if (emitInitialReplace) {
3975
3975
  try {
3976
3976
  emit({ action: "replace", path: [], newValue: deepClone(vueState) });
@@ -3979,6 +3979,7 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
3979
3979
  const prev = {};
3980
3980
  const pathStack = [];
3981
3981
  const keyStops = new Map;
3982
+ let rootStop = null;
3982
3983
  for (const k of Object.keys(vueState)) {
3983
3984
  prev[k] = deepClone(vueState[k]);
3984
3985
  }
@@ -3994,50 +3995,75 @@ function trackVueReactiveEvents(vueState, emit, options = {}) {
3994
3995
  prev[k] = result;
3995
3996
  }
3996
3997
  } catch (e) {
3997
- console.error("[trackVueReactiveEvents] diffAndClone threw for key", k, e);
3998
+ const errorPath = pathStack.slice();
3998
3999
  pathStack.length = 0;
3999
4000
  prev[k] = deepClone(vueState[k]);
4001
+ if (onDiffError) {
4002
+ onDiffError({ key: k, path: errorPath, error: e });
4003
+ }
4000
4004
  return;
4001
4005
  }
4002
4006
  pathStack.pop();
4003
4007
  }, { flush: "sync" });
4004
4008
  keyStops.set(k, stop);
4005
4009
  }
4006
- for (const k of Object.keys(prev)) {
4007
- createKeyEffect(k);
4008
- }
4009
- const stopRoot = watchEffect2(() => {
4010
- const currKeys = Object.keys(vueState);
4011
- const currKeySet = new Set(currKeys);
4012
- const prevKeySet = new Set(Object.keys(prev));
4013
- for (const k of currKeys) {
4014
- if (!prevKeySet.has(k)) {
4015
- import_reactivity.pauseTracking();
4016
- const cloned = deepClone(vueState[k]);
4017
- import_reactivity.resetTracking();
4018
- pathStack.push(k);
4019
- emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4020
- pathStack.pop();
4021
- prev[k] = cloned;
4022
- createKeyEffect(k);
4023
- }
4024
- }
4025
- for (const k of prevKeySet) {
4026
- if (!currKeySet.has(k)) {
4027
- pathStack.push(k);
4028
- emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4029
- pathStack.pop();
4030
- delete prev[k];
4031
- keyStops.get(k)?.();
4032
- keyStops.delete(k);
4033
- }
4034
- }
4035
- }, { flush: "sync" });
4036
- return () => {
4037
- stopRoot();
4010
+ function createRootEffect() {
4011
+ rootStop = watchEffect2(() => {
4012
+ const currKeys = Object.keys(vueState);
4013
+ const currKeySet = new Set(currKeys);
4014
+ const prevKeySet = new Set(Object.keys(prev));
4015
+ for (const k of currKeys) {
4016
+ if (!prevKeySet.has(k)) {
4017
+ import_reactivity.pauseTracking();
4018
+ const cloned = deepClone(vueState[k]);
4019
+ import_reactivity.resetTracking();
4020
+ pathStack.push(k);
4021
+ emit({ action: "set", path: pathStack.slice(), newValue: cloned });
4022
+ pathStack.pop();
4023
+ prev[k] = cloned;
4024
+ createKeyEffect(k);
4025
+ }
4026
+ }
4027
+ for (const k of prevKeySet) {
4028
+ if (!currKeySet.has(k)) {
4029
+ pathStack.push(k);
4030
+ emit({ action: "delete", path: pathStack.slice(), oldValue: prev[k] });
4031
+ pathStack.pop();
4032
+ delete prev[k];
4033
+ keyStops.get(k)?.();
4034
+ keyStops.delete(k);
4035
+ }
4036
+ }
4037
+ }, { flush: "sync" });
4038
+ }
4039
+ function stopAll() {
4040
+ rootStop?.();
4041
+ rootStop = null;
4038
4042
  for (const stop of keyStops.values())
4039
4043
  stop();
4040
4044
  keyStops.clear();
4045
+ }
4046
+ function startAll() {
4047
+ for (const k of Object.keys(prev)) {
4048
+ createKeyEffect(k);
4049
+ }
4050
+ createRootEffect();
4051
+ }
4052
+ startAll();
4053
+ return {
4054
+ stop: stopAll,
4055
+ pause: stopAll,
4056
+ resume() {
4057
+ const currentKeys = new Set(Object.keys(vueState));
4058
+ for (const k of Object.keys(prev)) {
4059
+ if (!currentKeys.has(k))
4060
+ delete prev[k];
4061
+ }
4062
+ for (const k of currentKeys) {
4063
+ prev[k] = deepClone(vueState[k]);
4064
+ }
4065
+ startAll();
4066
+ }
4041
4067
  };
4042
4068
  }
4043
4069
  function typeTag(v) {
@@ -1,6 +1,20 @@
1
1
  import type { StateEvent } from "../types";
2
+ export type DiffErrorContext = {
3
+ key: string;
4
+ path: (string | number | symbol)[];
5
+ error: unknown;
6
+ };
2
7
  export type TrackVueReactiveEventsOptions = {
3
8
  emitInitialReplace?: boolean;
9
+ onDiffError?: (ctx: DiffErrorContext) => void;
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;
4
18
  };
5
19
  /**
6
20
  * Observe a Vue 3 reactive object and emit RPS-compatible StateEvents
@@ -10,6 +24,7 @@ export type TrackVueReactiveEventsOptions = {
10
24
  * only the affected subtree is diffed on mutation. A root structural effect
11
25
  * tracks Object.keys() for key add/delete at the top level.
12
26
  *
13
- * 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).
14
29
  */
15
- 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yiin/reactive-proxy-state",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
4
4
  "author": "Yiin <stanislovas@yiin.lt>",
5
5
  "repository": {
6
6
  "type": "git",