@chromahq/store 1.0.4 → 1.0.6

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
@@ -260,11 +260,15 @@ class BridgeStore {
260
260
  }
261
261
  setupStateSync() {
262
262
  if (this.bridge.on) {
263
- this.bridge.on(`store:${this.storeName}:stateChanged`, (newState) => {
264
- this.previousState = this.currentState;
265
- this.currentState = newState;
266
- this.notifyListeners();
263
+ this.bridge.on(`store:${this.storeName}:stateChanged`, () => {
264
+ this.bridge.send(`store:${this.storeName}:getState`).then((newState) => {
265
+ this.previousState = this.currentState;
266
+ this.currentState = newState;
267
+ this.notifyListeners();
268
+ });
267
269
  });
270
+ } else {
271
+ console.warn(`BridgeStore[${this.storeName}]: Bridge does not support event listening`);
268
272
  }
269
273
  }
270
274
  setState(partial, replace) {
@@ -310,7 +314,7 @@ function useStoreActions(store) {
310
314
  store.setState((state) => ({ ...state, ...partial }));
311
315
  },
312
316
  updateWith: (updater) => {
313
- store.setState((state) => ({ ...state, ...updater(state) }));
317
+ store.setState((state) => updater(state));
314
318
  },
315
319
  replace: (newState) => {
316
320
  store.setState(newState, true);
@@ -397,6 +401,13 @@ class StoreBuilder {
397
401
  this.config.bridge = bridge;
398
402
  return this;
399
403
  }
404
+ /**
405
+ * Enable persistence with Chrome storage
406
+ */
407
+ withPersistence(options) {
408
+ this.config.persistence = options;
409
+ return this;
410
+ }
400
411
  /**
401
412
  * Create the store
402
413
  */
@@ -416,10 +427,13 @@ class StoreBuilder {
416
427
  createServiceWorkerStore() {
417
428
  let isReady = false;
418
429
  let initialState = null;
430
+ let runtimeBridge;
419
431
  const notifyReady = () => {
420
432
  isReady = true;
421
433
  readyCallbacks.forEach((callback) => callback());
434
+ this.onReadyCallbacks.forEach((callback) => callback());
422
435
  readyCallbacks.clear();
436
+ this.onReadyCallbacks.clear();
423
437
  };
424
438
  const creator = (set, get, store2) => {
425
439
  let state = {};
@@ -438,6 +452,11 @@ class StoreBuilder {
438
452
  };
439
453
  const persistedCreator = chromeStoragePersist(persistOptions)(creator);
440
454
  const store = vanilla.createStore(persistedCreator);
455
+ store.subscribe(() => {
456
+ if (runtimeBridge) {
457
+ runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
458
+ }
459
+ });
441
460
  const centralStore = Object.assign(store, {
442
461
  isReady: () => isReady,
443
462
  reset: () => {
@@ -447,6 +466,9 @@ class StoreBuilder {
447
466
  console.warn("ServiceWorkerStore: Cannot reset, initial state not available");
448
467
  }
449
468
  },
469
+ setBridge: (bridge) => {
470
+ runtimeBridge = bridge;
471
+ },
450
472
  onReady: (callback) => {
451
473
  if (isReady) {
452
474
  callback();
@@ -464,8 +486,19 @@ class StoreBuilder {
464
486
  function createStore(name) {
465
487
  return new StoreBuilder(name);
466
488
  }
489
+ function createServiceWorkerStore(slices, name = "default", persistOptions) {
490
+ const sliceArray = Array.isArray(slices) ? slices : [slices];
491
+ let builder = createStore(name).withSlices(...sliceArray);
492
+ if (persistOptions) {
493
+ builder = builder.withPersistence(persistOptions);
494
+ }
495
+ return builder.create();
496
+ }
497
+ function createUIStore(bridge, initialState, name = "default") {
498
+ return createBridgeStore(bridge, initialState, name);
499
+ }
467
500
 
468
- function autoRegisterStoreHandlers(store) {
501
+ function autoRegisterStoreHandlers(store, storeName = "default") {
469
502
  if (!store) {
470
503
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
471
504
  }
@@ -486,8 +519,8 @@ function autoRegisterStoreHandlers(store) {
486
519
  let replace = false;
487
520
  if (args.length === 1 && args[0] && typeof args[0] === "object") {
488
521
  const payload = args[0];
489
- if ("partial" in payload && "replace" in payload) {
490
- ({ partial, replace } = payload);
522
+ if ("partial" in payload) {
523
+ ({ partial, replace = false } = payload);
491
524
  } else {
492
525
  partial = payload;
493
526
  replace = false;
@@ -509,22 +542,13 @@ function autoRegisterStoreHandlers(store) {
509
542
  } else {
510
543
  store.setState(partial);
511
544
  }
512
- return store.getState();
513
- }
514
- }
515
- class AutoSubscribeToStoreMessage {
516
- handle() {
517
- if (!store) {
518
- throw new Error("Store instance not available");
519
- }
520
- store.subscribe((state, prevState) => {
521
- });
545
+ const updatedState = store.getState();
546
+ return updatedState;
522
547
  }
523
548
  }
524
549
  return {
525
550
  GetStoreStateMessage: AutoGetStoreStateMessage,
526
- SetStoreStateMessage: AutoSetStoreStateMessage,
527
- SubscribeToStoreMessage: AutoSubscribeToStoreMessage
551
+ SetStoreStateMessage: AutoSetStoreStateMessage
528
552
  };
529
553
  }
530
554
 
@@ -538,7 +562,7 @@ async function init(storeDefinition) {
538
562
  return {
539
563
  def: storeDefinition,
540
564
  store,
541
- classes: autoRegisterStoreHandlers(store)
565
+ classes: autoRegisterStoreHandlers(store, storeDefinition.name)
542
566
  };
543
567
  } catch (error) {
544
568
  console.error(`Failed to initialize store "${storeDefinition.name}":`, error);
@@ -551,8 +575,10 @@ exports.StoreBuilder = StoreBuilder;
551
575
  exports.chromeStoragePersist = chromeStoragePersist;
552
576
  exports.createActionHookForStore = createActionHookForStore;
553
577
  exports.createBridgeStore = createBridgeStore;
578
+ exports.createServiceWorkerStore = createServiceWorkerStore;
554
579
  exports.createStore = createStore;
555
580
  exports.createStoreHooks = createStoreHooks;
581
+ exports.createUIStore = createUIStore;
556
582
  exports.init = init;
557
583
  exports.useCentralDispatch = useCentralDispatch;
558
584
  exports.useCentralStore = useCentralStore;
package/dist/index.d.ts CHANGED
@@ -162,6 +162,10 @@ declare class StoreBuilder<T = any> {
162
162
  * Attach a bridge for cross-context communication
163
163
  */
164
164
  withBridge(bridge?: BridgeWithEvents): this;
165
+ /**
166
+ * Enable persistence with Chrome storage
167
+ */
168
+ withPersistence(options?: PersistOptions): this;
165
169
  /**
166
170
  * Create the store
167
171
  */
@@ -173,11 +177,21 @@ declare class StoreBuilder<T = any> {
173
177
  * Create a new store builder
174
178
  */
175
179
  declare function createStore<T = any>(name?: string): StoreBuilder<T>;
180
+ /**
181
+ * Create a service worker store directly (convenience function)
182
+ * This creates a store optimized for service worker context with persistence
183
+ */
184
+ declare function createServiceWorkerStore<T = any>(slices: StateCreator$1<T, [], [], T>[] | StateCreator$1<T, [], [], T>, name?: string, persistOptions?: PersistOptions): Promise<CentralStore<T>>;
185
+ /**
186
+ * Create a bridge store directly (convenience function)
187
+ * This creates a store optimized for UI context that connects to service worker
188
+ */
189
+ declare function createUIStore<T = any>(bridge: BridgeWithEvents, initialState?: T, name?: string): CentralStore<T>;
176
190
 
177
191
  /**
178
192
  * Initialize a store from a store definition
179
193
  */
180
194
  declare function init(storeDefinition: StoreDefinition): Promise<any>;
181
195
 
182
- export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, init, useCentralDispatch, useCentralStore, useStoreReady, useStoreReset };
196
+ export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createServiceWorkerStore, createStore, createStoreHooks, createUIStore, init, useCentralDispatch, useCentralStore, useStoreReady, useStoreReset };
183
197
  export type { Bridge, BridgeWithEvents, BridgeWithHandlers, CentralStore, ExtractSliceState, MergeSlices, PersistOptions, SliceCreator, StoreConfig, StoreDefinition };
package/dist/index.es.js CHANGED
@@ -240,11 +240,15 @@ class BridgeStore {
240
240
  }
241
241
  setupStateSync() {
242
242
  if (this.bridge.on) {
243
- this.bridge.on(`store:${this.storeName}:stateChanged`, (newState) => {
244
- this.previousState = this.currentState;
245
- this.currentState = newState;
246
- this.notifyListeners();
243
+ this.bridge.on(`store:${this.storeName}:stateChanged`, () => {
244
+ this.bridge.send(`store:${this.storeName}:getState`).then((newState) => {
245
+ this.previousState = this.currentState;
246
+ this.currentState = newState;
247
+ this.notifyListeners();
248
+ });
247
249
  });
250
+ } else {
251
+ console.warn(`BridgeStore[${this.storeName}]: Bridge does not support event listening`);
248
252
  }
249
253
  }
250
254
  setState(partial, replace) {
@@ -290,7 +294,7 @@ function useStoreActions(store) {
290
294
  store.setState((state) => ({ ...state, ...partial }));
291
295
  },
292
296
  updateWith: (updater) => {
293
- store.setState((state) => ({ ...state, ...updater(state) }));
297
+ store.setState((state) => updater(state));
294
298
  },
295
299
  replace: (newState) => {
296
300
  store.setState(newState, true);
@@ -377,6 +381,13 @@ class StoreBuilder {
377
381
  this.config.bridge = bridge;
378
382
  return this;
379
383
  }
384
+ /**
385
+ * Enable persistence with Chrome storage
386
+ */
387
+ withPersistence(options) {
388
+ this.config.persistence = options;
389
+ return this;
390
+ }
380
391
  /**
381
392
  * Create the store
382
393
  */
@@ -396,10 +407,13 @@ class StoreBuilder {
396
407
  createServiceWorkerStore() {
397
408
  let isReady = false;
398
409
  let initialState = null;
410
+ let runtimeBridge;
399
411
  const notifyReady = () => {
400
412
  isReady = true;
401
413
  readyCallbacks.forEach((callback) => callback());
414
+ this.onReadyCallbacks.forEach((callback) => callback());
402
415
  readyCallbacks.clear();
416
+ this.onReadyCallbacks.clear();
403
417
  };
404
418
  const creator = (set, get, store2) => {
405
419
  let state = {};
@@ -418,6 +432,11 @@ class StoreBuilder {
418
432
  };
419
433
  const persistedCreator = chromeStoragePersist(persistOptions)(creator);
420
434
  const store = createStore$1(persistedCreator);
435
+ store.subscribe(() => {
436
+ if (runtimeBridge) {
437
+ runtimeBridge.broadcast(`store:${this.config.name}:stateChanged`, store.getState());
438
+ }
439
+ });
421
440
  const centralStore = Object.assign(store, {
422
441
  isReady: () => isReady,
423
442
  reset: () => {
@@ -427,6 +446,9 @@ class StoreBuilder {
427
446
  console.warn("ServiceWorkerStore: Cannot reset, initial state not available");
428
447
  }
429
448
  },
449
+ setBridge: (bridge) => {
450
+ runtimeBridge = bridge;
451
+ },
430
452
  onReady: (callback) => {
431
453
  if (isReady) {
432
454
  callback();
@@ -444,8 +466,19 @@ class StoreBuilder {
444
466
  function createStore(name) {
445
467
  return new StoreBuilder(name);
446
468
  }
469
+ function createServiceWorkerStore(slices, name = "default", persistOptions) {
470
+ const sliceArray = Array.isArray(slices) ? slices : [slices];
471
+ let builder = createStore(name).withSlices(...sliceArray);
472
+ if (persistOptions) {
473
+ builder = builder.withPersistence(persistOptions);
474
+ }
475
+ return builder.create();
476
+ }
477
+ function createUIStore(bridge, initialState, name = "default") {
478
+ return createBridgeStore(bridge, initialState, name);
479
+ }
447
480
 
448
- function autoRegisterStoreHandlers(store) {
481
+ function autoRegisterStoreHandlers(store, storeName = "default") {
449
482
  if (!store) {
450
483
  throw new Error("autoRegisterStoreHandlers: store parameter is required");
451
484
  }
@@ -466,8 +499,8 @@ function autoRegisterStoreHandlers(store) {
466
499
  let replace = false;
467
500
  if (args.length === 1 && args[0] && typeof args[0] === "object") {
468
501
  const payload = args[0];
469
- if ("partial" in payload && "replace" in payload) {
470
- ({ partial, replace } = payload);
502
+ if ("partial" in payload) {
503
+ ({ partial, replace = false } = payload);
471
504
  } else {
472
505
  partial = payload;
473
506
  replace = false;
@@ -489,22 +522,13 @@ function autoRegisterStoreHandlers(store) {
489
522
  } else {
490
523
  store.setState(partial);
491
524
  }
492
- return store.getState();
493
- }
494
- }
495
- class AutoSubscribeToStoreMessage {
496
- handle() {
497
- if (!store) {
498
- throw new Error("Store instance not available");
499
- }
500
- store.subscribe((state, prevState) => {
501
- });
525
+ const updatedState = store.getState();
526
+ return updatedState;
502
527
  }
503
528
  }
504
529
  return {
505
530
  GetStoreStateMessage: AutoGetStoreStateMessage,
506
- SetStoreStateMessage: AutoSetStoreStateMessage,
507
- SubscribeToStoreMessage: AutoSubscribeToStoreMessage
531
+ SetStoreStateMessage: AutoSetStoreStateMessage
508
532
  };
509
533
  }
510
534
 
@@ -518,7 +542,7 @@ async function init(storeDefinition) {
518
542
  return {
519
543
  def: storeDefinition,
520
544
  store,
521
- classes: autoRegisterStoreHandlers(store)
545
+ classes: autoRegisterStoreHandlers(store, storeDefinition.name)
522
546
  };
523
547
  } catch (error) {
524
548
  console.error(`Failed to initialize store "${storeDefinition.name}":`, error);
@@ -526,4 +550,4 @@ async function init(storeDefinition) {
526
550
  }
527
551
  }
528
552
 
529
- export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, init, useCentralDispatch, useCentralStore, useStoreReady, useStoreReset };
553
+ export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createServiceWorkerStore, createStore, createStoreHooks, createUIStore, init, useCentralDispatch, useCentralStore, useStoreReady, useStoreReset };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromahq/store",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
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",
@@ -50,10 +50,13 @@
50
50
  "devDependencies": {
51
51
  "@types/chrome": "^0.0.326",
52
52
  "@types/react": "^18.2.7",
53
- "typescript": "^5.8.3"
53
+ "typescript": "^5.8.3",
54
+ "vitest": "^3.2.4"
54
55
  },
55
56
  "scripts": {
56
57
  "build": "rollup -c rollup.config.mjs",
57
- "dev": "rollup -c rollup.config.mjs --watch"
58
+ "dev": "rollup -c rollup.config.mjs --watch",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest"
58
61
  }
59
62
  }