@storesjs/stores 0.8.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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config.d.ts +13 -0
  3. package/dist/createBaseStore.d.ts +35 -0
  4. package/dist/createDerivedStore.d.ts +70 -0
  5. package/dist/createQueryStore.d.ts +131 -0
  6. package/dist/createVirtualStore.d.ts +39 -0
  7. package/dist/derivedStore/deriveProxy.d.ts +24 -0
  8. package/dist/derivedStore/globalDeriveScheduler.d.ts +22 -0
  9. package/dist/env.d.ts +7 -0
  10. package/dist/env.native.d.ts +8 -0
  11. package/dist/env.web.d.ts +7 -0
  12. package/dist/hooks/compareHooks.d.ts +49 -0
  13. package/dist/hooks/useLazyRef.d.ts +12 -0
  14. package/dist/hooks/useListen.d.ts +97 -0
  15. package/dist/hooks/useStableValue.d.ts +15 -0
  16. package/dist/index.d.ts +16 -0
  17. package/dist/logger.d.ts +16 -0
  18. package/dist/middleware/createHydrationGate.d.ts +19 -0
  19. package/dist/middleware/createSubscriptionManager.d.ts +10 -0
  20. package/dist/native/index.js +1 -0
  21. package/dist/native/index.mjs +1 -0
  22. package/dist/plugins/chrome/chromeExtensionSyncEngine.d.ts +31 -0
  23. package/dist/plugins/chrome/chromeStorageAdapter.d.ts +32 -0
  24. package/dist/plugins/chrome/createSyncedChromeStorage.d.ts +16 -0
  25. package/dist/plugins/chrome/index.d.ts +3 -0
  26. package/dist/plugins/chrome/utils.d.ts +1 -0
  27. package/dist/plugins/delta/deltaInstrumentation.d.ts +42 -0
  28. package/dist/plugins/delta/index.d.ts +1 -0
  29. package/dist/plugins/delta/recordDelta.d.ts +14 -0
  30. package/dist/plugins/network/index.d.ts +2 -0
  31. package/dist/plugins/router/RouteErrorBoundary.d.ts +19 -0
  32. package/dist/plugins/router/__tests__/router-types.test.d.ts +0 -0
  33. package/dist/plugins/router/constants.d.ts +38 -0
  34. package/dist/plugins/router/createRouter-old-version.d.ts +183 -0
  35. package/dist/plugins/router/createRouter.d.ts +183 -0
  36. package/dist/plugins/router/errorBoundary.d.ts +23 -0
  37. package/dist/plugins/router/index.d.ts +6 -0
  38. package/dist/plugins/router/lazy.d.ts +14 -0
  39. package/dist/plugins/router/locationStore.d.ts +24 -0
  40. package/dist/plugins/router/pathMatching.d.ts +28 -0
  41. package/dist/plugins/router/scrollRestoration.d.ts +8 -0
  42. package/dist/plugins/router/searchParams.d.ts +53 -0
  43. package/dist/plugins/router/test-link-params.d.ts +1 -0
  44. package/dist/plugins/router/test-prefetch.d.ts +17 -0
  45. package/dist/plugins/router/test-types.d.ts +1 -0
  46. package/dist/plugins/router/types.d.ts +11 -0
  47. package/dist/plugins/router/utils.d.ts +14 -0
  48. package/dist/plugins/router/vite.d.ts +5 -0
  49. package/dist/presence/heartbeat.d.ts +23 -0
  50. package/dist/presence/presenceChannel.d.ts +19 -0
  51. package/dist/presence/pruning.d.ts +34 -0
  52. package/dist/queryStore/classes/SubscriptionManager.d.ts +66 -0
  53. package/dist/queryStore/createParamManager.d.ts +27 -0
  54. package/dist/queryStore/types.d.ts +396 -0
  55. package/dist/signal.d.ts +19 -0
  56. package/dist/storage/storageCreators.d.ts +21 -0
  57. package/dist/storage/storageTypes.d.ts +12 -0
  58. package/dist/storesStorage.d.ts +2 -0
  59. package/dist/storesStorage.native.d.ts +2 -0
  60. package/dist/storesStorage.web.d.ts +2 -0
  61. package/dist/sync/browserSyncEngine.d.ts +2 -0
  62. package/dist/sync/networkSyncEngine.d.ts +137 -0
  63. package/dist/sync/noopSyncEngine.d.ts +2 -0
  64. package/dist/sync/syncEnhancer.d.ts +21 -0
  65. package/dist/sync/syncUtils.d.ts +5 -0
  66. package/dist/sync/transport.d.ts +112 -0
  67. package/dist/sync/types.d.ts +189 -0
  68. package/dist/tsconfig.tsbuildinfo +1 -0
  69. package/dist/types/functions.d.ts +6 -0
  70. package/dist/types/objects.d.ts +3 -0
  71. package/dist/types/utils.d.ts +8 -0
  72. package/dist/types.d.ts +332 -0
  73. package/dist/utils/core.d.ts +6 -0
  74. package/dist/utils/createAsyncMicrotaskScheduler.d.ts +34 -0
  75. package/dist/utils/createMicrotaskScheduler.d.ts +27 -0
  76. package/dist/utils/createStoreActions.d.ts +24 -0
  77. package/dist/utils/debounce.d.ts +21 -0
  78. package/dist/utils/equality.d.ts +37 -0
  79. package/dist/utils/factoryUtils.d.ts +21 -0
  80. package/dist/utils/hydrationCoordinator.d.ts +12 -0
  81. package/dist/utils/persistUtils.d.ts +8 -0
  82. package/dist/utils/promiseUtils.d.ts +1 -0
  83. package/dist/utils/serialization.d.ts +13 -0
  84. package/dist/utils/storeUtils.d.ts +56 -0
  85. package/dist/utils/stringUtils.d.ts +6 -0
  86. package/dist/utils/time.d.ts +46 -0
  87. package/dist/web/chrome.js +1 -0
  88. package/dist/web/chrome.mjs +1 -0
  89. package/dist/web/chunk-YWUZUTPH.mjs +1 -0
  90. package/dist/web/index.js +1 -0
  91. package/dist/web/index.mjs +1 -0
  92. package/package.json +75 -0
