@chromahq/store 1.0.2 → 1.0.4

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
@@ -109,15 +109,31 @@ function useStoreReset(store) {
109
109
  }
110
110
 
111
111
  class BridgeStore {
112
- constructor(bridge, initialState, storeName = "default") {
112
+ constructor(bridge, initialState, storeName = "default", readyCallbacks = /* @__PURE__ */ new Set()) {
113
113
  this.listeners = /* @__PURE__ */ new Set();
114
114
  this.currentState = null;
115
115
  this.previousState = null;
116
116
  this.initialState = null;
117
117
  this.ready = false;
118
118
  this.readyCallbacks = /* @__PURE__ */ new Set();
119
+ this.initializationAttempts = 0;
120
+ this.maxInitializationAttempts = 10;
119
121
  this.initialize = async () => {
122
+ this.initializationAttempts++;
120
123
  try {
124
+ if (this.initializationAttempts > this.maxInitializationAttempts) {
125
+ console.error(
126
+ `BridgeStore[${this.storeName}]: Max initialization attempts (${this.maxInitializationAttempts}) reached, giving up`
127
+ );
128
+ return;
129
+ }
130
+ if (!this.bridge.isConnected) {
131
+ console.warn(
132
+ `BridgeStore[${this.storeName}]: Bridge not connected (attempt ${this.initializationAttempts}), retrying in 1s...`
133
+ );
134
+ setTimeout(() => this.initialize(), 500);
135
+ return;
136
+ }
121
137
  const state = await this.bridge.send(`store:${this.storeName}:getState`);
122
138
  this.previousState = this.currentState;
123
139
  this.currentState = state;
@@ -128,7 +144,19 @@ class BridgeStore {
128
144
  this.ready = true;
129
145
  this.notifyReady();
130
146
  } catch (error) {
131
- console.warn("Failed to initialize bridge store:", error);
147
+ console.error(
148
+ `BridgeStore[${this.storeName}]: Failed to initialize (attempt ${this.initializationAttempts}):`,
149
+ error
150
+ );
151
+ if (this.bridge.isConnected && this.initializationAttempts < this.maxInitializationAttempts) {
152
+ const delay = Math.min(2e3 * this.initializationAttempts, 1e4);
153
+ console.warn(`BridgeStore[${this.storeName}]: Retrying initialization in ${delay}ms...`);
154
+ setTimeout(() => this.initialize(), delay);
155
+ } else {
156
+ console.error(
157
+ `BridgeStore[${this.storeName}]: Bridge disconnected or max attempts reached, cannot retry`
158
+ );
159
+ }
132
160
  }
133
161
  };
134
162
  this.notifyListeners = () => {
@@ -197,11 +225,36 @@ class BridgeStore {
197
225
  this.readyCallbacks.forEach((callback) => callback());
198
226
  this.readyCallbacks.clear();
199
227
  };
228
+ /**
229
+ * Force re-initialization of the store (useful for debugging)
230
+ */
231
+ this.forceInitialize = async () => {
232
+ console.debug(`BridgeStore[${this.storeName}]: Force re-initialization requested`);
233
+ this.ready = false;
234
+ this.initializationAttempts = 0;
235
+ await this.initialize();
236
+ };
237
+ /**
238
+ * Get debug information about the store state
239
+ */
240
+ this.getDebugInfo = () => {
241
+ return {
242
+ storeName: this.storeName,
243
+ ready: this.ready,
244
+ bridgeConnected: this.bridge.isConnected,
245
+ hasCurrentState: this.currentState !== null,
246
+ hasInitialState: this.initialState !== null,
247
+ readyCallbacksCount: this.readyCallbacks.size,
248
+ initializationAttempts: this.initializationAttempts,
249
+ maxInitializationAttempts: this.maxInitializationAttempts
250
+ };
251
+ };
200
252
  this.bridge = bridge;
201
253
  this.currentState = initialState || null;
202
254
  this.previousState = initialState || null;
203
255
  this.initialState = initialState || null;
204
256
  this.storeName = storeName;
257
+ this.readyCallbacks = readyCallbacks;
205
258
  this.setupStateSync();
206
259
  this.initialize();
207
260
  }
@@ -240,8 +293,8 @@ class BridgeStore {
240
293
  }
241
294
  }
242
295
  }
243
- function createBridgeStore(bridge, initialState, storeName = "default") {
244
- return new BridgeStore(bridge, initialState, storeName);
296
+ function createBridgeStore(bridge, initialState, storeName = "default", readyCallbacks = /* @__PURE__ */ new Set()) {
297
+ return new BridgeStore(bridge, initialState, storeName, readyCallbacks);
245
298
  }
246
299
 
247
300
  function createActionHookForStore(store, actionsFactory) {
@@ -317,8 +370,10 @@ function createStoreHooks() {
317
370
  };
318
371
  }
319
372
 
373
+ const readyCallbacks = /* @__PURE__ */ new Set();
320
374
  class StoreBuilder {
321
375
  constructor(name = "default") {
376
+ this.onReadyCallbacks = /* @__PURE__ */ new Set();
322
377
  this.config = {
323
378
  name,
324
379
  slices: []
@@ -331,6 +386,10 @@ class StoreBuilder {
331
386
  this.config.slices = [...this.config.slices, ...slices];
332
387
  return this;
333
388
  }
389
+ onReady(callback) {
390
+ this.onReadyCallbacks.add(callback);
391
+ return this;
392
+ }
334
393
  /**
335
394
  * Attach a bridge for cross-context communication
336
395
  */
@@ -350,13 +409,12 @@ class StoreBuilder {
350
409
  async createBaseStore() {
351
410
  const bridge = this.config.bridge;
352
411
  if (bridge) {
353
- return createBridgeStore(bridge, void 0, this.config.name);
412
+ return createBridgeStore(bridge, void 0, this.config.name, this.onReadyCallbacks);
354
413
  }
355
414
  return this.createServiceWorkerStore();
356
415
  }
357
416
  createServiceWorkerStore() {
358
417
  let isReady = false;
359
- const readyCallbacks = /* @__PURE__ */ new Set();
360
418
  let initialState = null;
361
419
  const notifyReady = () => {
362
420
  isReady = true;
@@ -487,11 +545,6 @@ async function init(storeDefinition) {
487
545
  throw error;
488
546
  }
489
547
  }
490
- if (typeof globalThis !== "undefined") {
491
- globalThis.__CHROMA__ = globalThis.__CHROMA__ || {};
492
- globalThis.__CHROMA__.initStores = init;
493
- globalThis.initStores = init;
494
- }
495
548
 
496
549
  exports.BridgeStore = BridgeStore;
497
550
  exports.StoreBuilder = StoreBuilder;
package/dist/index.d.ts CHANGED
@@ -66,7 +66,9 @@ declare class BridgeStore<T> implements CentralStore<T> {
66
66
  private storeName;
67
67
  private ready;
68
68
  private readyCallbacks;
69
- constructor(bridge: BridgeWithEvents, initialState?: T, storeName?: string);
69
+ private initializationAttempts;
70
+ private readonly maxInitializationAttempts;
71
+ constructor(bridge: BridgeWithEvents, initialState?: T, storeName?: string, readyCallbacks?: Set<() => void>);
70
72
  initialize: () => Promise<void>;
71
73
  private setupStateSync;
72
74
  private notifyListeners;
@@ -80,8 +82,25 @@ declare class BridgeStore<T> implements CentralStore<T> {
80
82
  onReady: (callback: () => void) => (() => void);
81
83
  reset: () => void;
82
84
  private notifyReady;
85
+ /**
86
+ * Force re-initialization of the store (useful for debugging)
87
+ */
88
+ forceInitialize: () => Promise<void>;
89
+ /**
90
+ * Get debug information about the store state
91
+ */
92
+ getDebugInfo: () => {
93
+ storeName: string;
94
+ ready: boolean;
95
+ bridgeConnected: boolean;
96
+ hasCurrentState: boolean;
97
+ hasInitialState: boolean;
98
+ readyCallbacksCount: number;
99
+ initializationAttempts: number;
100
+ maxInitializationAttempts: number;
101
+ };
83
102
  }
84
- declare function createBridgeStore<T>(bridge: BridgeWithEvents, initialState?: T, storeName?: string): CentralStore<T>;
103
+ declare function createBridgeStore<T>(bridge: BridgeWithEvents, initialState?: T, storeName?: string, readyCallbacks?: Set<() => void>): CentralStore<T>;
85
104
 
86
105
  /**
87
106
  * Generic action hook factory for any store instance.
@@ -132,11 +151,13 @@ declare function createStoreHooks<T extends Record<string, any>>(): {
132
151
  */
133
152
  declare class StoreBuilder<T = any> {
134
153
  private config;
154
+ private onReadyCallbacks;
135
155
  constructor(name?: string);
136
156
  /**
137
157
  * Add state slices to the store
138
158
  */
139
159
  withSlices(...slices: StateCreator$1<any, [], [], any>[]): this;
160
+ onReady(callback: () => void): this;
140
161
  /**
141
162
  * Attach a bridge for cross-context communication
142
163
  */
package/dist/index.es.js CHANGED
@@ -89,15 +89,31 @@ function useStoreReset(store) {
89
89
  }
90
90
 
91
91
  class BridgeStore {
92
- constructor(bridge, initialState, storeName = "default") {
92
+ constructor(bridge, initialState, storeName = "default", readyCallbacks = /* @__PURE__ */ new Set()) {
93
93
  this.listeners = /* @__PURE__ */ new Set();
94
94
  this.currentState = null;
95
95
  this.previousState = null;
96
96
  this.initialState = null;
97
97
  this.ready = false;
98
98
  this.readyCallbacks = /* @__PURE__ */ new Set();
99
+ this.initializationAttempts = 0;
100
+ this.maxInitializationAttempts = 10;
99
101
  this.initialize = async () => {
102
+ this.initializationAttempts++;
100
103
  try {
104
+ if (this.initializationAttempts > this.maxInitializationAttempts) {
105
+ console.error(
106
+ `BridgeStore[${this.storeName}]: Max initialization attempts (${this.maxInitializationAttempts}) reached, giving up`
107
+ );
108
+ return;
109
+ }
110
+ if (!this.bridge.isConnected) {
111
+ console.warn(
112
+ `BridgeStore[${this.storeName}]: Bridge not connected (attempt ${this.initializationAttempts}), retrying in 1s...`
113
+ );
114
+ setTimeout(() => this.initialize(), 500);
115
+ return;
116
+ }
101
117
  const state = await this.bridge.send(`store:${this.storeName}:getState`);
102
118
  this.previousState = this.currentState;
103
119
  this.currentState = state;
@@ -108,7 +124,19 @@ class BridgeStore {
108
124
  this.ready = true;
109
125
  this.notifyReady();
110
126
  } catch (error) {
111
- console.warn("Failed to initialize bridge store:", error);
127
+ console.error(
128
+ `BridgeStore[${this.storeName}]: Failed to initialize (attempt ${this.initializationAttempts}):`,
129
+ error
130
+ );
131
+ if (this.bridge.isConnected && this.initializationAttempts < this.maxInitializationAttempts) {
132
+ const delay = Math.min(2e3 * this.initializationAttempts, 1e4);
133
+ console.warn(`BridgeStore[${this.storeName}]: Retrying initialization in ${delay}ms...`);
134
+ setTimeout(() => this.initialize(), delay);
135
+ } else {
136
+ console.error(
137
+ `BridgeStore[${this.storeName}]: Bridge disconnected or max attempts reached, cannot retry`
138
+ );
139
+ }
112
140
  }
113
141
  };
114
142
  this.notifyListeners = () => {
@@ -177,11 +205,36 @@ class BridgeStore {
177
205
  this.readyCallbacks.forEach((callback) => callback());
178
206
  this.readyCallbacks.clear();
179
207
  };
208
+ /**
209
+ * Force re-initialization of the store (useful for debugging)
210
+ */
211
+ this.forceInitialize = async () => {
212
+ console.debug(`BridgeStore[${this.storeName}]: Force re-initialization requested`);
213
+ this.ready = false;
214
+ this.initializationAttempts = 0;
215
+ await this.initialize();
216
+ };
217
+ /**
218
+ * Get debug information about the store state
219
+ */
220
+ this.getDebugInfo = () => {
221
+ return {
222
+ storeName: this.storeName,
223
+ ready: this.ready,
224
+ bridgeConnected: this.bridge.isConnected,
225
+ hasCurrentState: this.currentState !== null,
226
+ hasInitialState: this.initialState !== null,
227
+ readyCallbacksCount: this.readyCallbacks.size,
228
+ initializationAttempts: this.initializationAttempts,
229
+ maxInitializationAttempts: this.maxInitializationAttempts
230
+ };
231
+ };
180
232
  this.bridge = bridge;
181
233
  this.currentState = initialState || null;
182
234
  this.previousState = initialState || null;
183
235
  this.initialState = initialState || null;
184
236
  this.storeName = storeName;
237
+ this.readyCallbacks = readyCallbacks;
185
238
  this.setupStateSync();
186
239
  this.initialize();
187
240
  }
@@ -220,8 +273,8 @@ class BridgeStore {
220
273
  }
221
274
  }
222
275
  }
223
- function createBridgeStore(bridge, initialState, storeName = "default") {
224
- return new BridgeStore(bridge, initialState, storeName);
276
+ function createBridgeStore(bridge, initialState, storeName = "default", readyCallbacks = /* @__PURE__ */ new Set()) {
277
+ return new BridgeStore(bridge, initialState, storeName, readyCallbacks);
225
278
  }
226
279
 
227
280
  function createActionHookForStore(store, actionsFactory) {
@@ -297,8 +350,10 @@ function createStoreHooks() {
297
350
  };
298
351
  }
299
352
 
353
+ const readyCallbacks = /* @__PURE__ */ new Set();
300
354
  class StoreBuilder {
301
355
  constructor(name = "default") {
356
+ this.onReadyCallbacks = /* @__PURE__ */ new Set();
302
357
  this.config = {
303
358
  name,
304
359
  slices: []
@@ -311,6 +366,10 @@ class StoreBuilder {
311
366
  this.config.slices = [...this.config.slices, ...slices];
312
367
  return this;
313
368
  }
369
+ onReady(callback) {
370
+ this.onReadyCallbacks.add(callback);
371
+ return this;
372
+ }
314
373
  /**
315
374
  * Attach a bridge for cross-context communication
316
375
  */
@@ -330,13 +389,12 @@ class StoreBuilder {
330
389
  async createBaseStore() {
331
390
  const bridge = this.config.bridge;
332
391
  if (bridge) {
333
- return createBridgeStore(bridge, void 0, this.config.name);
392
+ return createBridgeStore(bridge, void 0, this.config.name, this.onReadyCallbacks);
334
393
  }
335
394
  return this.createServiceWorkerStore();
336
395
  }
337
396
  createServiceWorkerStore() {
338
397
  let isReady = false;
339
- const readyCallbacks = /* @__PURE__ */ new Set();
340
398
  let initialState = null;
341
399
  const notifyReady = () => {
342
400
  isReady = true;
@@ -467,10 +525,5 @@ async function init(storeDefinition) {
467
525
  throw error;
468
526
  }
469
527
  }
470
- if (typeof globalThis !== "undefined") {
471
- globalThis.__CHROMA__ = globalThis.__CHROMA__ || {};
472
- globalThis.__CHROMA__.initStores = init;
473
- globalThis.initStores = init;
474
- }
475
528
 
476
529
  export { BridgeStore, StoreBuilder, chromeStoragePersist, createActionHookForStore, createBridgeStore, createStore, createStoreHooks, init, useCentralDispatch, useCentralStore, useStoreReady, useStoreReset };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromahq/store",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
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",