@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.
- package/dist/config.d.ts +37 -7
- package/dist/createQueryStore.d.ts +3 -19
- package/dist/createStoreWithEqualityFn.d.ts +5 -0
- package/dist/createVirtualStore.d.ts +4 -3
- package/dist/derivedStore/cascadeScheduler.d.ts +8 -0
- package/dist/derivedStore/deriveProxy.d.ts +6 -16
- package/dist/derivedStore/pathFinder.d.ts +27 -0
- package/dist/errors.d.ts +14 -0
- package/dist/hooks/useSyncExternalStoreWithSelector.d.ts +5 -0
- package/dist/index.d.ts +3 -1
- package/dist/logger.d.ts +0 -5
- package/dist/native/index.js +1 -1
- package/dist/native/index.mjs +1 -1
- package/dist/plugins/chrome/chromeExtensionSyncEngine.d.ts +3 -1
- package/dist/queryStore/queryStoreDefaults.d.ts +8 -0
- package/dist/queryStore/signalTypes.d.ts +13 -0
- package/dist/queryStore/types.d.ts +35 -30
- package/dist/signal.d.ts +2 -11
- package/dist/sync/syncEnhancer.d.ts +4 -0
- package/dist/sync/types.d.ts +53 -128
- package/dist/types/functions.d.ts +19 -2
- package/dist/types/objects.d.ts +10 -3
- package/dist/types.d.ts +26 -27
- package/dist/utils/core.d.ts +23 -4
- package/dist/utils/createStoreActions.d.ts +3 -3
- package/dist/utils/persistUtils.d.ts +2 -2
- package/dist/utils/storeUtils.d.ts +1 -1
- package/dist/utils/time.d.ts +0 -3
- package/dist/web/chrome.js +1 -1
- package/dist/web/chrome.mjs +1 -1
- package/dist/web/chunk-3U5A7HQV.mjs +1 -0
- package/dist/web/index.js +1 -1
- package/dist/web/index.mjs +1 -1
- package/package.json +10 -6
- package/dist/sync/transport.d.ts +0 -113
- package/dist/web/chunk-MMPMCVRC.mjs +0 -1
package/dist/sync/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
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
|
|
61
|
-
* storage
|
|
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
|
|
84
|
+
* The sync engine implementation to use.
|
|
148
85
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
86
|
+
* Defaults to cross-tab sync in browser environments. No-op in other environments unless a
|
|
87
|
+
* custom engine is provided.
|
|
151
88
|
*/
|
|
152
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
package/dist/types/objects.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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 {
|
|
4
|
-
import {
|
|
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
|
|
60
|
-
*
|
|
61
|
-
*
|
|
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
|
|
68
|
-
* Returns `
|
|
66
|
+
* Extracts a store's `PersistedState` type.
|
|
67
|
+
* Returns `never` if the store doesn't use persistence.
|
|
69
68
|
*/
|
|
70
|
-
export type InferPersistedState<Store,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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?:
|
|
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?:
|
|
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.
|
package/dist/utils/core.d.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Returns the
|
|
3
|
-
* @param value - Any value.
|
|
4
|
-
* @returns `value`.
|
|
2
|
+
* Returns the argument provided.
|
|
5
3
|
*/
|
|
6
|
-
export declare
|
|
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
|
|
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
|
|
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
|
/**
|
package/dist/utils/time.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/web/chrome.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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})}};
|
package/dist/web/chrome.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_STORAGE_KEY_PREFIX as t,isPromiseLike as e,replacer as r,reviver as s,isPlainObject as n}from"./chunk-
|
|
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};
|