@@ -0,0 +1,396 @@
1
+ import { AttachValue, SignalFunction } from '../signal';
2
+ import { BaseStore, DebounceOptions, SetPartial, Store } from '../types';
3
+ /**
4
+ * Helper type that represents the store returned by `createQueryStore()`.
5
+ */
6
+ export type QueryStore<TData, TParams extends Record<string, unknown>, CustomState = unknown> = Store<QueryStoreState<TData, TParams, CustomState>>;
7
+ /**
8
+ * Configuration options for creating a query-enabled store.
9
+ */
10
+ export type QueryStoreConfig<TQueryFnData, TParams extends Record<string, unknown>, TData = TQueryFnData, CustomState = unknown, S extends QueryStoreState<TData, TParams, CustomState> = QueryStoreState<TData, TParams, CustomState>> = {
11
+ /**
12
+ * **A function responsible for fetching data from a remote source.**
13
+ * Receives parameters of type TParams and optionally an abort controller.
14
+ * Returns either a promise or a raw data value of type TQueryFnData.
15
+ *
16
+ * ---
17
+ * `abortController` is by default available, unless either:
18
+ * - `abortInterruptedFetches` is set to `false` in the store's config
19
+ * - The fetch was manually triggered with `skipStoreUpdates: true`
20
+ */
21
+ fetcher: (params: TParams, abortController: AbortController | null) => TQueryFnData | Promise<TQueryFnData>;
22
+ /**
23
+ * **A callback invoked whenever a fetch operation fails.**
24
+ * Receives the error and the current retry count.
25
+ */
26
+ onError?: (error: Error, retryCount: number) => void;
27
+ /**
28
+ * **A callback invoked whenever fresh data is successfully fetched.**
29
+ * Receives the transformed data and the store's set function, which can optionally be used to update store state.
30
+ */
31
+ onFetched?: (info: OnFetchedParams<TData, TParams, CustomState, S>) => void;
32
+ /**
33
+ * **A function that overrides the default behavior of setting the fetched data in the store's query cache.**
34
+ * Receives an object containing the transformed data, the query parameters, the query key, and the store's set function.
35
+ *
36
+ * When using `setData`, it’s important to note that you are taking full responsibility for managing query data. If your
37
+ * query supports variable parameters (and thus multiple query keys) and you want to cache data for each key, you’ll need
38
+ * to manually handle storing data based on the provided `params` or `queryKey`. Naturally, you will also bear
39
+ * responsibility for pruning this data in the event you do not want it persisted indefinitely.
40
+ *
41
+ * Automatic refetching per your specified `staleTime` is still managed internally by the store. While no query *data*
42
+ * will be cached internally if `setData` is provided, metadata such as the last fetch time for each query key is still
43
+ * cached and tracked by the store, unless caching is fully disabled via `disableCache: true`.
44
+ */
45
+ setData?: (info: SetDataParams<TData, TParams, CustomState, S>) => void;
46
+ /**
47
+ * **A function to transform the raw fetched data** (`TQueryFnData`) into another form (`TData`).
48
+ * If not provided, the raw data returned by `fetcher` is used.
49
+ */
50
+ transform?: (data: TQueryFnData, params: TParams) => TData;
51
+ /**
52
+ * If `true`, the store will abort any partially completed fetches when:
53
+ * - A new fetch is initiated due to a change in parameters
54
+ * - All components subscribed to the store via selectors are unmounted
55
+ * @default true
56
+ */
57
+ abortInterruptedFetches?: boolean;
58
+ /**
59
+ * The maximum duration, in milliseconds, that fetched data is considered fresh.
60
+ * After this time, data is considered expired and will be refetched when requested.
61
+ * @default time.days(7)
62
+ */
63
+ cacheTime?: number | ((params: TParams) => number);
64
+ /**
65
+ * If `true`, the store will log debug messages to the console.
66
+ * @default false
67
+ */
68
+ debugMode?: boolean;
69
+ /**
70
+ * If `true`, the store will **not** trigger automatic refetches when data becomes stale. This is
71
+ * useful in cases where you want to refetch data on component mount if stale, but not automatically
72
+ * if data becomes stale while your component is already mounted.
73
+ * @default false
74
+ */
75
+ disableAutoRefetching?: boolean;
76
+ /**
77
+ * Controls whether the store's caching mechanisms are disabled. When disabled, the store will always refetch
78
+ * data when params change, and fetched data will not be stored unless a `setData` function is provided.
79
+ * @default false
80
+ */
81
+ disableCache?: boolean;
82
+ /**
83
+ * When `true`, the store actively fetches and refetches data as needed.
84
+ * When `false`, the store will not automatically fetch data until explicitly enabled.
85
+ * @default true
86
+ */
87
+ enabled?: boolean | ReactiveParam<boolean, TParams, S, TData>;
88
+ /**
89
+ * When `true`, the store's `getData` method will always return existing data from the cache if it exists,
90
+ * regardless of whether the cached data is expired, until the data is pruned following a successful refetch.
91
+ *
92
+ * Additionally, when params change while the store is enabled, `getData` will return the previous data until
93
+ * data for the new params is available.
94
+ * @default false
95
+ */
96
+ keepPreviousData?: boolean;
97
+ /**
98
+ * The maximum number of times to retry a failed fetch operation.
99
+ * @default 5
100
+ */
101
+ maxRetries?: number;
102
+ /**
103
+ * Delay before triggering a fetch when parameters change.
104
+ * Accepts a number (ms), false (no throttling), or debounce options:
105
+ *
106
+ * `{ delay: number, leading?: boolean, trailing?: boolean, maxWait?: number }`
107
+ * @default false
108
+ */
109
+ paramChangeThrottle?: false | number | DebounceOptions;
110
+ /**
111
+ * Parameters to be passed to the fetcher, defined as either direct values or `ReactiveParam` functions.
112
+ * Dynamic parameters using `AttachValue` will cause the store to refetch when their values change.
113
+ */
114
+ params?: QueryStoreParams<TParams, TData, S, CustomState>;
115
+ /**
116
+ * The delay between retries after a fetch error occurs, in milliseconds, defined as a number or a function that
117
+ * receives the error and current retry count and returns a number.
118
+ *
119
+ * @default Exponential backoff starting at 5s, doubling each retry, capped at 5m:
120
+ * ```ts
121
+ * retryCount => Math.min(time.seconds(5) * Math.pow(2, retryCount), time.minutes(5))
122
+ * ```
123
+ */
124
+ retryDelay?: number | ((retryCount: number, error: Error) => number);
125
+ /**
126
+ * The duration, in milliseconds, that data is considered fresh after fetching.
127
+ * After becoming stale, the store may automatically refetch data in the background if there are active subscribers.
128
+ *
129
+ * **Note:** Stale times under 5 seconds are strongly discouraged.
130
+ * @default time.minutes(2)
131
+ */
132
+ staleTime?: number | ReactiveParam<number, TParams, S, TData>;
133
+ /**
134
+ * Suppresses warnings in the event a `staleTime` under the minimum is desired.
135
+ * @default false
136
+ */
137
+ suppressStaleTimeWarning?: boolean;
138
+ /**
139
+ * @deprecated Only use for backwards compatibility.
140
+ * @default true
141
+ */
142
+ useParsableQueryKeys?: boolean;
143
+ };
144
+ /**
145
+ * The full state structure managed by the query store. This type is generally internal,
146
+ * though the state it defines can be accessed via the store's public interface.
147
+ */
148
+ export type QueryStoreState<TData, TParams extends Record<string, unknown>, CustomState = unknown> = {
149
+ /**
150
+ * Initiates a data fetch for the given parameters. If no parameters are provided,
151
+ * the store's current parameters are used.
152
+ * @param params - Optional parameters to pass to the fetcher function.
153
+ * @param options - Optional {@link FetchOptions} to customize the fetch behavior.
154
+ * @returns A promise that resolves when the fetch operation completes.
155
+ */
156
+ fetch: (params?: Partial<TParams>, options?: FetchOptions) => Promise<TData | null>;
157
+ /**
158
+ * A lower-level helper that provides direct access to raw cache entries. If no query key
159
+ * or params are specified, the cache entry for the current parameters is returned.
160
+ * @param paramsOrQueryKey - Optional parameters or query key to retrieve the cache entry.
161
+ * @returns The relevant cache entry, or `null` if no entry is found.
162
+ */
163
+ getCacheEntry: (paramsOrQueryKey?: TParams | Partial<TParams> | string) => CacheEntry<TData> | null;
164
+ /**
165
+ * Returns the cached data, if available, for the provided query key or parameters.
166
+ * If no query key or params are specified, data for the current parameters is returned.
167
+ * @param paramsOrQueryKey - Optional parameters or query key to retrieve cached data for.
168
+ * @returns The cached data, or `null` if no data is available.
169
+ */
170
+ getData: (paramsOrQueryKey?: TParams | string) => CacheEntry<TData>['data'];
171
+ /**
172
+ * Returns expanded status information for the currently specified query parameters.
173
+ * Pass a status key to avoid building the full status object.
174
+ * @example
175
+ * ```ts
176
+ * const isInitialLoad = useMyQueryStore(state => state.getStatus('isInitialLoad'));
177
+ * ```
178
+ * @returns The requested status, or the full status object if no key is provided.
179
+ */
180
+ getStatus(statusKey: keyof QueryStatusInfo): QueryStatusInfo[keyof QueryStatusInfo];
181
+ getStatus(): QueryStatusInfo;
182
+ getStatus(statusKey?: keyof QueryStatusInfo): QueryStatusInfo[keyof QueryStatusInfo] | QueryStatusInfo;
183
+ /**
184
+ * Determines if the current data is expired based on whether `cacheTime` has been exceeded.
185
+ * @param override - An optional override for the default cache time, in milliseconds.
186
+ * @returns `true` if the data is expired, otherwise `false`.
187
+ */
188
+ isDataExpired: (override?: number) => boolean;
189
+ /**
190
+ * Determines if the current data is stale based on whether `staleTime` has been exceeded.
191
+ * Stale data may be refreshed automatically in the background.
192
+ * @param override - An optional override for the default stale time, in milliseconds.
193
+ * @returns `true` if the data is stale, otherwise `false`.
194
+ */
195
+ isStale: (override?: number) => boolean;
196
+ /**
197
+ * Tears down param subscriptions and timers and resets fetch state. Optionally resets store state.
198
+ * @param resetStoreState - If `true`, the store's state will be reset to its initial state.
199
+ * @default false
200
+ */
201
+ reset: (resetStoreState?: boolean) => void;
202
+ /**
203
+ * Indicates whether the store should actively fetch data.
204
+ * When `false`, the store won't automatically refetch data.
205
+ */
206
+ enabled: boolean;
207
+ /**
208
+ * The most recent error encountered during a fetch operation, if any.
209
+ */
210
+ error: Error | null;
211
+ /**
212
+ * The timestamp of the last successful fetch, or null if no successful fetch has occurred.
213
+ */
214
+ lastFetchedAt: number | null;
215
+ /**
216
+ * A cache of fetched data and metadata, keyed by query stringified params.
217
+ */
218
+ queryCache: Record<string, CacheEntry<TData> | undefined>;
219
+ /**
220
+ * The current query key, which is a string representation of the current query parameter values.
221
+ */
222
+ queryKey: string;
223
+ /**
224
+ * The current status of the query's remote data fetching operation.
225
+ */
226
+ status: QueryStatus;
227
+ } & CustomState;
228
+ /**
229
+ * Defines additional options for a data fetch operation.
230
+ */
231
+ export type FetchOptions = {
232
+ /**
233
+ * Overrides the store's default cacheTime for this fetch, which dictates when the data fetched in this operation
234
+ * will become eligible for pruning.
235
+ *
236
+ * Has no effect if `skipStoreUpdates` is set to `true`.
237
+ */
238
+ cacheTime?: number;
239
+ /**
240
+ * Forces a fetch request even if there is fresh data available in the cache.
241
+ *
242
+ * Note: If a pending fetch matches the forced fetch's params, the pending promise *will* be returned.
243
+ * @default false
244
+ */
245
+ force?: boolean;
246
+ /**
247
+ * If `true`, the fetch will simply return the data without any internal handling or side effects,
248
+ * running in parallel with any other ongoing fetches. Use together with `force: true` if you want to
249
+ * guarantee that a fresh fetch is triggered regardless of the current store state.
250
+ *
251
+ * ---
252
+ * If set to `'withCache'`, the fetch will similarly run in parallel without affecting the store, but the
253
+ * fetched data will be stored in the cache, as long as the store's config doesn't contain `disableCache: true`.
254
+ * @default false
255
+ */
256
+ skipStoreUpdates?: boolean | 'withCache';
257
+ /**
258
+ * Overrides the store's default staleTime for this fetch, which dictates how fresh data must be to be returned
259
+ * from the cache.
260
+ */
261
+ staleTime?: number;
262
+ /**
263
+ * If `true`, the fetch operation will throw an error if the fetch fails.
264
+ * @default false
265
+ */
266
+ throwOnError?: boolean;
267
+ /**
268
+ * Dictates whether the store's `queryKey` should be updated based on the params used in the fetch operation.
269
+ * Useful if for instance you want to cache the manually fetched data, but skip updating the store's current
270
+ * `queryKey` (which determines where `getData()` points to).
271
+ *
272
+ * ---
273
+ * Defaults to `true` unless `skipStoreUpdates: true` is specified, in which case the default is `false`.
274
+ */
275
+ updateQueryKey?: boolean;
276
+ };
277
+ /**
278
+ * A set of constants representing the various stages of a query's remote data fetching process.
279
+ */
280
+ export declare const QueryStatuses: {
281
+ readonly Error: "error";
282
+ readonly Idle: "idle";
283
+ readonly Loading: "loading";
284
+ readonly Success: "success";
285
+ };
286
+ /**
287
+ * Represents the current status of the query's remote data fetching operation.
288
+ *
289
+ * Possible values:
290
+ * - **`'error'`**: The most recent request encountered an error.
291
+ * - **`'idle'`**: No request in progress, no error, no data yet.
292
+ * - **`'loading'`**: A request is currently in progress.
293
+ * - **`'success'`**: The most recent request has succeeded and data is available.
294
+ */
295
+ export type QueryStatus = (typeof QueryStatuses)[keyof typeof QueryStatuses];
296
+ /**
297
+ * Expanded status information for the currently specified query parameters.
298
+ */
299
+ export type QueryStatusInfo = {
300
+ isError: boolean;
301
+ isIdle: boolean;
302
+ isInitialLoad: boolean;
303
+ isLoading: boolean;
304
+ isSuccess: boolean;
305
+ };
306
+ /**
307
+ * Represents an entry in the query cache, which stores fetched data along with metadata,
308
+ * and error information in the event the most recent fetch failed.
309
+ */
310
+ export type CacheEntry<T> = {
311
+ cacheTime: number;
312
+ data: T | null;
313
+ } & ({
314
+ errorInfo: {
315
+ error: Error;
316
+ lastFailedAt: number;
317
+ retryCount: number;
318
+ };
319
+ lastFetchedAt: null;
320
+ } | {
321
+ errorInfo: {
322
+ error: Error;
323
+ lastFailedAt: number;
324
+ retryCount: number;
325
+ } | null;
326
+ lastFetchedAt: number;
327
+ });
328
+ /**
329
+ * Internal helper type for the config’s params clause.
330
+ */
331
+ export type QueryStoreParams<TParams extends Record<string, unknown>, TData, S extends QueryStoreState<TData, TParams, CustomState>, CustomState = unknown> = [TParams] extends [Record<string, never>] ? undefined : {
332
+ [K in keyof TParams]: ReactiveParam<TParams[K], TParams, S, TData>;
333
+ };
334
+ /**
335
+ * Represents a parameter that can be provided directly or defined via a reactive `AttachValue`.
336
+ * A parameter can be:
337
+ * - A static value (e.g. `string`, `number`).
338
+ * - A function that returns an `AttachValue<T>` when given a `SignalFunction`.
339
+ */
340
+ export type ReactiveParam<T, TParams extends Record<string, unknown>, S extends QueryStoreState<TData, TParams>, TData> = T | (($: SignalFunction, store: BaseStore<S>) => AttachValue<T>);
341
+ /**
342
+ * The result of resolving reactive and static parameter values.
343
+ */
344
+ export type ResolvedParamsResult<TParams extends Record<string, unknown>> = {
345
+ /**
346
+ * Reactive parameter values wrapped in `AttachValue`, which trigger refetches when they change.
347
+ */
348
+ attachVals: Partial<Record<keyof TParams, AttachValue<unknown>>>;
349
+ /**
350
+ * Direct, non-reactive values resolved from the initial configuration.
351
+ */
352
+ directValues: Partial<TParams>;
353
+ /**
354
+ * Fully resolved parameters, merging both direct and reactive values.
355
+ */
356
+ resolvedParams: TParams;
357
+ };
358
+ /**
359
+ * The result of resolving the `enabled` option.
360
+ */
361
+ export type ResolvedEnabledResult = {
362
+ /**
363
+ * The reactive enabled state, if provided as a function returning an AttachValue.
364
+ */
365
+ enabledAttachVal: AttachValue<boolean> | null;
366
+ /**
367
+ * The static enabled state, if provided as a direct boolean value.
368
+ */
369
+ enabledDirectValue: boolean | null;
370
+ /**
371
+ * The final enabled state, derived from either the reactive or static value.
372
+ */
373
+ resolvedEnabled: boolean;
374
+ };
375
+ /**
376
+ * The keys that make up the internal state of the store.
377
+ */
378
+ export type InternalStateKeys = keyof QueryStoreState<unknown, Record<string, unknown>>;
379
+ /**
380
+ * Helper type for defining `onFetched` parameters.
381
+ */
382
+ export type OnFetchedParams<TData, TParams extends Record<string, unknown> = Record<string, never>, CustomState = unknown, S extends QueryStoreState<TData, TParams, CustomState> = QueryStoreState<TData, TParams, CustomState>> = {
383
+ data: TData;
384
+ fetch: (params?: TParams | Partial<TParams>, options?: FetchOptions) => Promise<TData | null>;
385
+ params: TParams;
386
+ set: (update: SetPartial<S>) => void;
387
+ };
388
+ /**
389
+ * Helper type for defining `setData` parameters.
390
+ */
391
+ export type SetDataParams<TData, TParams extends Record<string, unknown> = Record<string, never>, CustomState = unknown, S extends QueryStoreState<TData, TParams, CustomState> = QueryStoreState<TData, TParams, CustomState>> = {
392
+ data: TData;
393
+ params: TParams;
394
+ queryKey: string;
395
+ set: (update: SetPartial<S>) => void;
396
+ };
@@ -0,0 +1,19 @@
1
+ import { BaseStore, UnsubscribeFn } from './types';
2
+ export declare const attachValueSubscriptionMap: WeakMap<AttachValue<unknown>, Subscribe>;
3
+ type NestedAttachValue<T> = T extends object ? {
4
+ readonly [K in keyof T]: AttachValue<T[K]>;
5
+ } : Record<string, never>;
6
+ export type AttachValue<T> = {
7
+ readonly value: T;
8
+ } & NestedAttachValue<T>;
9
+ export type SignalFunction = {
10
+ <T>(store: BaseStore<T>): AttachValue<T>;
11
+ <T, S>(store: BaseStore<T>, selector: (state: T) => S, equalityFn?: (a: S, b: S) => boolean): AttachValue<S>;
12
+ };
13
+ export type Subscribe = (callback: () => void) => UnsubscribeFn;
14
+ export type GetValue = () => unknown;
15
+ export type SetValue = (path: unknown[], value: unknown) => void;
16
+ export declare function $<T>(store: BaseStore<T>): AttachValue<T>;
17
+ export declare function $<T, S>(store: BaseStore<T>, selector: (state: T) => S, equalityFn?: (a: S, b: S) => boolean): AttachValue<S>;
18
+ export declare const createSignal: <T, S>(store: BaseStore<T>, selector: (state: T) => S, equalityFn: (a: S, b: S) => boolean) => [Subscribe, GetValue, SetValue];
19
+ export {};
@@ -0,0 +1,21 @@
1
+ import { AsyncStorageInterface, BaseStoreOptions, EnforceStorageKey, SyncStorageInterface } from 'src/types';
2
+ import { PersistStorage } from 'zustand/middleware';
3
+ import { StorageValue } from './storageTypes';
4
+ import { SyncContext } from '../sync/syncEnhancer';
5
+ type SyncPersistStorage<S> = {
6
+ getItem: (name: string) => StorageValue<S> | null;
7
+ removeItem: (name: string) => void;
8
+ setItem: (name: string, value: StorageValue<S>) => void;
9
+ };
10
+ /**
11
+ * Creates a persist storage object for the base store.
12
+ */
13
+ export declare function createPersistStorage<S, PersistedState extends Partial<S>, PersistReturn>(options: EnforceStorageKey<BaseStoreOptions<S, PersistedState, PersistReturn>>, storage: AsyncStorageInterface | SyncStorageInterface | undefined, syncContext: SyncContext | undefined): {
14
+ persistStorage: SyncPersistStorage<PersistedState> | PersistStorage<PersistedState, Promise<void>>;
15
+ version: number;
16
+ };
17
+ /**
18
+ * Creates an asynchronous persist storage adapter for Zustand.
19
+ */
20
+ export declare function createAsyncPersistStorage<S, PersistedState extends Partial<S>, PersistReturn>(storage: AsyncStorageInterface, options: EnforceStorageKey<BaseStoreOptions<S, PersistedState, PersistReturn>>, persistThrottleMs: number | undefined, syncContext?: SyncContext): PersistStorage<PersistedState, Promise<void>>;
21
+ export {};
@@ -0,0 +1,12 @@
1
+ export type StorageValue<S, HideSyncMetadata extends boolean = false> = HideSyncMetadata extends true ? {
2
+ state: S;
3
+ version?: number;
4
+ } : {
5
+ state: S;
6
+ syncMetadata?: {
7
+ origin?: string;
8
+ timestamp?: number;
9
+ fields?: Record<string, number>;
10
+ };
11
+ version?: number;
12
+ };
@@ -0,0 +1,2 @@
1
+ import { SyncStorageInterface } from './types';
2
+ export declare const storesStorage: SyncStorageInterface;
@@ -0,0 +1,2 @@
1
+ import { SyncStorageInterface } from './types';
2
+ export declare const storesStorage: SyncStorageInterface<string>;
@@ -0,0 +1,2 @@
1
+ import { SyncStorageInterface } from './types';
2
+ export declare const storesStorage: SyncStorageInterface;
@@ -0,0 +1,2 @@
1
+ import { SyncEngine } from './types';
2
+ export declare function createBrowserSyncEngine(): SyncEngine;
@@ -0,0 +1,137 @@
1
+ import { SyncTransport } from './transport';
2
+ import { SyncAuthenticator, SyncEngine, SyncHandle, SyncPresenceChannel, SyncPresenceRegistration, SyncRegistration } from './types';
3
+ /**
4
+ * Defines how offline edits are resolved when reconnecting after being offline.
5
+ *
6
+ * ### `Chronological`
7
+ * Offline edits are applied using last-write-wins based on their original creation
8
+ * timestamp. If a field was modified online while the client was offline with a later
9
+ * timestamp, the online edit wins. This mode preserves chronological ordering of edits
10
+ * regardless of connectivity.
11
+ *
12
+ * ### `DiscardOnConflict`
13
+ * Offline edits are discarded entirely for any field that was modified while offline,
14
+ * regardless of timestamps. This ensures online edits always take priority over offline
15
+ * edits for the same field. Useful for shared resources where online state should be
16
+ * authoritative (e.g., collaborative canvases).
17
+ */
18
+ export declare enum OfflineResolutionMode {
19
+ Chronological = "chronological",
20
+ DiscardOnConflict = "discard-on-conflict"
21
+ }
22
+ export type NetworkSyncEngineOptions = {
23
+ /**
24
+ * Defines how offline edits are resolved when reconnecting.
25
+ * @default OfflineResolutionMode.Chronological
26
+ */
27
+ offlineResolution?: OfflineResolutionMode;
28
+ /**
29
+ * Maximum number of updates to queue while offline.
30
+ * When exceeded, oldest updates are discarded.
31
+ * @default 100
32
+ */
33
+ offlineQueueLimit?: number;
34
+ /**
35
+ * Transport layer implementation for network communication.
36
+ */
37
+ transport: SyncTransport;
38
+ /**
39
+ * Optional authenticator used to provide connection metadata.
40
+ */
41
+ authenticator?: SyncAuthenticator;
42
+ /**
43
+ * When true, logs delta workload metrics for development profiling.
44
+ * @default false
45
+ */
46
+ instrumentDeltaWorkload?: boolean;
47
+ /**
48
+ * @deprecated Use `instrumentDeltaWorkload` instead.
49
+ */
50
+ instrumentDeltaStrategies?: boolean;
51
+ };
52
+ /**
53
+ * ### `NetworkSyncEngine`
54
+ *
55
+ * Sync engine that uses a pluggable transport layer for network-based
56
+ * state synchronization. Supports offline queuing, automatic reconnection,
57
+ * and presence coordination.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const transport = new WebSocketTransport('ws://localhost:3000');
62
+ * const engine = new NetworkSyncEngine({ transport });
63
+ *
64
+ * const store = createBaseStore(
65
+ * (set) => ({ count: 0, increment: () => set(s => ({ count: s.count + 1 })) }),
66
+ * {
67
+ * sync: {
68
+ * engine,
69
+ * fields: ['count'],
70
+ * key: 'counter-store',
71
+ * },
72
+ * }
73
+ * );
74
+ * ```
75
+ */
76
+ export declare class NetworkSyncEngine implements SyncEngine {
77
+ private readonly listeners;
78
+ private readonly offlineQueue;
79
+ private readonly offlineQueueLimit;
80
+ private readonly offlineResolution;
81
+ private readonly presenceChannels;
82
+ private readonly registrations;
83
+ private readonly serverFieldWrites;
84
+ private readonly transport;
85
+ private readonly deltaConfigs;
86
+ private readonly fieldSnapshots;
87
+ private readonly authenticator;
88
+ private readonly deltaInstrumentationEnabled;
89
+ private connectPromise;
90
+ private authPromise;
91
+ private readonly discardConflicts;
92
+ private bootstrappedStores;
93
+ private isConnected;
94
+ private needsBootstrap;
95
+ private offlineSnapshot;
96
+ constructor(options: NetworkSyncEngineOptions);
97
+ get sessionId(): string;
98
+ register<T extends Record<string, unknown>>(registration: SyncRegistration<T>): SyncHandle<T>;
99
+ registerPresence<T>(registration: SyncPresenceRegistration<T>): SyncPresenceChannel<T>;
100
+ private initializeTransport;
101
+ private resolveAuthPayload;
102
+ private fetchAuthPayload;
103
+ private handleAuthChallenge;
104
+ private handleAuthError;
105
+ private handleTransportConnected;
106
+ private handleTransportDisconnected;
107
+ private refreshTransportAuth;
108
+ private notifyAuthFailure;
109
+ private dispatchMessage;
110
+ private initializeDeltaSnapshots;
111
+ private prepareOutboundUpdate;
112
+ private cloneCanonicalUpdate;
113
+ private cloneSyncValues;
114
+ private shouldUseRecordDelta;
115
+ private normalizeDeltaDescriptor;
116
+ private getRecordSnapshot;
117
+ private saveRecordSnapshot;
118
+ private deleteRecordSnapshot;
119
+ private ensureSnapshotStore;
120
+ private applyReplaceSnapshotCleanup;
121
+ private decodeInboundUpdate;
122
+ private alignOutboundWithCanonical;
123
+ private removeListener;
124
+ private queueUpdate;
125
+ private captureOfflineSnapshot;
126
+ private filterConflictingFields;
127
+ private filterDiscardConflicts;
128
+ private flushOfflineQueue;
129
+ private getMaxOfflineTimestamp;
130
+ private trackDiscardConflictsFromBootstrap;
131
+ private enforceDiscardConflicts;
132
+ private isRemoteWriteNewer;
133
+ private recordServerFieldWrites;
134
+ private rejoinPresenceChannels;
135
+ private pausePresenceChannels;
136
+ private dispatchToListeners;
137
+ }
@@ -0,0 +1,2 @@
1
+ import { SyncEngine } from './types';
2
+ export declare function createNoopSyncEngine(): SyncEngine;
@@ -0,0 +1,21 @@
1
+ import { StateCreator } from '../types';
2
+ import { NormalizedSyncConfig } from './types';
3
+ export type SyncContext = {
4
+ isAsync: boolean;
5
+ clearFieldTimestamps: (snapshot: Record<string, number> | undefined) => void;
6
+ getFieldTimestampSnapshot: () => Record<string, number> | undefined;
7
+ getIsApplyingRemote: () => boolean;
8
+ getSessionId: () => string | undefined;
9
+ getTimestamp: () => number | undefined;
10
+ mergeFieldTimestamps: (fields: Record<string, number>) => void;
11
+ onHydrationComplete: (() => void) | undefined;
12
+ onHydrationFlushEnd: (() => void) | undefined;
13
+ setIsApplyingRemote: (value: boolean) => void;
14
+ setSessionId: (sessionId: string) => void;
15
+ setTimestamp: (timestamp: number) => void;
16
+ setWithoutPersist: (<_T extends (..._: unknown[]) => void | Promise<void>, Args extends unknown[]>(..._: Args) => void | Promise<void>) | undefined;
17
+ };
18
+ export declare function createSyncedStateCreator<T extends Record<string, unknown>>(stateCreator: StateCreator<T>, config: NormalizedSyncConfig<T>, isAsync: boolean): {
19
+ stateCreator: StateCreator<T>;
20
+ syncContext: SyncContext;
21
+ };
@@ -0,0 +1,5 @@
1
+ import { FieldMetadata } from './types';
2
+ /**
3
+ * Helper to create `FieldMetadata` tuples.
4
+ */
5
+ export declare function createFieldMetadata(timestamp: number, sessionId: string): FieldMetadata;