@chromahq/store 1.0.40 → 1.0.42

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.js CHANGED
@@ -127,8 +127,8 @@ class BridgeStore {
127
127
  this.stateChangedHandler = null;
128
128
  // Debounce timer for state sync (optimization for rapid updates)
129
129
  this.stateSyncDebounceTimer = null;
130
- this.stateSyncDebounceMs = 16;
131
- // ~1 frame at 60fps
130
+ this.stateSyncDebounceMs = 100;
131
+ // Increased to 100ms to reduce burst traffic on Windows
132
132
  // Reconnect delay timer (to allow SW to bootstrap before re-initializing)
133
133
  this.reconnectDelayTimer = null;
134
134
  this.initialize = async () => {
@@ -392,11 +392,28 @@ class BridgeStore {
392
392
  );
393
393
  }
394
394
  this.forceInitialize();
395
- }, 500);
395
+ }, 1500);
396
396
  };
397
397
  this.bridge.on("bridge:connected", this.reconnectHandler);
398
398
  }
399
399
  }
400
+ /**
401
+ * Apply state directly from broadcast payload (no round-trip)
402
+ */
403
+ applyBroadcastState(newState) {
404
+ if (!newState || typeof newState !== "object") {
405
+ if (STORE_ENABLE_LOGS) {
406
+ console.warn(`BridgeStore[${this.storeName}]: Invalid broadcast state, ignoring`);
407
+ }
408
+ return;
409
+ }
410
+ this.previousState = this.currentState;
411
+ this.currentState = newState;
412
+ this.notifyListeners();
413
+ }
414
+ /**
415
+ * Fetch state from SW (fallback when broadcast doesn't include payload)
416
+ */
400
417
  fetchAndApplyState() {
401
418
  if (this.pendingStateSync) {
402
419
  return;
@@ -419,13 +436,17 @@ class BridgeStore {
419
436
  }
420
437
  setupStateSync() {
421
438
  if (this.bridge.on) {
422
- this.stateChangedHandler = () => {
439
+ this.stateChangedHandler = (payload) => {
423
440
  if (this.stateSyncDebounceTimer) {
424
441
  clearTimeout(this.stateSyncDebounceTimer);
425
442
  }
426
443
  this.stateSyncDebounceTimer = setTimeout(() => {
427
444
  this.stateSyncDebounceTimer = null;
428
- this.fetchAndApplyState();
445
+ if (payload && typeof payload === "object") {
446
+ this.applyBroadcastState(payload);
447
+ } else {
448
+ this.fetchAndApplyState();
449
+ }
429
450
  }, this.stateSyncDebounceMs);
430
451
  };
431
452
  this.bridge.on(`store:${this.storeName}:stateChanged`, this.stateChangedHandler);
@@ -658,9 +679,17 @@ class StoreBuilder {
658
679
  };
659
680
  const persistedCreator = chromeStoragePersist(persistOptions)(creator);
660
681
  const store = vanilla.createStore(persistedCreator);
682
+ let broadcastDebounceTimer = null;
683
+ const BROADCAST_DEBOUNCE_MS = 50;
661
684
  store.subscribe(() => {
662
685
  if (runtimeBridge) {
663
- runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
686
+ if (broadcastDebounceTimer) {
687
+ clearTimeout(broadcastDebounceTimer);
688
+ }
689
+ broadcastDebounceTimer = setTimeout(() => {
690
+ broadcastDebounceTimer = null;
691
+ runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
692
+ }, BROADCAST_DEBOUNCE_MS);
664
693
  }
665
694
  });
666
695
  const centralStore = Object.assign(store, {
package/dist/index.d.ts CHANGED
@@ -83,6 +83,13 @@ declare class BridgeStore<T> implements CentralStore<T> {
83
83
  initialize: () => Promise<void>;
84
84
  private stateSyncSequence;
85
85
  private pendingStateSync;
86
+ /**
87
+ * Apply state directly from broadcast payload (no round-trip)
88
+ */
89
+ private applyBroadcastState;
90
+ /**
91
+ * Fetch state from SW (fallback when broadcast doesn't include payload)
92
+ */
86
93
  private fetchAndApplyState;
87
94
  private setupStateSync;
88
95
  private notifyListeners;
package/dist/index.es.js CHANGED
@@ -107,8 +107,8 @@ class BridgeStore {
107
107
  this.stateChangedHandler = null;
108
108
  // Debounce timer for state sync (optimization for rapid updates)
109
109
  this.stateSyncDebounceTimer = null;
110
- this.stateSyncDebounceMs = 16;
111
- // ~1 frame at 60fps
110
+ this.stateSyncDebounceMs = 100;
111
+ // Increased to 100ms to reduce burst traffic on Windows
112
112
  // Reconnect delay timer (to allow SW to bootstrap before re-initializing)
113
113
  this.reconnectDelayTimer = null;
114
114
  this.initialize = async () => {
@@ -372,11 +372,28 @@ class BridgeStore {
372
372
  );
373
373
  }
374
374
  this.forceInitialize();
375
- }, 500);
375
+ }, 1500);
376
376
  };
377
377
  this.bridge.on("bridge:connected", this.reconnectHandler);
378
378
  }
379
379
  }
380
+ /**
381
+ * Apply state directly from broadcast payload (no round-trip)
382
+ */
383
+ applyBroadcastState(newState) {
384
+ if (!newState || typeof newState !== "object") {
385
+ if (STORE_ENABLE_LOGS) {
386
+ console.warn(`BridgeStore[${this.storeName}]: Invalid broadcast state, ignoring`);
387
+ }
388
+ return;
389
+ }
390
+ this.previousState = this.currentState;
391
+ this.currentState = newState;
392
+ this.notifyListeners();
393
+ }
394
+ /**
395
+ * Fetch state from SW (fallback when broadcast doesn't include payload)
396
+ */
380
397
  fetchAndApplyState() {
381
398
  if (this.pendingStateSync) {
382
399
  return;
@@ -399,13 +416,17 @@ class BridgeStore {
399
416
  }
400
417
  setupStateSync() {
401
418
  if (this.bridge.on) {
402
- this.stateChangedHandler = () => {
419
+ this.stateChangedHandler = (payload) => {
403
420
  if (this.stateSyncDebounceTimer) {
404
421
  clearTimeout(this.stateSyncDebounceTimer);
405
422
  }
406
423
  this.stateSyncDebounceTimer = setTimeout(() => {
407
424
  this.stateSyncDebounceTimer = null;
408
- this.fetchAndApplyState();
425
+ if (payload && typeof payload === "object") {
426
+ this.applyBroadcastState(payload);
427
+ } else {
428
+ this.fetchAndApplyState();
429
+ }
409
430
  }, this.stateSyncDebounceMs);
410
431
  };
411
432
  this.bridge.on(`store:${this.storeName}:stateChanged`, this.stateChangedHandler);
@@ -638,9 +659,17 @@ class StoreBuilder {
638
659
  };
639
660
  const persistedCreator = chromeStoragePersist(persistOptions)(creator);
640
661
  const store = createStore$1(persistedCreator);
662
+ let broadcastDebounceTimer = null;
663
+ const BROADCAST_DEBOUNCE_MS = 50;
641
664
  store.subscribe(() => {
642
665
  if (runtimeBridge) {
643
- runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
666
+ if (broadcastDebounceTimer) {
667
+ clearTimeout(broadcastDebounceTimer);
668
+ }
669
+ broadcastDebounceTimer = setTimeout(() => {
670
+ broadcastDebounceTimer = null;
671
+ runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
672
+ }, BROADCAST_DEBOUNCE_MS);
644
673
  }
645
674
  });
646
675
  const centralStore = Object.assign(store, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromahq/store",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "Centralized, persistent store for Chrome extensions using zustand, accessible from service workers and React, with chrome.storage.local persistence.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",