wxt-zustand
Version:
High-performance Zustand state management for WXT web extensions with seamless cross-tab synchronization and sub-10ms React re-renders
100 lines • 3.92 kB
JavaScript
import { mergeStatePreservingFunctions } from '../utils/stateTransforms';
import { connectAndFetchInitialState as _connectAndFetchInitialState } from './connect';
import { setupBidirectionalSync as _setupBidirectionalSync } from './sync';
/**
* WeakMap registry to track per-store readiness promises.
* Uses WXT-optimized approach for extension context management.
* Map key: Zustand StoreApi instance (WeakMap avoids memory leaks)
* Map value: Record of storeName -> readiness Promise<void>
*/
const readinessRegistry = new WeakMap();
function getRecord(store) {
const existing = readinessRegistry.get(store);
if (existing)
return existing;
const created = {};
readinessRegistry.set(store, created);
return created;
}
/**
* Returns the cached readiness promise for a given store and name, if any.
*/
export function getStoreReadiness(storeName, store) {
const record = readinessRegistry.get(store);
return record?.[storeName];
}
/**
* Caches a readiness promise for a given store and name.
*/
export function setStoreReadiness(storeName, store, readiness) {
const record = getRecord(store);
record[storeName] = readiness;
}
/**
* Cleanup cached readiness data.
* - When storeName is provided, remove only that entry.
* - Otherwise, remove the entire record for the StoreApi.
*/
export function cleanupStoreReadiness(store, storeName) {
if (storeName) {
const record = readinessRegistry.get(store);
if (!record)
return;
delete record[storeName];
// If record becomes empty, drop the WeakMap entry
if (Object.keys(record).length === 0) {
readinessRegistry.delete(store);
}
}
else {
readinessRegistry.delete(store);
}
}
/**
* For diagnostics/tests only: expose internal state length.
*/
export function __readinessSizeFor(store) {
const record = readinessRegistry.get(store);
return record ? Object.keys(record).length : 0;
}
// Internal indirection for testability (avoid global mock.module collisions)
let connectAndFetchInitialState = _connectAndFetchInitialState;
let setupBidirectionalSync = _setupBidirectionalSync;
export function __setReadyImplementations(impl) {
if (impl.connectAndFetchInitialState)
connectAndFetchInitialState = impl.connectAndFetchInitialState;
if (impl.setupBidirectionalSync)
setupBidirectionalSync = impl.setupBidirectionalSync;
}
export function __resetReadyImplementations() {
connectAndFetchInitialState = _connectAndFetchInitialState;
setupBidirectionalSync = _setupBidirectionalSync;
}
/**
* Orchestrate frontend readiness for a WXT Zustand store.
* - Uses WXT-native primitives for optimal performance and compatibility.
* - Ensures single initialization per (store instance + name) via readiness cache.
* - Applies initial state, then sets up bidirectional sync.
*/
export async function wxtZustandStoreReady(storeName, store, config = {}) {
// If we already kicked off readiness for this store+name, just await it.
const existing = getStoreReadiness(storeName, store);
if (existing) {
await existing;
return store;
}
// Create a single readiness promise that both fetches initial state and
// attaches sync. Cache it immediately to prevent duplicate work.
const readiness = (async () => {
const { initialState } = await connectAndFetchInitialState(storeName);
// Replace entire state but preserve any function props (e.g., actions)
const merged = mergeStatePreservingFunctions(store.getState(), initialState);
store.setState(merged, true);
// After initial state is in place, wire up bidirectional sync.
setupBidirectionalSync(storeName, store, config);
})();
setStoreReadiness(storeName, store, readiness);
await readiness;
return store;
}
//# sourceMappingURL=ready.js.map