@storesjs/stores 0.8.7 → 0.9.0

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.
@@ -1,4 +1,4 @@
1
- type UnknownFunction = (...args: unknown[]) => unknown;
1
+ import { UnknownFunction } from '../types/functions';
2
2
  /**
3
3
  * Metadata for a field's last write.
4
4
  */
@@ -9,147 +9,86 @@ export type SyncStateKey<T extends Record<string, unknown>> = Extract<{
9
9
  export type SyncValues<T extends Record<string, unknown>> = Partial<T> & {
10
10
  [K in SyncStateKey<T>]?: T[K];
11
11
  };
12
- export type RecordDeltaPayload<TValue = unknown> = {
13
- readonly clear?: true;
14
- readonly del?: readonly string[];
15
- readonly set?: Record<string, TValue>;
16
- readonly patch?: Record<string, RecordDeltaPayload>;
17
- };
18
- export type SyncDeltaPayload<TValue = unknown> = {
19
- readonly kind: 'record';
20
- } & RecordDeltaPayload<TValue>;
21
- export type SyncDeltaDescriptor = {
22
- /**
23
- * Minimum fraction of the full payload the delta must save (0–1).
24
- */
25
- readonly minSavingsRatio?: number;
26
- /**
27
- * Minimum number of bytes the delta must save compared to sending the full payload.
28
- */
29
- readonly minSavingsBytes?: number;
30
- };
31
- /**
32
- * Per-field delta configuration. Use `true` to enable with defaults, or provide thresholds.
33
- */
34
- export type SyncDeltaConfig<T extends Record<string, unknown>> = Partial<Record<SyncStateKey<T>, SyncDeltaDescriptor | true>>;
35
- export type SyncDeltaMap<T extends Record<string, unknown>> = Partial<Record<SyncStateKey<T>, SyncDeltaPayload<T[SyncStateKey<T>]>>>;
36
12
  export type SyncUpdate<T extends Record<string, unknown>> = {
37
- deltas?: SyncDeltaMap<T>;
38
13
  replace: boolean;
39
14
  sessionId: string;
40
15
  timestamp: number;
41
16
  values: SyncValues<T>;
42
17
  };
18
+ /**
19
+ * Passed to `SyncEngine.register()` to connect a store to the sync system.
20
+ */
43
21
  export type SyncRegistration<T extends Record<string, unknown>> = {
22
+ /** Callback invoked by the engine to apply incoming remote updates to the store. */
44
23
  apply: (update: SyncUpdate<T>) => void;
24
+ /** The state keys to sync. Non-function properties only. */
45
25
  fields: ReadonlyArray<SyncStateKey<T>>;
26
+ /** Returns the store's current state. Used by engines that need to read state (e.g., for diffing). */
46
27
  getState: () => T;
28
+ /** Unique identifier for this store. Must match across clients to sync the same data. */
47
29
  key: string;
48
- delta?: SyncDeltaConfig<T>;
49
30
  };
31
+ /**
32
+ * Returned by `SyncEngine.register()`. Controls the lifecycle of a synced store.
33
+ */
50
34
  export interface SyncHandle<T extends Record<string, unknown>> {
35
+ /**
36
+ * Permanently removes this store from the sync engine. After calling, the handle
37
+ * is invalid and the store will no longer send or receive updates. To temporarily
38
+ * pause sync, use `onFirstSubscribe`/`onLastUnsubscribe` lifecycle hooks instead.
39
+ */
51
40
  destroy: () => void;
41
+ /** Returns `true` once the store has received its initial state from the engine. */
52
42
  hydrated?: () => boolean;
43
+ /**
44
+ * Called when the store's subscriber count goes from 0 to 1. The registration
45
+ * remains active. Use for lazy resource acquisition (e.g., opening a WebSocket).
46
+ */
47
+ onFirstSubscribe?: () => void;
48
+ /** Registers a one-time callback to run when hydration completes. */
53
49
  onHydrated?: (callback: () => void) => void;
50
+ /**
51
+ * Called when the store's subscriber count drops to 0. The registration remains
52
+ * active and `onFirstSubscribe` will fire again on the next subscription.
53
+ * Use for resource cleanup (e.g., closing idle connections).
54
+ */
55
+ onLastUnsubscribe?: () => void;
56
+ /**
57
+ * Broadcasts a state update to other clients. Set to `null` for engines where
58
+ * publishing is implicit (e.g., `chrome.storage` where the write itself triggers sync).
59
+ */
54
60
  publish: ((update: SyncUpdate<T>) => void) | null;
55
61
  }
62
+ /**
63
+ * Interface for multi-client state synchronization. Stores register to send and receive updates.
64
+ */
56
65
  export interface SyncEngine {
57
- register<T extends Record<string, unknown>>(registration: SyncRegistration<T>): SyncHandle<T>;
58
- registerPresence?<Presence>(registration: SyncPresenceRegistration<Presence>): SyncPresenceChannel<Presence> | null;
59
66
  /**
60
- * When true, injects sync metadata (`{ origin, timestamp, fields }`) into the persisted
61
- * storage payload. Only takes effect when used with a persisted store.
62
- *
63
- * Useful for sync engines that use storage events as their transport (e.g., `chrome.storage`).
67
+ * When `true`, embeds sync metadata (`{ origin, timestamp, fields }`) into persisted
68
+ * storage values. Required for engines that use storage writes as their transport.
69
+ * Only effective when the store is also persisted.
64
70
  * @default false
65
71
  */
66
72
  readonly injectStorageMetadata?: boolean;
73
+ /** Registers a store for synchronization. Returns a handle to control the sync lifecycle. */
74
+ register: {
75
+ <T extends Record<string, unknown>>(registration: SyncRegistration<T>): SyncHandle<T>;
76
+ (registration: SyncRegistration<Record<string, unknown>>): SyncHandle<Record<string, unknown>>;
77
+ };
78
+ /** Unique identifier for this client session. Used for conflict resolution and filtering self-updates. */
67
79
  readonly sessionId: string;
68
80
  }
69
81
  export type SyncMergeFn<T, TState = unknown> = (incoming: T, current: T, currentState: TState, incomingValues: Partial<TState>) => T;
70
- export type SyncPresenceJoinHandler<Presence> = (userId: string, data: Presence) => void;
71
- export type SyncPresenceUpdateHandler<Presence> = (userId: string, data: Presence) => void;
72
- export type SyncPresenceLeaveHandler = (userId: string) => void;
73
- export type PresencePruneStrategy = 'updates' | 'activity';
74
- type PresenceActivityField<Presence> = Presence extends Record<string, unknown> ? Extract<keyof Presence, string> : string;
75
- export type SyncPresenceHeartbeatConfig<Presence> = {
76
- /** Interval in milliseconds between heartbeat broadcasts */
77
- interval: number;
78
- /** Reuse the last presence payload for each heartbeat (default). */
79
- behavior?: 'reuse' | undefined;
80
- } | {
81
- /** Interval in milliseconds between heartbeat broadcasts */
82
- interval: number;
83
- /** Clone the payload and refresh an activity field on every heartbeat. */
84
- behavior: 'refresh-activity';
85
- /**
86
- * Field from the presence payload to refresh. Defaults to the prune strategy's activity field or `timestamp`.
87
- */
88
- activityField?: PresenceActivityField<Presence>;
89
- } | {
90
- /** Interval in milliseconds between heartbeat broadcasts */
91
- interval: number;
92
- /** Derive a custom payload for each heartbeat. */
93
- behavior: 'transform';
94
- /**
95
- * Transform invoked before each heartbeat. Return a payload to broadcast, or void to reuse the current data.
96
- */
97
- onHeartbeat: (currentData: Presence) => Presence | void;
98
- };
99
- export type SyncPresenceRegistration<Presence> = {
100
- key: string;
101
- /**
102
- * Optional heartbeat configuration. When enabled, presence data is re-broadcast at the
103
- * specified interval. Use `'reuse'` (default) to emit the last payload unchanged, `'refresh-activity'`
104
- * to automatically update a timestamp-like field on object payloads, or `'transform'` to derive a custom payload.
105
- */
106
- heartbeat?: SyncPresenceHeartbeatConfig<Presence>;
107
- /**
108
- * Optional stale presence pruning. When enabled, remote presence entries that
109
- * haven't been updated within the specified threshold are automatically removed.
110
- */
111
- pruneStale?: {
112
- /**
113
- * Determines how staleness is evaluated.
114
- * - `updates` (default) considers the time since the last presence message arrived.
115
- * - `activity` considers a timestamp field within the presence payload (defaults to `timestamp`).
116
- */
117
- basedOn?: PresencePruneStrategy;
118
- /**
119
- * Field from the presence payload to inspect when `basedOn` is set to `activity`.
120
- * Defaults to `timestamp`.
121
- */
122
- activityField?: PresenceActivityField<Presence>;
123
- /** Time in milliseconds after which presence is considered stale */
124
- after: number;
125
- /** Optional callback invoked before removing stale presence */
126
- onPrune?: (userId: string, data: Presence) => void;
127
- };
128
- onJoin?: SyncPresenceJoinHandler<Presence>;
129
- onLeave?: SyncPresenceLeaveHandler;
130
- onUpdate?: SyncPresenceUpdateHandler<Presence>;
131
- };
132
- export interface SyncPresenceChannel<Presence> {
133
- join(userId: string, data: Presence): void;
134
- leave(): void;
135
- update(data: Presence): void;
136
- /**
137
- * Destroys the presence channel and cleans up all resources.
138
- * Automatically calls leave() and clears all timers.
139
- * Safe to call multiple times.
140
- */
141
- destroy(): void;
142
- }
143
82
  export type SyncConfig<T extends Record<string, unknown>> = {
144
- engine?: SyncEngine;
145
- fields?: ReadonlyArray<SyncStateKey<T>>;
146
83
  /**
147
- * The delta configuration for the sync engine.
84
+ * The sync engine implementation to use.
148
85
  *
149
- * Only takes effect when used with delta-enabled engines like `NetworkSyncEngine`.
150
- * @default undefined
86
+ * Defaults to cross-tab sync in browser environments. No-op in other environments unless a
87
+ * custom engine is provided.
151
88
  */
152
- delta?: SyncDeltaConfig<T>;
89
+ engine?: SyncEngine;
90
+ /** The state keys to sync. If unspecified, all non-function store properties are synced. */
91
+ fields?: ReadonlyArray<SyncStateKey<T>>;
153
92
  /**
154
93
  * When true, injects sync metadata (`{ origin, timestamp, fields }`) into the persisted
155
94
  * storage payload. Only takes effect when used with a persisted store.
@@ -160,7 +99,9 @@ export type SyncConfig<T extends Record<string, unknown>> = {
160
99
  * @default false
161
100
  */
162
101
  injectStorageMetadata?: boolean;
102
+ /** The key used to identify the store to the sync engine. Required if `storageKey` is absent. */
163
103
  key?: string;
104
+ /** Optional merge function to use for each synced state key. Use with caution. */
164
105
  merge?: {
165
106
  [K in SyncStateKey<T>]?: SyncMergeFn<T[K], T>;
166
107
  };
@@ -171,20 +112,4 @@ export type SyncConfig<T extends Record<string, unknown>> = {
171
112
  export type NormalizedSyncConfig<T extends Record<string, unknown>> = SyncConfig<T> & {
172
113
  key: string;
173
114
  };
174
- export type SyncAuthPhase = 'connect' | 'refresh' | 'challenge';
175
- export type SyncAuthPayload = {
176
- readonly headers?: Record<string, string>;
177
- readonly query?: Record<string, string>;
178
- readonly token?: string;
179
- };
180
- export type SyncAuthFailure = {
181
- readonly code: string;
182
- readonly message?: string;
183
- readonly retryable: boolean;
184
- };
185
- export type SyncAuthenticator = {
186
- readonly getPayload: (phase: SyncAuthPhase) => Promise<SyncAuthPayload | null> | SyncAuthPayload | null;
187
- readonly onFailure?: (failure: SyncAuthFailure) => void;
188
- };
189
- export {};
190
115
  //# sourceMappingURL=types.d.ts.map
@@ -1,7 +1,24 @@
1
- /** Extract the keys of T whose values are functions. */
1
+ /**
2
+ * Relaxes function parameter variance to allow subtype
3
+ * assignment otherwise blocked by strict contravariance.
4
+ */
5
+ export type BivariantMethod<T extends Record<string, UnknownFunction>> = T[keyof T];
6
+ /**
7
+ * Extract the keys of `T` whose values are functions.
8
+ */
2
9
  export type FunctionKeys<T> = {
3
10
  [K in keyof T]-?: T[K] extends UnknownFunction ? K : never;
4
11
  }[keyof T];
5
- export type OmitFunctionKeys<T> = Omit<T, FunctionKeys<T>>;
12
+ /**
13
+ * A record of string keys to unknown functions.
14
+ */
15
+ export type FunctionRecord = Record<string, UnknownFunction>;
16
+ /**
17
+ * Return `T` if it is **not** a function, otherwise `never`.
18
+ */
19
+ export type NonFunction<T> = T extends (...args: infer _) => unknown ? never : T;
20
+ /**
21
+ * Unknown generic function type.
22
+ */
6
23
  export type UnknownFunction = (...args: never[]) => unknown;
7
24
  //# sourceMappingURL=functions.d.ts.map
@@ -1,4 +1,11 @@
1
- import { FunctionKeys, UnknownFunction } from './functions';
2
- export type NoOverlap<State, Bundled extends ObjectMethods> = Extract<keyof Bundled, FunctionKeys<State>> extends never ? Bundled : never;
3
- export type ObjectMethods = Record<string, UnknownFunction>;
1
+ /**
2
+ * Forces TypeScript to expand a type for clearer IDE display.
3
+ */
4
+ export type Prettify<T> = T extends infer U ? {
5
+ [K in keyof U]: U[K];
6
+ } : never;
7
+ /**
8
+ * Enforce no overlapping keys between two objects.
9
+ */
10
+ export type NoOverlap<A, B> = B & Record<Extract<keyof A, keyof B>, never>;
4
11
  //# sourceMappingURL=objects.d.ts.map
package/dist/types.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { Mutate, StateCreator as ZustandStateCreator, StoreApi } from 'zustand';
2
- import { PersistOptions } from 'zustand/middleware';
3
- import { UseBoundStoreWithEqualityFn } from 'zustand/traditional';
4
- import { StorageValue } from './storage/storageTypes';
5
- import { SyncConfig } from './sync/types';
1
+ import type { Mutate, StateCreator as ZustandStateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand';
2
+ import type { PersistOptions } from 'zustand/middleware';
3
+ import type { StorageValue } from './storage/storageTypes';
4
+ import type { SyncConfig } from './sync/types';
6
5
  type SubscribeWithSelector = ['zustand/subscribeWithSelector', never];
6
+ export type StoreMutators = [StoreMutatorIdentifier, unknown][];
7
+ export type StoreMutatorsWithSelector<Mutators extends StoreMutators = StoreMutators> = [SubscribeWithSelector, ...Mutators];
7
8
  type HydrationPromise<PersistReturn> = PersistReturn extends Promise<void> ? {
8
9
  /** Invoke to get a promise that resolves once hydration completes. */
9
10
  hydrationPromise: () => Promise<void>;
@@ -30,13 +31,11 @@ type WithPersist<Store, PersistedState, PersistReturn> = Store extends {
30
31
  } & HydrationPromise<PersistReturn>;
31
32
  } : never;
32
33
  export type StateCreator<S, U = S> = ZustandStateCreator<S, [SubscribeWithSelector], [SubscribeWithSelector], U>;
34
+ export type UseBoundStoreWithEqualityFn<Store extends StoreApi<unknown>, State = InferStoreState<Store>> = UseStoreCallSignatures<State> & Store;
33
35
  export type BaseStore<S, ExtraSubscribeOptions extends boolean = false> = UseBoundStoreWithEqualityFn<Mutate<StoreApi<S>, [SubscribeWithSelector]>> & {
34
36
  subscribe: SubscribeOverloads<S, ExtraSubscribeOptions>;
35
37
  };
36
- export type PersistedStore<S, PersistedState = Partial<S>, PersistReturn = unknown, ExtraSubscribeOptions extends boolean = false> = {
37
- (): S;
38
- <U>(selector: (state: S) => U, equalityFn?: (a: U, b: U) => boolean): U;
39
- } & Omit<BaseStore<S, ExtraSubscribeOptions>, 'setState' | 'persist'> & WithPersist<BaseStore<S, ExtraSubscribeOptions>, PersistedState, PersistReturn>;
38
+ export type PersistedStore<S, PersistedState = Partial<S>, PersistReturn = unknown, ExtraSubscribeOptions extends boolean = false> = UseStoreCallSignatures<S> & Omit<BaseStore<S, ExtraSubscribeOptions>, 'setState' | 'persist'> & WithPersist<BaseStore<S, ExtraSubscribeOptions>, PersistedState, PersistReturn>;
40
39
  export type Store<S, PersistedState extends Partial<S> = never, PersistReturn = unknown, ExtraSubscribeOptions extends boolean = false> = [
41
40
  PersistedState
42
41
  ] extends [never] ? BaseStore<S, ExtraSubscribeOptions> : PersistedStore<S, PersistedState, PersistReturn, ExtraSubscribeOptions>;
@@ -56,24 +55,18 @@ export type InferStoreState<Store extends StoreApi<unknown>> = Store extends {
56
55
  getState: () => infer T;
57
56
  } ? T : never;
58
57
  /**
59
- * Extracts the return type of setState from a store.
60
- * Returns `void` for non-persisted or sync-persisted stores.
61
- * Returns `Promise<void>` for async-persisted stores.
58
+ * Extracts a store's `setState` return type.
59
+ * - `void` for non-persisted or synchronous persisted stores.
60
+ * - `Promise<void>` for async persisted stores.
62
61
  */
63
62
  export type InferSetStateReturn<Store> = Store extends {
64
63
  setState(...args: SetStateArgs<infer S>): infer R;
65
64
  } ? R : void;
66
65
  /**
67
- * Extracts the PersistedState type from a store's persist property.
68
- * Returns `Partial<State>` if the store doesn't have persistence.
66
+ * Extracts a store's `PersistedState` type.
67
+ * Returns `never` if the store doesn't use persistence.
69
68
  */
70
- export type InferPersistedState<Store, State> = Store extends {
71
- persist: {
72
- getOptions: () => infer Options;
73
- };
74
- } ? Options extends {
75
- name?: string;
76
- } ? Partial<State> : Partial<State> : Partial<State>;
69
+ export type InferPersistedState<PersistedStore> = PersistedStore extends Store<infer _, infer PersistedState> ? PersistedState : never;
77
70
  export type SetPartial<S> = Partial<S> | ((state: S) => Partial<S>);
78
71
  export type SetFull<S> = S | ((state: S) => S);
79
72
  export type SetStateReplaceArgs<S, ExtraArgs extends unknown[] = []> = [update: SetFull<S>, replace: true, ...extraArgs: ExtraArgs];
@@ -89,6 +82,12 @@ export type WithAsyncSet<Store extends StoreApi<unknown>, S, PersistedState, Per
89
82
  setState(update: SetPartial<InferStoreState<Store>>, replace?: false): PersistReturn;
90
83
  setState(update: SetFull<InferStoreState<Store>>, replace: true): PersistReturn;
91
84
  };
85
+ /**
86
+ * Minimum store API required for subscription.
87
+ */
88
+ export type SubscribableStore = {
89
+ subscribe(selector: Selector<unknown, unknown>, listener: () => void, options?: SubscribeOptions<unknown>): UnsubscribeFn;
90
+ };
92
91
  export type SubscribeOptions<Selected> = {
93
92
  equalityFn?: EqualityFn<Selected>;
94
93
  fireImmediately?: boolean;
@@ -206,12 +205,12 @@ export interface SyncStorageInterface<SerializedState = unknown> {
206
205
  * Adapter-level deserializer used when a store does not supply its own.
207
206
  * Acts as the default before falling back to the framework implementation.
208
207
  */
209
- readonly deserializer?: <PersistedState>(serializedState: SerializedState) => StorageValue<PersistedState>;
208
+ deserializer?<PersistedState>(serializedState: SerializedState): StorageValue<PersistedState>;
210
209
  /**
211
210
  * Adapter-level serializer used when a store does not supply its own.
212
211
  * Acts as the default before falling back to the framework implementation.
213
212
  */
214
- readonly serializer?: <PersistedState>(storageValue: StorageValue<PersistedState>) => SerializedState;
213
+ serializer?<PersistedState>(storageValue: StorageValue<PersistedState>): SerializedState;
215
214
  clearAll(): void;
216
215
  contains(key: string): boolean;
217
216
  delete(key: string): void;
@@ -229,12 +228,12 @@ export type AsyncStorageInterface<SerializedState = unknown> = {
229
228
  * Adapter-level deserializer used when a store does not supply its own.
230
229
  * Acts as the default before falling back to the framework implementation.
231
230
  */
232
- readonly deserializer?: <PersistedState>(serializedState: SerializedState) => StorageValue<PersistedState>;
231
+ deserializer?<PersistedState>(serializedState: SerializedState): StorageValue<PersistedState>;
233
232
  /**
234
233
  * Adapter-level serializer used when a store does not supply its own.
235
234
  * Acts as the default before falling back to the framework implementation.
236
235
  */
237
- readonly serializer?: <PersistedState>(storageValue: StorageValue<PersistedState>) => SerializedState;
236
+ serializer?<PersistedState>(storageValue: StorageValue<PersistedState>): SerializedState;
238
237
  clearAll(): Promise<void>;
239
238
  contains(key: string): Promise<boolean>;
240
239
  delete(key: string): Promise<void>;
@@ -250,7 +249,7 @@ export type PersistConfig<S, PersistedState = Partial<S>, PersistReturn = void>
250
249
  * A function to convert the serialized value back into the state object.
251
250
  * If not provided, the storage adapter's `deserializer` is used before falling back to the default implementation.
252
251
  */
253
- deserializer?: <SerializedState>(serializedState: SerializedState) => StorageValue<PersistedState>;
252
+ deserializer?: (serializedState: unknown) => StorageValue<PersistedState>;
254
253
  /**
255
254
  * A function to merge persisted state with current state during hydration.
256
255
  * By default, zustand does a shallow merge, but this allows custom logic for deep merging nested objects.
@@ -281,7 +280,7 @@ export type PersistConfig<S, PersistedState = Partial<S>, PersistReturn = void>
281
280
  * A function to serialize the state and version for storage.
282
281
  * If not provided, the storage adapter's `serializer` is used before falling back to the default implementation.
283
282
  */
284
- serializer?: <SerializedState>(storageValue: StorageValue<PersistedState>) => SerializedState;
283
+ serializer?: (storageValue: StorageValue<PersistedState>) => string;
285
284
  /**
286
285
  * Custom storage implementation. If async, `setState` will return a Promise that resolves
287
286
  * when the state is persisted. If sync, `setState` will return void.
@@ -1,7 +1,26 @@
1
1
  /**
2
- * Returns the first argument provided to it.
3
- * @param value - Any value.
4
- * @returns `value`.
2
+ * Returns the argument provided.
5
3
  */
6
- export declare const identity: (value: any) => any;
4
+ export declare function identity<T>(value: T): T;
5
+ export declare function identity<T, _>(value: T): T;
6
+ /**
7
+ * Creates a null-prototype object using the runtime-optimal path:
8
+ * - React Native: direct literal `{ __proto__: null }`
9
+ * - Web/Node: `Object.create` with a shared, frozen null prototype
10
+ */
11
+ export declare function nullObject<T extends Record<string, unknown> | object = Record<string, unknown>>(): T;
12
+ /**
13
+ * Builds null-prototype objects. Provided arguments are
14
+ * shallow-merged into a newly created null-prototype object:
15
+ *
16
+ * ```ts
17
+ * Object.assign(nullObject(), a, b?)
18
+ * ```
19
+ */
20
+ export declare function buildNullObject<A extends Record<string, unknown>>(a: A): A;
21
+ export declare function buildNullObject<A extends object, B>(a: object, b?: object): [undefined] extends B ? A : A & B;
22
+ /**
23
+ * Does nothing.
24
+ */
25
+ export declare function noop(): void;
7
26
  //# sourceMappingURL=core.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { StoreApi } from 'zustand';
2
2
  import { InferStoreState } from '../types';
3
- import { NoOverlap, ObjectMethods } from '../types/objects';
4
- import { FunctionKeys } from '../types/functions';
3
+ import { NoOverlap } from '../types/objects';
4
+ import { FunctionKeys, FunctionRecord } from '../types/functions';
5
5
  export type StoreActions<Store extends StoreApi<unknown>> = Pick<InferStoreState<Store>, FunctionKeys<InferStoreState<Store>>>;
6
6
  /**
7
7
  * Given a store instance, produces a new object containing only its actions.
@@ -21,5 +21,5 @@ export type StoreActions<Store extends StoreApi<unknown>> = Pick<InferStoreState
21
21
  * exampleActions.increment();
22
22
  */
23
23
  export declare function createStoreActions<Store extends StoreApi<unknown>>(store: Store): StoreActions<Store>;
24
- export declare function createStoreActions<Store extends StoreApi<unknown>, Bundled extends ObjectMethods>(store: Store, bundledMethods: NoOverlap<InferStoreState<Store>, Bundled>): StoreActions<Store> & Bundled;
24
+ export declare function createStoreActions<Store extends StoreApi<unknown>, Bundled extends FunctionRecord>(store: Store, bundledMethods: NoOverlap<InferStoreState<Store>, Bundled>): StoreActions<Store> & Bundled;
25
25
  //# sourceMappingURL=createStoreActions.d.ts.map
@@ -1,9 +1,9 @@
1
- import { StorageValue } from '../storage/storageTypes';
1
+ import type { StorageValue } from '../storage/storageTypes';
2
2
  /**
3
3
  * Default partialize function if none is provided. It omits top-level store
4
4
  * methods and keeps all other state.
5
5
  */
6
- export declare function omitStoreMethods<S, PersistedState extends Partial<S>>(state: S): PersistedState;
6
+ export declare function omitStoreMethods<S, PersistedState extends Partial<S> = Partial<S>>(state: S): PersistedState;
7
7
  export declare function defaultSerializeState<PersistedState>(storageValue: StorageValue<PersistedState>, shouldUseReplacer: boolean): string;
8
8
  export declare function defaultDeserializeState<PersistedState>(serializedState: string, shouldUseReviver: boolean): StorageValue<PersistedState>;
9
9
  //# sourceMappingURL=persistUtils.d.ts.map
@@ -53,7 +53,7 @@ export declare function isDerivedStore<T extends BaseStore<unknown> | StoreApi<u
53
53
  /**
54
54
  * Checks if a store is persisted.
55
55
  */
56
- export declare function isPersistedStore<T extends BaseStore<unknown>>(store: T): store is T & {
56
+ export declare function isPersistedStore<T extends BaseStore<unknown> | PersistedStore<unknown>>(store: T): store is T & {
57
57
  persist: PersistedStore<InferStoreState<T>>['persist'];
58
58
  };
59
59
  /**
@@ -38,9 +38,6 @@ export declare const time: TimeUtils;
38
38
  * Uses setTimeout(0) to allow microtasks scheduled via queueMicrotask to execute.
39
39
  *
40
40
  * Useful in tests when waiting for async operations scheduled via microtasks.
41
- *
42
- * @example
43
- * await waitForMicrotask();
44
41
  */
45
42
  export declare function waitForMicrotask(): Promise<void>;
46
43
  export {};
@@ -1 +1 @@
1
- "use strict";var e="stores:";function t(e){if("object"!=typeof e||null===e)return!1;const t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function r(e,t){return t instanceof Map?{__type:"Map",entries:Array.from(t.entries())}:t instanceof Set?{__type:"Set",values:Array.from(t)}:t}function s(e,t){return function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Map"===e.__type}(t)?new Map(t.entries):function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Set"===e.__type}(t)?new Set(t.values):t}var n=class{constructor(t){this.async=!0,this.deserializer=i,this.serializer=o,this.area=t?.area??"local",this.storageKeyPrefix=t?.storageKeyPrefix??e}async clearAll(){const e=this.ensureStorage();if(!e)return;if(!this.storageKeyPrefix)throw new Error("Cannot clear all storage with empty storageKeyPrefix. This would delete all storage entries.");const t=await this.listPrefixedKeys(e,this.storageKeyPrefix);t.length&&await this.execute(e,r=>e.remove(t,r))}async contains(e){const t=this.ensureStorage();if(!t)return!1;const r=this.toStorageKey(e),s=await this.getFromStorage(t,r);return Object.prototype.hasOwnProperty.call(s,r)}async delete(e){const t=this.ensureStorage();if(!t)return;const r=this.toStorageKey(e);await this.execute(t,e=>t.remove(r,e))}async getAllKeys(){const e=this.ensureStorage();if(!e)return[];const t=await this.getFromStorage(e,null),r=this.storageKeyPrefix;return r?Object.keys(t).filter(e=>e.startsWith(r)).map(e=>e.slice(r.length)):Object.keys(t)}async get(e){const t=this.ensureStorage();if(!t)return;const r=this.toStorageKey(e);return a((await this.getFromStorage(t,r))[r])||void 0}async set(e,t){const r=this.ensureStorage();if(!r)return;const s=this.toStorageKey(e);await this.execute(r,e=>r.set({[s]:t},e))}ensureStorage(){return e=this.area,"undefined"!=typeof chrome&&chrome.storage?chrome.storage[e]??null:null;var e}toStorageKey(e){return this.storageKeyPrefix?`${this.storageKeyPrefix}${e}`:e}async listPrefixedKeys(e,t){const r=await this.getFromStorage(e,null);return Object.keys(r).filter(e=>e.startsWith(t))}async getFromStorage(e,t){return this.invokeWithCallbackSupport(r=>e.get(t,r))}async execute(e,t){await this.invokeWithCallbackSupport(t)}async invokeWithCallbackSupport(e){return new Promise((t,r)=>{let s=!1;const n=e=>{if(s)return;s=!0;const n="undefined"!=typeof chrome&&chrome.runtime&&chrome.runtime.lastError?new Error(chrome.runtime.lastError.message):null;n?r(n):t(e)};try{const t=e(n);(o=t)&&"object"==typeof o&&"then"in o&&"function"==typeof o.then&&t.then(n).catch(r)}catch(e){r(e)}var o})}};function o(e){return{state:h(e.state),syncMetadata:e.syncMetadata,version:e.version}}function i(e){const t=a(e);if(!t)throw new Error("[ChromeStorageAdapter] Invalid serialized state format");return{state:u(t.state),syncMetadata:t.syncMetadata,version:t.version}}function a(e){if(c(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);if(c(t))return t}catch{}return null}function c(e){return!(!e||"object"!=typeof e)&&Object.prototype.hasOwnProperty.call(e,"state")}function h(e,s=r){if(e instanceof Map||e instanceof Set)return s.call(void 0,"",e);if(!t(e))return e;const n={};for(const[t,r]of Object.entries(e))n[t]=s.call(e,t,r);return n}function u(e,r=s){const n=r.call(void 0,"",e);if(!t(n))return n;const o={};for(const e of Object.entries(n)){const t=e[0],s=e[1];o[t]=r.call(n,t,s)}return o}var l=class{constructor(t){this.injectStorageMetadata=!0,this.registrations=new Map,this.isListening=!1,this.onStorageChanged=async(e,t)=>{if(t===this.area)for(const t of this.registrations){const r=t[0],s=t[1];if(s.destroyed)continue;const n=e[this.toStorageKey(r)];if(n&&void 0!==n.newValue)try{const e=this.parsePersistValue(n.newValue);if(!e||e.syncMetadata?.origin===this.sessionId)continue;const t=e?.syncMetadata,r=this.extractChangedFields(s,e.state,t,n.oldValue);if(!Object.keys(r).length)continue;s.registration.apply({replace:!1,sessionId:t?.origin??"unknown",timestamp:t?.timestamp??Date.now(),values:r})}catch(e){continue}}},t&&"storage"in t?(this.area=t.storage.area,this.storageKeyPrefix=t.storage.storageKeyPrefix):(this.area=t?.area??"local",this.storageKeyPrefix=t?.storageKeyPrefix??e),this.sessionId=this.generateSessionId(),this.attachListener()}generateSessionId(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Math.random().toString(36).slice(2)}:${Date.now().toString(36)}`}register(e){this.attachListener();const t={destroyed:!1,hydrated:!0,listeners:new Set,registration:e};return this.registrations.set(e.key,t),{destroy:()=>{t.destroyed=!0,t.listeners.clear(),this.registrations.delete(e.key),this.registrations.size||this.detachListener()},publish:null}}attachListener(){"undefined"!=typeof chrome&&chrome.storage&&!this.isListening&&(this.isListening=!0,chrome.storage.onChanged.addListener(this.onStorageChanged))}detachListener(){"undefined"!=typeof chrome&&chrome.storage&&this.isListening&&(chrome.storage.onChanged.removeListener(this.onStorageChanged),this.isListening=!1)}extractChangedFields(e,t,r,s){const n=Object.create(null),o=r?.fields;if(o&&Object.keys(o).length>0){let r=!1;for(const s of e.registration.fields){const e=String(s);Object.prototype.hasOwnProperty.call(o,e)&&(n[s]=t[s],r=!0)}if(r)return n}const i=this.parsePersistValue(s);for(const r of e.registration.fields){const e=t[r],s=i?.state[r];Object.is(e,s)||(n[r]=e)}return n}toStorageKey(e){return this.storageKeyPrefix?`${this.storageKeyPrefix}${e}`:e}parsePersistValue(e){return i(e)}};exports.ChromeExtensionSyncEngine=l,exports.ChromeStorageAdapter=n,exports.createSyncedChromeStorage=function(e){const t=new n(e);return{storage:t,syncEngine:new l({storage:t})}};
1
+ process.env.NODE_ENV,process.env.NODE_ENV;var e=Object.prototype.hasOwnProperty;function t(t,r){return e.call(t,r)}function r(e){if("object"!=typeof e||null===e)return!1;const t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}var s=Object.freeze(Object.create(null)),n="stores:";function o(e,t){return t instanceof Map?{__type:"Map",entries:Array.from(t.entries())}:t instanceof Set?{__type:"Set",values:Array.from(t)}:t}function i(e,t){return function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Map"===e.__type}(t)?new Map(t.entries):function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Set"===e.__type}(t)?new Set(t.values):t}var a=class{constructor(e){this.async=!0,this.deserializer=h,this.serializer=c,this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??n}async clearAll(){const e=this.ensureStorage();if(!e)return;if(!this.storageKeyPrefix)throw new Error("Cannot clear all storage with empty storageKeyPrefix. This would delete all storage entries.");const t=await this.listPrefixedKeys(e,this.storageKeyPrefix);t.length&&await this.execute(e,r=>e.remove(t,r))}async contains(e){const t=this.ensureStorage();if(!t)return!1;const r=this.toStorageKey(e),s=await this.getFromStorage(t,r);return Object.prototype.hasOwnProperty.call(s,r)}async delete(e){const t=this.ensureStorage();if(!t)return;const r=this.toStorageKey(e);await this.execute(t,e=>t.remove(r,e))}async getAllKeys(){const e=this.ensureStorage();if(!e)return[];const t=await this.getFromStorage(e,null),r=this.storageKeyPrefix;return r?Object.keys(t).filter(e=>e.startsWith(r)).map(e=>e.slice(r.length)):Object.keys(t)}async get(e){const t=this.ensureStorage();if(!t)return;const r=this.toStorageKey(e);return u((await this.getFromStorage(t,r))[r])||void 0}async set(e,t){const r=this.ensureStorage();if(!r)return;const s=this.toStorageKey(e);await this.execute(r,e=>r.set({[s]:t},e))}ensureStorage(){return e=this.area,"undefined"!=typeof chrome&&chrome.storage?chrome.storage[e]??null:null;var e}toStorageKey(e){return this.storageKeyPrefix?`${this.storageKeyPrefix}${e}`:e}async listPrefixedKeys(e,t){const r=await this.getFromStorage(e,null);return Object.keys(r).filter(e=>e.startsWith(t))}async getFromStorage(e,t){return this.invokeWithCallbackSupport(r=>e.get(t,r))}async execute(e,t){await this.invokeWithCallbackSupport(t)}async invokeWithCallbackSupport(e){return new Promise((t,r)=>{let s=!1;function n(e){if(s)return;s=!0;const n="undefined"!=typeof chrome&&chrome.runtime&&chrome.runtime.lastError?new Error(chrome.runtime.lastError.message):null;n?r(n):t(e)}try{const t=e(n);(o=t)&&"object"==typeof o&&"then"in o&&"function"==typeof o.then&&t.then(n).catch(r)}catch(e){r(e)}var o})}};function c(e){return{state:g(e.state),syncMetadata:e.syncMetadata,version:e.version}}function h(e){const t=u(e);if(!t)throw new Error("[ChromeStorageAdapter] Invalid serialized state format");return{state:f(t.state),syncMetadata:t.syncMetadata,version:t.version}}function u(e){if(l(e))return e;if("string"==typeof e)try{const t=JSON.parse(e);if(l(t))return t}catch{}return null}function l(e){return!(!e||"object"!=typeof e)&&Object.prototype.hasOwnProperty.call(e,"state")}function g(e,t=o){if(e instanceof Map||e instanceof Set)return t.call(void 0,"",e);if(!r(e))return e;const s={};for(const[r,n]of Object.entries(e))s[r]=t.call(e,r,n);return s}function f(e,t=i){const s=t.call(void 0,"",e);if(!r(s))return s;const n={};for(const e of Object.entries(s)){const r=e[0],o=e[1];n[r]=t.call(s,r,o)}return n}var y=class{constructor(e){this.injectStorageMetadata=!0,this.registrations=new Map,this.isListening=!1,this.onStorageChanged=async(e,t)=>{if(t===this.area)for(const t of this.registrations){const r=t[0],s=t[1];if(s.destroyed)continue;const n=e[this.toStorageKey(r)];if(n&&void 0!==n.newValue)try{const e=this.parsePersistValue(n.newValue);if(!e||e.syncMetadata?.origin===this.sessionId)continue;const t=e?.syncMetadata,r=this.extractChangedFields(s,e.state,t,n.oldValue);if(!Object.keys(r).length)continue;s.registration.apply({replace:!1,sessionId:t?.origin??"unknown",timestamp:t?.timestamp??Date.now(),values:r})}catch(e){continue}}},e&&"storage"in e?(this.area=e.storage.area,this.storageKeyPrefix=e.storage.storageKeyPrefix):(this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??n),this.sessionId=this.generateSessionId(),this.attachListener()}destroy(){for(const e of this.registrations.values())e.destroyed=!0,e.listeners.clear();this.detachListener()}register(e){this.attachListener();const t={destroyed:!1,hydrated:!0,listeners:new Set,registration:e};return this.setRegistration(e.key,t),{destroy:()=>{t.destroyed=!0,t.listeners.clear(),this.registrations.delete(e.key),this.registrations.size||this.detachListener()},publish:null}}generateSessionId(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Math.random().toString(36).slice(2)}:${Date.now().toString(36)}`}attachListener(){"undefined"!=typeof chrome&&chrome.storage&&!this.isListening&&(this.isListening=!0,chrome.storage.onChanged.addListener(this.onStorageChanged))}detachListener(){"undefined"!=typeof chrome&&chrome.storage&&this.isListening&&(chrome.storage.onChanged.removeListener(this.onStorageChanged),this.isListening=!1)}extractChangedFields(e,r,n,o){const i=Object.create(s),a=n?.fields;if(a&&Object.keys(a).length>0){let s=!1;for(const n of e.registration.fields)t(a,String(n))&&(i[n]=r[n],s=!0);if(s)return i}const c=this.parsePersistValue(o);for(const t of e.registration.fields){const e=r[t],s=c?.state[t];Object.is(e,s)||(i[t]=e)}return i}setRegistration(e,t){this.registrations.set(e,t)}toStorageKey(e){return this.storageKeyPrefix?`${this.storageKeyPrefix}${e}`:e}parsePersistValue(e){return h(e)}};exports.ChromeExtensionSyncEngine=y,exports.ChromeStorageAdapter=a,exports.createSyncedChromeStorage=function(e){const t=new a(e);return{storage:t,syncEngine:new y({storage:t})}};
@@ -1 +1 @@
1
- import{DEFAULT_STORAGE_KEY_PREFIX as t,isPromiseLike as e,replacer as r,reviver as s,isPlainObject as n}from"./chunk-MMPMCVRC.mjs";var i=class{constructor(e){this.async=!0,this.deserializer=a,this.serializer=o,this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??t}async clearAll(){const t=this.ensureStorage();if(!t)return;if(!this.storageKeyPrefix)throw new Error("Cannot clear all storage with empty storageKeyPrefix. This would delete all storage entries.");const e=await this.listPrefixedKeys(t,this.storageKeyPrefix);e.length&&await this.execute(t,r=>t.remove(e,r))}async contains(t){const e=this.ensureStorage();if(!e)return!1;const r=this.toStorageKey(t),s=await this.getFromStorage(e,r);return Object.prototype.hasOwnProperty.call(s,r)}async delete(t){const e=this.ensureStorage();if(!e)return;const r=this.toStorageKey(t);await this.execute(e,t=>e.remove(r,t))}async getAllKeys(){const t=this.ensureStorage();if(!t)return[];const e=await this.getFromStorage(t,null),r=this.storageKeyPrefix;return r?Object.keys(e).filter(t=>t.startsWith(r)).map(t=>t.slice(r.length)):Object.keys(e)}async get(t){const e=this.ensureStorage();if(!e)return;const r=this.toStorageKey(t);return c((await this.getFromStorage(e,r))[r])||void 0}async set(t,e){const r=this.ensureStorage();if(!r)return;const s=this.toStorageKey(t);await this.execute(r,t=>r.set({[s]:e},t))}ensureStorage(){return t=this.area,"undefined"!=typeof chrome&&chrome.storage?chrome.storage[t]??null:null;var t}toStorageKey(t){return this.storageKeyPrefix?`${this.storageKeyPrefix}${t}`:t}async listPrefixedKeys(t,e){const r=await this.getFromStorage(t,null);return Object.keys(r).filter(t=>t.startsWith(e))}async getFromStorage(t,e){return this.invokeWithCallbackSupport(r=>t.get(e,r))}async execute(t,e){await this.invokeWithCallbackSupport(e)}async invokeWithCallbackSupport(t){return new Promise((r,s)=>{let n=!1;const i=t=>{if(n)return;n=!0;const e="undefined"!=typeof chrome&&chrome.runtime&&chrome.runtime.lastError?new Error(chrome.runtime.lastError.message):null;e?s(e):r(t)};try{const r=t(i);e(r)&&r.then(i).catch(s)}catch(t){s(t)}})}};function o(t){return{state:g(t.state),syncMetadata:t.syncMetadata,version:t.version}}function a(t){const e=c(t);if(!e)throw new Error("[ChromeStorageAdapter] Invalid serialized state format");return{state:l(e.state),syncMetadata:e.syncMetadata,version:e.version}}function c(t){if(h(t))return t;if("string"==typeof t)try{const e=JSON.parse(t);if(h(e))return e}catch{}return null}function h(t){return!(!t||"object"!=typeof t)&&Object.prototype.hasOwnProperty.call(t,"state")}function g(t,e=r){if(t instanceof Map||t instanceof Set)return e.call(void 0,"",t);if(!n(t))return t;const s={};for(const[r,n]of Object.entries(t))s[r]=e.call(t,r,n);return s}function l(t,e=s){const r=e.call(void 0,"",t);if(!n(r))return r;const i={};for(const t of Object.entries(r)){const s=t[0],n=t[1];i[s]=e.call(r,s,n)}return i}var u=class{constructor(e){this.injectStorageMetadata=!0,this.registrations=new Map,this.isListening=!1,this.onStorageChanged=async(t,e)=>{if(e===this.area)for(const e of this.registrations){const r=e[0],s=e[1];if(s.destroyed)continue;const n=t[this.toStorageKey(r)];if(n&&void 0!==n.newValue)try{const t=this.parsePersistValue(n.newValue);if(!t||t.syncMetadata?.origin===this.sessionId)continue;const e=t?.syncMetadata,r=this.extractChangedFields(s,t.state,e,n.oldValue);if(!Object.keys(r).length)continue;s.registration.apply({replace:!1,sessionId:e?.origin??"unknown",timestamp:e?.timestamp??Date.now(),values:r})}catch(t){continue}}},e&&"storage"in e?(this.area=e.storage.area,this.storageKeyPrefix=e.storage.storageKeyPrefix):(this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??t),this.sessionId=this.generateSessionId(),this.attachListener()}generateSessionId(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Math.random().toString(36).slice(2)}:${Date.now().toString(36)}`}register(t){this.attachListener();const e={destroyed:!1,hydrated:!0,listeners:new Set,registration:t};return this.registrations.set(t.key,e),{destroy:()=>{e.destroyed=!0,e.listeners.clear(),this.registrations.delete(t.key),this.registrations.size||this.detachListener()},publish:null}}attachListener(){"undefined"!=typeof chrome&&chrome.storage&&!this.isListening&&(this.isListening=!0,chrome.storage.onChanged.addListener(this.onStorageChanged))}detachListener(){"undefined"!=typeof chrome&&chrome.storage&&this.isListening&&(chrome.storage.onChanged.removeListener(this.onStorageChanged),this.isListening=!1)}extractChangedFields(t,e,r,s){const n=Object.create(null),i=r?.fields;if(i&&Object.keys(i).length>0){let r=!1;for(const s of t.registration.fields){const t=String(s);Object.prototype.hasOwnProperty.call(i,t)&&(n[s]=e[s],r=!0)}if(r)return n}const o=this.parsePersistValue(s);for(const r of t.registration.fields){const t=e[r],s=o?.state[r];Object.is(t,s)||(n[r]=t)}return n}toStorageKey(t){return this.storageKeyPrefix?`${this.storageKeyPrefix}${t}`:t}parsePersistValue(t){return a(t)}};function f(t){const e=new i(t);return{storage:e,syncEngine:new u({storage:e})}}export{u as ChromeExtensionSyncEngine,i as ChromeStorageAdapter,f as createSyncedChromeStorage};
1
+ import{DEFAULT_STORAGE_KEY_PREFIX as t,isPromiseLike as e,replacer as r,reviver as s,isPlainObject as i,nullObject as n,hasOwn as o}from"./chunk-3U5A7HQV.mjs";var a=class{constructor(e){this.async=!0,this.deserializer=h,this.serializer=c,this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??t}async clearAll(){const t=this.ensureStorage();if(!t)return;if(!this.storageKeyPrefix)throw new Error("Cannot clear all storage with empty storageKeyPrefix. This would delete all storage entries.");const e=await this.listPrefixedKeys(t,this.storageKeyPrefix);e.length&&await this.execute(t,r=>t.remove(e,r))}async contains(t){const e=this.ensureStorage();if(!e)return!1;const r=this.toStorageKey(t),s=await this.getFromStorage(e,r);return Object.prototype.hasOwnProperty.call(s,r)}async delete(t){const e=this.ensureStorage();if(!e)return;const r=this.toStorageKey(t);await this.execute(e,t=>e.remove(r,t))}async getAllKeys(){const t=this.ensureStorage();if(!t)return[];const e=await this.getFromStorage(t,null),r=this.storageKeyPrefix;return r?Object.keys(e).filter(t=>t.startsWith(r)).map(t=>t.slice(r.length)):Object.keys(e)}async get(t){const e=this.ensureStorage();if(!e)return;const r=this.toStorageKey(t);return g((await this.getFromStorage(e,r))[r])||void 0}async set(t,e){const r=this.ensureStorage();if(!r)return;const s=this.toStorageKey(t);await this.execute(r,t=>r.set({[s]:e},t))}ensureStorage(){return t=this.area,"undefined"!=typeof chrome&&chrome.storage?chrome.storage[t]??null:null;var t}toStorageKey(t){return this.storageKeyPrefix?`${this.storageKeyPrefix}${t}`:t}async listPrefixedKeys(t,e){const r=await this.getFromStorage(t,null);return Object.keys(r).filter(t=>t.startsWith(e))}async getFromStorage(t,e){return this.invokeWithCallbackSupport(r=>t.get(e,r))}async execute(t,e){await this.invokeWithCallbackSupport(e)}async invokeWithCallbackSupport(t){return new Promise((r,s)=>{let i=!1;function n(t){if(i)return;i=!0;const e="undefined"!=typeof chrome&&chrome.runtime&&chrome.runtime.lastError?new Error(chrome.runtime.lastError.message):null;e?s(e):r(t)}try{const r=t(n);e(r)&&r.then(n).catch(s)}catch(t){s(t)}})}};function c(t){return{state:u(t.state),syncMetadata:t.syncMetadata,version:t.version}}function h(t){const e=g(t);if(!e)throw new Error("[ChromeStorageAdapter] Invalid serialized state format");return{state:f(e.state),syncMetadata:e.syncMetadata,version:e.version}}function g(t){if(l(t))return t;if("string"==typeof t)try{const e=JSON.parse(t);if(l(e))return e}catch{}return null}function l(t){return!(!t||"object"!=typeof t)&&Object.prototype.hasOwnProperty.call(t,"state")}function u(t,e=r){if(t instanceof Map||t instanceof Set)return e.call(void 0,"",t);if(!i(t))return t;const s={};for(const[r,i]of Object.entries(t))s[r]=e.call(t,r,i);return s}function f(t,e=s){const r=e.call(void 0,"",t);if(!i(r))return r;const n={};for(const t of Object.entries(r)){const s=t[0],i=t[1];n[s]=e.call(r,s,i)}return n}var y=class{constructor(e){this.injectStorageMetadata=!0,this.registrations=new Map,this.isListening=!1,this.onStorageChanged=async(t,e)=>{if(e===this.area)for(const e of this.registrations){const r=e[0],s=e[1];if(s.destroyed)continue;const i=t[this.toStorageKey(r)];if(i&&void 0!==i.newValue)try{const t=this.parsePersistValue(i.newValue);if(!t||t.syncMetadata?.origin===this.sessionId)continue;const e=t?.syncMetadata,r=this.extractChangedFields(s,t.state,e,i.oldValue);if(!Object.keys(r).length)continue;s.registration.apply({replace:!1,sessionId:e?.origin??"unknown",timestamp:e?.timestamp??Date.now(),values:r})}catch(t){continue}}},e&&"storage"in e?(this.area=e.storage.area,this.storageKeyPrefix=e.storage.storageKeyPrefix):(this.area=e?.area??"local",this.storageKeyPrefix=e?.storageKeyPrefix??t),this.sessionId=this.generateSessionId(),this.attachListener()}destroy(){for(const t of this.registrations.values())t.destroyed=!0,t.listeners.clear();this.detachListener()}register(t){this.attachListener();const e={destroyed:!1,hydrated:!0,listeners:new Set,registration:t};return this.setRegistration(t.key,e),{destroy:()=>{e.destroyed=!0,e.listeners.clear(),this.registrations.delete(t.key),this.registrations.size||this.detachListener()},publish:null}}generateSessionId(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Math.random().toString(36).slice(2)}:${Date.now().toString(36)}`}attachListener(){"undefined"!=typeof chrome&&chrome.storage&&!this.isListening&&(this.isListening=!0,chrome.storage.onChanged.addListener(this.onStorageChanged))}detachListener(){"undefined"!=typeof chrome&&chrome.storage&&this.isListening&&(chrome.storage.onChanged.removeListener(this.onStorageChanged),this.isListening=!1)}extractChangedFields(t,e,r,s){const i=n(),a=r?.fields;if(a&&Object.keys(a).length>0){let r=!1;for(const s of t.registration.fields){const t=String(s);o(a,t)&&(i[s]=e[s],r=!0)}if(r)return i}const c=this.parsePersistValue(s);for(const r of t.registration.fields){const t=e[r],s=c?.state[r];Object.is(t,s)||(i[r]=t)}return i}setRegistration(t,e){this.registrations.set(t,e)}toStorageKey(t){return this.storageKeyPrefix?`${this.storageKeyPrefix}${t}`:t}parsePersistValue(t){return h(t)}};function d(t){const e=new a(t);return{storage:e,syncEngine:new y({storage:e})}}export{y as ChromeExtensionSyncEngine,a as ChromeStorageAdapter,d as createSyncedChromeStorage};
@@ -0,0 +1 @@
1
+ var e=class extends Error{constructor(e,t){super(e),this.name="StoresError",void 0!==t&&Object.defineProperty(this,"cause",{configurable:!0,value:t,writable:!0})}};function t(e){return e instanceof Error?e:new Error(String(e))}var r="undefined"!=typeof window&&"undefined"!=typeof document,n=!1,o="development"===process.env.NODE_ENV,s="test"===process.env.NODE_ENV,i=e=>e(),a=Object.freeze(Object.create(null));function c(e){return e}function l(){return Object.create(a)}function u(e,t){return void 0===t?Object.assign(l(),e):Object.assign(l(),e,t)}function f(){}function d(){return"undefined"!=typeof window?window.localStorage:null}var y={debug:(e,t)=>{o&&console.debug(e,t)},error:(e,t)=>{o&&!s&&console.error(e,t)},info:(e,t)=>{o&&console.info(e,t)},warn:(e,t)=>{o&&console.warn(e,t)}},h=Object.prototype.hasOwnProperty;function g(e,t){return h.call(e,t)}function p(e){if("object"!=typeof e||null===e)return!1;const t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}var w="stores/core/sync-channel",v=`${w}:storage:`;function m(){try{return"undefined"!=typeof window?window.localStorage:null}catch{return null}}var b,S,E,O,j=class{constructor(e){this.broadcast=e.broadcast,this.origin=e.origin,this.storeKey=e.storeKey,this.teardown=e.teardown}destroy(){this.teardown()}publish(e){const t=l();for(const r of Object.entries(e.values))t[r[0]]=r[1];const r={origin:this.origin,replace:e.replace,sessionId:e.sessionId,storeKey:this.storeKey,timestamp:e.timestamp,values:t};this.broadcast(r)}},I=class{constructor(){this.listeners=new Map,this.origin="undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Math.random().toString(36).slice(2)}:${Date.now().toString(36)}`,this.onChannelMessage=e=>{e.data&&this.dispatch(e.data)},this.onStorageEvent=t=>{if(t.key&&t.newValue&&t.key.startsWith(v))try{const e=JSON.parse(t.newValue);this.dispatch(e)}catch(t){y.error(new e("[sync] Failed to parse storage event payload",t))}},this.channel="undefined"==typeof BroadcastChannel?null:new BroadcastChannel(w),this.storage=m(),this.channel&&this.channel.addEventListener("message",this.onChannelMessage),r&&window.addEventListener("storage",this.onStorageEvent)}get sessionId(){return this.origin}register(e){const t=t=>{if(t.origin===this.origin||t.storeKey!==e.key)return;const r=l();for(const n of e.fields)g(t.values,n)&&(r[n]=t.values[n]);Object.keys(r).length&&e.apply({replace:t.replace,sessionId:t.sessionId,timestamp:t.timestamp,values:r})};let r=this.listeners.get(e.key);return r||(r=new Set,this.listeners.set(e.key,r)),r.add(t),new j({broadcast:e=>this.broadcast(e),origin:this.origin,storeKey:e.key,teardown:()=>this.removeListener(e.key,t)})}broadcast(t){try{this.channel&&this.channel.postMessage(t),this.writeToStorage(t)}catch(t){y.error(new e("[sync] Failed to broadcast update",t))}}dispatch(e){if(!e.storeKey)return;const t=this.listeners.get(e.storeKey);if(t&&t.size)for(const r of t)r(e)}removeListener(e,t){const r=this.listeners.get(e);r&&(r.delete(t),r.size||this.listeners.delete(e))}writeToStorage(t){if(this.storage||(this.storage=m()),!this.storage)return;const r=`${v}${t.storeKey}`;try{this.storage.setItem(r,JSON.stringify(t))}catch(t){y.error(new e("[sync] Failed to write broadcast payload to storage",t))}}},_=class{destroy(){}publish(){}},$=class{constructor(){this.sessionId="noop"}register(e){return new _}},k="stores:",K=!1;function M(e){var t;o&&function(){if(K)throw new Error("[stores]: configureStores() called after first store creation. Call it earlier before creating any stores.")}(),e.logger&&(t=e.logger,y=t),E??(E=function(e){return e?.queryStoreDefaults?{queryStoreDefaults:e.queryStoreDefaults}:void 0}(e)),O??(O=C(e))}function D(){if(E)return E}function N(){return O??(O=C(void 0))}function A(){K=!0}function C(e){return{storage:e?.storage??(t=e?.storageKeyPrefix??k,{clearAll(){try{const e=d();if(!e)return;const r=[];for(let n=0;n<e.length;n++){const o=e.key(n);o?.startsWith(t)&&r.push(o)}for(const t of r)e.removeItem(t)}catch(e){console.error("Error clearing localStorage:",e)}},contains(e){const r=d();return null!==r?.getItem(`${t}${e}`)},delete(e){try{const r=d();r?.removeItem(`${t}${e}`)}catch(e){console.error("Error deleting from localStorage:",e)}},getAllKeys(){try{const e=d();return e?Array.from(e.keys()):[]}catch(e){return console.error("Error getting keys from localStorage:",e),[]}},get(e){try{const r=d();return r?r.getItem(`${t}${e}`)??void 0:void 0}catch(e){return void console.error("Error reading from localStorage:",e)}},set(e,r){try{const n=d();n?.setItem(`${t}${e}`,r)}catch(e){console.error("Error writing to localStorage:",e)}}}),syncEngine:e?.syncEngine??(r?(b||(b=new I),b):(S||(S=new $),S))};var t}function L(e,t){return t instanceof Map?{__type:"Map",entries:Array.from(t.entries())}:t instanceof Set?{__type:"Set",values:Array.from(t)}:t}function P(e,t){return function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Map"===e.__type}(t)?new Map(t.entries):function(e){return"object"==typeof e&&null!==e&&"__type"in e&&"Set"===e.__type}(t)?new Set(t.values):t}function U(e){return!!e&&"object"==typeof e&&"then"in e&&"function"==typeof e.then}export{k as DEFAULT_STORAGE_KEY_PREFIX,r as IS_BROWSER,o as IS_DEV,n as IS_IOS,s as IS_TEST,e as StoresError,u as buildNullObject,M as configureStores,t as ensureError,D as getOptions,N as getStorageConfig,g as hasOwn,c as identity,p as isPlainObject,U as isPromiseLike,y as logger,A as markStoreCreated,f as noop,l as nullObject,L as replacer,P as reviver,i as unstable_batchedUpdates};