@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.
- package/LICENSE +21 -0
- package/dist/config.d.ts +13 -0
- package/dist/createBaseStore.d.ts +35 -0
- package/dist/createDerivedStore.d.ts +70 -0
- package/dist/createQueryStore.d.ts +131 -0
- package/dist/createVirtualStore.d.ts +39 -0
- package/dist/derivedStore/deriveProxy.d.ts +24 -0
- package/dist/derivedStore/globalDeriveScheduler.d.ts +22 -0
- package/dist/env.d.ts +7 -0
- package/dist/env.native.d.ts +8 -0
- package/dist/env.web.d.ts +7 -0
- package/dist/hooks/compareHooks.d.ts +49 -0
- package/dist/hooks/useLazyRef.d.ts +12 -0
- package/dist/hooks/useListen.d.ts +97 -0
- package/dist/hooks/useStableValue.d.ts +15 -0
- package/dist/index.d.ts +16 -0
- package/dist/logger.d.ts +16 -0
- package/dist/middleware/createHydrationGate.d.ts +19 -0
- package/dist/middleware/createSubscriptionManager.d.ts +10 -0
- package/dist/native/index.js +1 -0
- package/dist/native/index.mjs +1 -0
- package/dist/plugins/chrome/chromeExtensionSyncEngine.d.ts +31 -0
- package/dist/plugins/chrome/chromeStorageAdapter.d.ts +32 -0
- package/dist/plugins/chrome/createSyncedChromeStorage.d.ts +16 -0
- package/dist/plugins/chrome/index.d.ts +3 -0
- package/dist/plugins/chrome/utils.d.ts +1 -0
- package/dist/plugins/delta/deltaInstrumentation.d.ts +42 -0
- package/dist/plugins/delta/index.d.ts +1 -0
- package/dist/plugins/delta/recordDelta.d.ts +14 -0
- package/dist/plugins/network/index.d.ts +2 -0
- package/dist/plugins/router/RouteErrorBoundary.d.ts +19 -0
- package/dist/plugins/router/__tests__/router-types.test.d.ts +0 -0
- package/dist/plugins/router/constants.d.ts +38 -0
- package/dist/plugins/router/createRouter-old-version.d.ts +183 -0
- package/dist/plugins/router/createRouter.d.ts +183 -0
- package/dist/plugins/router/errorBoundary.d.ts +23 -0
- package/dist/plugins/router/index.d.ts +6 -0
- package/dist/plugins/router/lazy.d.ts +14 -0
- package/dist/plugins/router/locationStore.d.ts +24 -0
- package/dist/plugins/router/pathMatching.d.ts +28 -0
- package/dist/plugins/router/scrollRestoration.d.ts +8 -0
- package/dist/plugins/router/searchParams.d.ts +53 -0
- package/dist/plugins/router/test-link-params.d.ts +1 -0
- package/dist/plugins/router/test-prefetch.d.ts +17 -0
- package/dist/plugins/router/test-types.d.ts +1 -0
- package/dist/plugins/router/types.d.ts +11 -0
- package/dist/plugins/router/utils.d.ts +14 -0
- package/dist/plugins/router/vite.d.ts +5 -0
- package/dist/presence/heartbeat.d.ts +23 -0
- package/dist/presence/presenceChannel.d.ts +19 -0
- package/dist/presence/pruning.d.ts +34 -0
- package/dist/queryStore/classes/SubscriptionManager.d.ts +66 -0
- package/dist/queryStore/createParamManager.d.ts +27 -0
- package/dist/queryStore/types.d.ts +396 -0
- package/dist/signal.d.ts +19 -0
- package/dist/storage/storageCreators.d.ts +21 -0
- package/dist/storage/storageTypes.d.ts +12 -0
- package/dist/storesStorage.d.ts +2 -0
- package/dist/storesStorage.native.d.ts +2 -0
- package/dist/storesStorage.web.d.ts +2 -0
- package/dist/sync/browserSyncEngine.d.ts +2 -0
- package/dist/sync/networkSyncEngine.d.ts +137 -0
- package/dist/sync/noopSyncEngine.d.ts +2 -0
- package/dist/sync/syncEnhancer.d.ts +21 -0
- package/dist/sync/syncUtils.d.ts +5 -0
- package/dist/sync/transport.d.ts +112 -0
- package/dist/sync/types.d.ts +189 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/functions.d.ts +6 -0
- package/dist/types/objects.d.ts +3 -0
- package/dist/types/utils.d.ts +8 -0
- package/dist/types.d.ts +332 -0
- package/dist/utils/core.d.ts +6 -0
- package/dist/utils/createAsyncMicrotaskScheduler.d.ts +34 -0
- package/dist/utils/createMicrotaskScheduler.d.ts +27 -0
- package/dist/utils/createStoreActions.d.ts +24 -0
- package/dist/utils/debounce.d.ts +21 -0
- package/dist/utils/equality.d.ts +37 -0
- package/dist/utils/factoryUtils.d.ts +21 -0
- package/dist/utils/hydrationCoordinator.d.ts +12 -0
- package/dist/utils/persistUtils.d.ts +8 -0
- package/dist/utils/promiseUtils.d.ts +1 -0
- package/dist/utils/serialization.d.ts +13 -0
- package/dist/utils/storeUtils.d.ts +56 -0
- package/dist/utils/stringUtils.d.ts +6 -0
- package/dist/utils/time.d.ts +46 -0
- package/dist/web/chrome.js +1 -0
- package/dist/web/chrome.mjs +1 -0
- package/dist/web/chunk-YWUZUTPH.mjs +1 -0
- package/dist/web/index.js +1 -0
- package/dist/web/index.mjs +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { SyncAuthPayload, SyncUpdate } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* ### `SyncTransportMessage`
|
|
4
|
+
*
|
|
5
|
+
* Message envelope for sync engine communication over a transport layer.
|
|
6
|
+
* Supports sync updates and presence coordination.
|
|
7
|
+
*/
|
|
8
|
+
export type SyncTransportMessage<T extends Record<string, unknown> = Record<string, unknown>> = PingMessage | {
|
|
9
|
+
type: 'sync-update';
|
|
10
|
+
storeKey: string;
|
|
11
|
+
update: SyncUpdate<T>;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'auth-challenge';
|
|
14
|
+
code: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'auth-error';
|
|
18
|
+
code: string;
|
|
19
|
+
message?: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'presence-join';
|
|
22
|
+
storeKey: string;
|
|
23
|
+
userId: string;
|
|
24
|
+
userData?: unknown;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'presence-leave';
|
|
27
|
+
storeKey: string;
|
|
28
|
+
userId: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'presence-update';
|
|
31
|
+
storeKey: string;
|
|
32
|
+
userId: string;
|
|
33
|
+
userData: unknown;
|
|
34
|
+
};
|
|
35
|
+
export type PingMessage = {
|
|
36
|
+
readonly type: 'ping';
|
|
37
|
+
} | {
|
|
38
|
+
readonly type: 'pong';
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* ### `SyncTransport`
|
|
42
|
+
*
|
|
43
|
+
* Abstract transport interface for network-based sync engines.
|
|
44
|
+
* Implementations can use WebSockets, SSE, HTTP long-polling, or any other
|
|
45
|
+
* bidirectional communication protocol.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const transport = new WebSocketTransport('ws://localhost:3000');
|
|
50
|
+
* await transport.connect();
|
|
51
|
+
*
|
|
52
|
+
* transport.onMessage(message => {
|
|
53
|
+
* if (message.type === 'sync-update') {
|
|
54
|
+
* // Handle update
|
|
55
|
+
* }
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* transport.send({
|
|
59
|
+
* type: 'sync-update',
|
|
60
|
+
* storeKey: 'my-store',
|
|
61
|
+
* update: { ... }
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export interface SyncTransport {
|
|
66
|
+
/**
|
|
67
|
+
* Establishes connection to the transport endpoint.
|
|
68
|
+
* @throws {Error} If connection fails
|
|
69
|
+
*/
|
|
70
|
+
connect(options?: SyncTransportConnectOptions): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Closes the transport connection and cleans up resources.
|
|
73
|
+
*/
|
|
74
|
+
disconnect(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Sends a message through the transport.
|
|
77
|
+
* Messages sent while disconnected may be queued or dropped depending on implementation.
|
|
78
|
+
*
|
|
79
|
+
* @param message - The message to send
|
|
80
|
+
*/
|
|
81
|
+
send(message: SyncTransportMessage): void;
|
|
82
|
+
/**
|
|
83
|
+
* Registers a handler for incoming messages.
|
|
84
|
+
* Only one handler can be registered at a time; subsequent calls replace the previous handler.
|
|
85
|
+
*
|
|
86
|
+
* @param handler - Function to call when messages arrive
|
|
87
|
+
*/
|
|
88
|
+
onMessage(handler: (message: SyncTransportMessage) => void): void;
|
|
89
|
+
/**
|
|
90
|
+
* Registers a handler for connection state changes.
|
|
91
|
+
*
|
|
92
|
+
* @param handler - Function to call when connection state changes
|
|
93
|
+
*/
|
|
94
|
+
onConnectionChange(handler: (connected: boolean) => void): void;
|
|
95
|
+
/**
|
|
96
|
+
* Updates the active authentication payload. Transports may choose to
|
|
97
|
+
* reconnect automatically or apply the metadata lazily on the next handshake.
|
|
98
|
+
*/
|
|
99
|
+
updateAuth?(auth: SyncAuthPayload | null): void;
|
|
100
|
+
/**
|
|
101
|
+
* Current connection status.
|
|
102
|
+
*/
|
|
103
|
+
readonly connected: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Unique identifier for this transport client.
|
|
106
|
+
* Used to filter self-updates in distributed sync.
|
|
107
|
+
*/
|
|
108
|
+
readonly clientId: string;
|
|
109
|
+
}
|
|
110
|
+
export type SyncTransportConnectOptions = {
|
|
111
|
+
readonly auth?: SyncAuthPayload | null;
|
|
112
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
type UnknownFunction = (...args: unknown[]) => unknown;
|
|
2
|
+
/**
|
|
3
|
+
* Metadata for a field's last write.
|
|
4
|
+
*/
|
|
5
|
+
export type FieldMetadata = readonly [timestamp: number, sessionId: string];
|
|
6
|
+
export type SyncStateKey<T extends Record<string, unknown>> = Extract<{
|
|
7
|
+
[K in keyof T]-?: T[K] extends UnknownFunction ? never : K;
|
|
8
|
+
}[keyof T], string>;
|
|
9
|
+
export type SyncValues<T extends Record<string, unknown>> = Partial<T> & {
|
|
10
|
+
[K in SyncStateKey<T>]?: T[K];
|
|
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
|
+
export type SyncUpdate<T extends Record<string, unknown>> = {
|
|
37
|
+
deltas?: SyncDeltaMap<T>;
|
|
38
|
+
replace: boolean;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
values: SyncValues<T>;
|
|
42
|
+
};
|
|
43
|
+
export type SyncRegistration<T extends Record<string, unknown>> = {
|
|
44
|
+
apply: (update: SyncUpdate<T>) => void;
|
|
45
|
+
fields: ReadonlyArray<SyncStateKey<T>>;
|
|
46
|
+
getState: () => T;
|
|
47
|
+
key: string;
|
|
48
|
+
delta?: SyncDeltaConfig<T>;
|
|
49
|
+
};
|
|
50
|
+
export interface SyncHandle<T extends Record<string, unknown>> {
|
|
51
|
+
destroy: () => void;
|
|
52
|
+
hydrated?: () => boolean;
|
|
53
|
+
onHydrated?: (callback: () => void) => void;
|
|
54
|
+
publish: ((update: SyncUpdate<T>) => void) | null;
|
|
55
|
+
}
|
|
56
|
+
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
|
+
/**
|
|
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`).
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
readonly injectStorageMetadata?: boolean;
|
|
67
|
+
readonly sessionId: string;
|
|
68
|
+
}
|
|
69
|
+
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
|
+
export type SyncConfig<T extends Record<string, unknown>> = {
|
|
144
|
+
engine?: SyncEngine;
|
|
145
|
+
fields?: ReadonlyArray<SyncStateKey<T>>;
|
|
146
|
+
/**
|
|
147
|
+
* The delta configuration for the sync engine.
|
|
148
|
+
*
|
|
149
|
+
* Only takes effect when used with delta-enabled engines like `NetworkSyncEngine`.
|
|
150
|
+
* @default undefined
|
|
151
|
+
*/
|
|
152
|
+
delta?: SyncDeltaConfig<T>;
|
|
153
|
+
/**
|
|
154
|
+
* When true, injects sync metadata (`{ origin, timestamp, fields }`) into the persisted
|
|
155
|
+
* storage payload. Only takes effect when used with a persisted store.
|
|
156
|
+
*
|
|
157
|
+
* Useful for sync engines that use storage events as their transport (e.g., `chrome.storage`).
|
|
158
|
+
*
|
|
159
|
+
* Can also be set on the `engine` object. This option takes precedence if both are provided.
|
|
160
|
+
* @default false
|
|
161
|
+
*/
|
|
162
|
+
injectStorageMetadata?: boolean;
|
|
163
|
+
key?: string;
|
|
164
|
+
merge?: {
|
|
165
|
+
[K in SyncStateKey<T>]?: SyncMergeFn<T[K], T>;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Internal type for `SyncConfig` with `key` always present.
|
|
170
|
+
*/
|
|
171
|
+
export type NormalizedSyncConfig<T extends Record<string, unknown>> = SyncConfig<T> & {
|
|
172
|
+
key: string;
|
|
173
|
+
};
|
|
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 {};
|