floppy-disk 3.7.3 → 3.9.0-beta.1
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/esm/index.d.mts +1 -1
- package/esm/react/create-mutation.d.mts +1 -1
- package/esm/react/create-query.d.mts +1 -1
- package/esm/react/create-store.d.mts +1 -1
- package/esm/react/create-stores.d.mts +1 -1
- package/esm/react/create-stream.d.mts +14 -56
- package/esm/react/use-store.d.mts +1 -1
- package/esm/react.mjs +6 -6
- package/index.d.ts +1 -1
- package/package.json +4 -1
- package/react/create-mutation.d.ts +1 -1
- package/react/create-query.d.ts +1 -1
- package/react/create-store.d.ts +1 -1
- package/react/create-stores.d.ts +1 -1
- package/react/create-stream.d.ts +14 -56
- package/react/use-store.d.ts +1 -1
- package/react.js +6 -6
package/esm/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "
|
|
1
|
+
export * from "floppy-disk/vanilla";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type InitStoreOptions, type StoreApi } from "
|
|
1
|
+
import { type InitStoreOptions, type StoreApi } from "floppy-disk/vanilla";
|
|
2
2
|
type GoodInputForHash = string | number | boolean | null | Date;
|
|
3
3
|
export type StoreKey = GoodInputForHash | {
|
|
4
4
|
[key: string | number]: StoreKey | StoreKey[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type InitStoreOptions, type SetStateInput } from "
|
|
1
|
+
import { type InitStoreOptions, type SetStateInput } from "floppy-disk/vanilla";
|
|
2
2
|
import type { StoreKey } from "./create-stores.mjs";
|
|
3
3
|
type StreamDataState<TData, TError> = {
|
|
4
4
|
state: "INITIAL";
|
|
@@ -230,65 +230,23 @@ export type StreamOptions<TConnection, TData, TError = Error> = InitStoreOptions
|
|
|
230
230
|
* @returns A function to retrieve or create a stream instance by variable
|
|
231
231
|
*
|
|
232
232
|
* @remarks
|
|
233
|
-
*
|
|
234
|
-
* -
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* ### 1. Connection lifecycle (managed automatically)
|
|
243
|
-
*
|
|
244
|
-
* - Connection is established when needed (e.g. first subscriber)
|
|
245
|
-
* - Connection may be disconnected based on triggers:
|
|
246
|
-
* - no subscribers
|
|
247
|
-
* - tab hidden
|
|
248
|
-
* - offline
|
|
249
|
-
* - Reconnection is controlled via `reconnectOn`
|
|
250
|
-
*
|
|
251
|
-
* ---
|
|
252
|
-
*
|
|
253
|
-
* ### 2. Data flow (push-based)
|
|
254
|
-
*
|
|
255
|
-
* The `connect` function receives an `emit` API:
|
|
256
|
-
*
|
|
257
|
-
* - `emit.connected()` → mark connection as established
|
|
258
|
-
* - `emit.data(fn)` → update data using reducer
|
|
259
|
-
* - `emit.error(err)` → report error
|
|
260
|
-
*
|
|
261
|
-
* Data updates are **incremental** and controlled by the stream source.
|
|
262
|
-
*
|
|
263
|
-
* ---
|
|
264
|
-
*
|
|
265
|
-
* ### 3. Store-per-variable
|
|
266
|
-
*
|
|
267
|
-
* - Each unique `variable` creates a separate stream instance
|
|
268
|
-
* - Variables are deterministically hashed for stable identity
|
|
269
|
-
* - Each instance manages its own:
|
|
270
|
-
* - connection
|
|
271
|
-
* - state
|
|
272
|
-
* - subscribers
|
|
273
|
-
*
|
|
274
|
-
* ---
|
|
275
|
-
*
|
|
276
|
-
* ### 4. React integration (Proxy-based)
|
|
277
|
-
*
|
|
278
|
-
* - The returned hook exposes the full state as a Proxy
|
|
279
|
-
* - Components automatically subscribe to accessed properties
|
|
280
|
-
* - No selector or memoization is required
|
|
233
|
+
* - Designed for **long-lived, push-based async sources**, such as: WebSocket, SSE, realtime databases
|
|
234
|
+
* - A stream consists of two independent concerns:
|
|
235
|
+
* 1. **Connection state** — lifecycle of the underlying connection
|
|
236
|
+
* 2. **Data state** — lifecycle of emitted data
|
|
237
|
+
* - Connection lifecycle:
|
|
238
|
+
* - Connection is established when needed (e.g. first subscriber)
|
|
239
|
+
* - Connection may be disconnected based on triggers: no subscribers, tab hidden, offline
|
|
240
|
+
* - Streams are **keyed by variable** (via deterministic hashing).
|
|
241
|
+
* - Each unique variable maps to its own stream instance.
|
|
281
242
|
*
|
|
282
243
|
* ---
|
|
283
244
|
*
|
|
284
245
|
* ## Execution model
|
|
285
246
|
*
|
|
286
|
-
* - Streams are **lazy**:
|
|
287
|
-
*
|
|
288
|
-
* - Streams are **
|
|
289
|
-
* - Multiple subscribers reuse the same connection
|
|
290
|
-
* - Streams are **stateful**:
|
|
291
|
-
* - Data persists across reconnects (unless reset or GC)
|
|
247
|
+
* - Streams are **lazy**: No connection until there is a subscriber
|
|
248
|
+
* - Streams are **shared**: Multiple subscribers reuse the same connection
|
|
249
|
+
* - Streams are **stateful**: Data persists across reconnects (unless reset or GC)
|
|
292
250
|
*
|
|
293
251
|
* ---
|
|
294
252
|
*
|
|
@@ -316,7 +274,7 @@ export type StreamOptions<TConnection, TData, TError = Error> = InitStoreOptions
|
|
|
316
274
|
* return <div>{state.data?.length}</div>;
|
|
317
275
|
* }
|
|
318
276
|
*/
|
|
319
|
-
export declare const
|
|
277
|
+
export declare const createStream: <TConnection, TData, TVariable extends StoreKey, TError = Error>(connect: (variable: TVariable, emit: {
|
|
320
278
|
connected: () => void;
|
|
321
279
|
data: (reducer: (data: TData | undefined) => TData) => void;
|
|
322
280
|
error: (error: TError) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type StoreApi } from "
|
|
1
|
+
import { type StoreApi } from "floppy-disk/vanilla";
|
|
2
2
|
type Path = Array<string | number | symbol>;
|
|
3
3
|
export declare const getValueByPath: (obj: any, path: Path) => any;
|
|
4
4
|
export declare const isPrefixPath: (candidatePrefix: Path, targetPath: Path) => boolean;
|
package/esm/react.mjs
CHANGED
|
@@ -52,7 +52,7 @@ const useStoreStateProxy = (storeState) => {
|
|
|
52
52
|
const NO_INITIAL_VALUE = {};
|
|
53
53
|
const useStoreStateWithInitializer = (store, initialState = NO_INITIAL_VALUE) => {
|
|
54
54
|
const initiatedAt = useRef(new WeakMap([[store, 0]]));
|
|
55
|
-
|
|
55
|
+
useEffect(() => {
|
|
56
56
|
if (initialState === NO_INITIAL_VALUE || initiatedAt.current.get(store)) return;
|
|
57
57
|
store.setState(initialState);
|
|
58
58
|
initiatedAt.current.set(store, Date.now());
|
|
@@ -65,7 +65,7 @@ const useStoreState = (store, options = {}) => {
|
|
|
65
65
|
const [state] = useStoreStateWithInitializer(store, options.initialState);
|
|
66
66
|
const [trackedState, usedPathsRef] = useStoreStateProxy(state);
|
|
67
67
|
const [, reRender] = useState({});
|
|
68
|
-
|
|
68
|
+
useEffect(() => {
|
|
69
69
|
return store.subscribe((nextState, prevState, changedKeys) => {
|
|
70
70
|
const paths = compressPaths(usedPathsRef.current);
|
|
71
71
|
for (const path of paths) {
|
|
@@ -445,7 +445,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
445
445
|
) : storeStateToBeUsed
|
|
446
446
|
);
|
|
447
447
|
const [, reRender] = useState({});
|
|
448
|
-
|
|
448
|
+
useEffect(() => {
|
|
449
449
|
return store.subscribe((nextState, prevState2, changedKeys) => {
|
|
450
450
|
if (prevState2.state === "INITIAL" && !prevState2.isPending && nextState.isPending && !nextState.isRetrying) {
|
|
451
451
|
return;
|
|
@@ -460,7 +460,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
460
460
|
}
|
|
461
461
|
});
|
|
462
462
|
}, [store]);
|
|
463
|
-
|
|
463
|
+
useEffect(() => {
|
|
464
464
|
if (revalidateOnMount !== false) {
|
|
465
465
|
if (!initialDataIsStale) {
|
|
466
466
|
const dataInitiatedAt = initialDataInitiatedAt.current.get(store);
|
|
@@ -769,7 +769,7 @@ const INITIAL_STATE = {
|
|
|
769
769
|
error: void 0,
|
|
770
770
|
errorUpdatedAt: void 0
|
|
771
771
|
};
|
|
772
|
-
const
|
|
772
|
+
const createStream = (connect, disconnect, options = {}) => {
|
|
773
773
|
const {
|
|
774
774
|
disconnectOn = () => 5e3,
|
|
775
775
|
// 5 seconds after any `DisconnectTrigger`
|
|
@@ -1002,4 +1002,4 @@ const offlineListeners = /* @__PURE__ */ new Set();
|
|
|
1002
1002
|
const onWindowOffline = () => [...offlineListeners].forEach((fn) => fn());
|
|
1003
1003
|
let listenersAdded = false;
|
|
1004
1004
|
|
|
1005
|
-
export { createMutation, createQuery, createStore, createStores,
|
|
1005
|
+
export { createMutation, createQuery, createStore, createStores, createStream, useIsomorphicLayoutEffect, useMutation, useStoreState };
|
package/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "
|
|
1
|
+
export * from "floppy-disk/vanilla";
|
package/package.json
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
"name": "floppy-disk",
|
|
3
3
|
"description": "Lightweight unified state management for sync and async data.",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.9.0-beta.1",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"tag": "beta"
|
|
8
|
+
},
|
|
6
9
|
"keywords": [
|
|
7
10
|
"utilities",
|
|
8
11
|
"store",
|
package/react/create-query.d.ts
CHANGED
package/react/create-store.d.ts
CHANGED
package/react/create-stores.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type InitStoreOptions, type StoreApi } from "
|
|
1
|
+
import { type InitStoreOptions, type StoreApi } from "floppy-disk/vanilla";
|
|
2
2
|
type GoodInputForHash = string | number | boolean | null | Date;
|
|
3
3
|
export type StoreKey = GoodInputForHash | {
|
|
4
4
|
[key: string | number]: StoreKey | StoreKey[];
|
package/react/create-stream.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type InitStoreOptions, type SetStateInput } from "
|
|
1
|
+
import { type InitStoreOptions, type SetStateInput } from "floppy-disk/vanilla";
|
|
2
2
|
import type { StoreKey } from "./create-stores.ts";
|
|
3
3
|
type StreamDataState<TData, TError> = {
|
|
4
4
|
state: "INITIAL";
|
|
@@ -230,65 +230,23 @@ export type StreamOptions<TConnection, TData, TError = Error> = InitStoreOptions
|
|
|
230
230
|
* @returns A function to retrieve or create a stream instance by variable
|
|
231
231
|
*
|
|
232
232
|
* @remarks
|
|
233
|
-
*
|
|
234
|
-
* -
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* ### 1. Connection lifecycle (managed automatically)
|
|
243
|
-
*
|
|
244
|
-
* - Connection is established when needed (e.g. first subscriber)
|
|
245
|
-
* - Connection may be disconnected based on triggers:
|
|
246
|
-
* - no subscribers
|
|
247
|
-
* - tab hidden
|
|
248
|
-
* - offline
|
|
249
|
-
* - Reconnection is controlled via `reconnectOn`
|
|
250
|
-
*
|
|
251
|
-
* ---
|
|
252
|
-
*
|
|
253
|
-
* ### 2. Data flow (push-based)
|
|
254
|
-
*
|
|
255
|
-
* The `connect` function receives an `emit` API:
|
|
256
|
-
*
|
|
257
|
-
* - `emit.connected()` → mark connection as established
|
|
258
|
-
* - `emit.data(fn)` → update data using reducer
|
|
259
|
-
* - `emit.error(err)` → report error
|
|
260
|
-
*
|
|
261
|
-
* Data updates are **incremental** and controlled by the stream source.
|
|
262
|
-
*
|
|
263
|
-
* ---
|
|
264
|
-
*
|
|
265
|
-
* ### 3. Store-per-variable
|
|
266
|
-
*
|
|
267
|
-
* - Each unique `variable` creates a separate stream instance
|
|
268
|
-
* - Variables are deterministically hashed for stable identity
|
|
269
|
-
* - Each instance manages its own:
|
|
270
|
-
* - connection
|
|
271
|
-
* - state
|
|
272
|
-
* - subscribers
|
|
273
|
-
*
|
|
274
|
-
* ---
|
|
275
|
-
*
|
|
276
|
-
* ### 4. React integration (Proxy-based)
|
|
277
|
-
*
|
|
278
|
-
* - The returned hook exposes the full state as a Proxy
|
|
279
|
-
* - Components automatically subscribe to accessed properties
|
|
280
|
-
* - No selector or memoization is required
|
|
233
|
+
* - Designed for **long-lived, push-based async sources**, such as: WebSocket, SSE, realtime databases
|
|
234
|
+
* - A stream consists of two independent concerns:
|
|
235
|
+
* 1. **Connection state** — lifecycle of the underlying connection
|
|
236
|
+
* 2. **Data state** — lifecycle of emitted data
|
|
237
|
+
* - Connection lifecycle:
|
|
238
|
+
* - Connection is established when needed (e.g. first subscriber)
|
|
239
|
+
* - Connection may be disconnected based on triggers: no subscribers, tab hidden, offline
|
|
240
|
+
* - Streams are **keyed by variable** (via deterministic hashing).
|
|
241
|
+
* - Each unique variable maps to its own stream instance.
|
|
281
242
|
*
|
|
282
243
|
* ---
|
|
283
244
|
*
|
|
284
245
|
* ## Execution model
|
|
285
246
|
*
|
|
286
|
-
* - Streams are **lazy**:
|
|
287
|
-
*
|
|
288
|
-
* - Streams are **
|
|
289
|
-
* - Multiple subscribers reuse the same connection
|
|
290
|
-
* - Streams are **stateful**:
|
|
291
|
-
* - Data persists across reconnects (unless reset or GC)
|
|
247
|
+
* - Streams are **lazy**: No connection until there is a subscriber
|
|
248
|
+
* - Streams are **shared**: Multiple subscribers reuse the same connection
|
|
249
|
+
* - Streams are **stateful**: Data persists across reconnects (unless reset or GC)
|
|
292
250
|
*
|
|
293
251
|
* ---
|
|
294
252
|
*
|
|
@@ -316,7 +274,7 @@ export type StreamOptions<TConnection, TData, TError = Error> = InitStoreOptions
|
|
|
316
274
|
* return <div>{state.data?.length}</div>;
|
|
317
275
|
* }
|
|
318
276
|
*/
|
|
319
|
-
export declare const
|
|
277
|
+
export declare const createStream: <TConnection, TData, TVariable extends StoreKey, TError = Error>(connect: (variable: TVariable, emit: {
|
|
320
278
|
connected: () => void;
|
|
321
279
|
data: (reducer: (data: TData | undefined) => TData) => void;
|
|
322
280
|
error: (error: TError) => void;
|
package/react/use-store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type StoreApi } from "
|
|
1
|
+
import { type StoreApi } from "floppy-disk/vanilla";
|
|
2
2
|
type Path = Array<string | number | symbol>;
|
|
3
3
|
export declare const getValueByPath: (obj: any, path: Path) => any;
|
|
4
4
|
export declare const isPrefixPath: (candidatePrefix: Path, targetPath: Path) => boolean;
|
package/react.js
CHANGED
|
@@ -54,7 +54,7 @@ const useStoreStateProxy = (storeState) => {
|
|
|
54
54
|
const NO_INITIAL_VALUE = {};
|
|
55
55
|
const useStoreStateWithInitializer = (store, initialState = NO_INITIAL_VALUE) => {
|
|
56
56
|
const initiatedAt = react.useRef(new WeakMap([[store, 0]]));
|
|
57
|
-
|
|
57
|
+
react.useEffect(() => {
|
|
58
58
|
if (initialState === NO_INITIAL_VALUE || initiatedAt.current.get(store)) return;
|
|
59
59
|
store.setState(initialState);
|
|
60
60
|
initiatedAt.current.set(store, Date.now());
|
|
@@ -67,7 +67,7 @@ const useStoreState = (store, options = {}) => {
|
|
|
67
67
|
const [state] = useStoreStateWithInitializer(store, options.initialState);
|
|
68
68
|
const [trackedState, usedPathsRef] = useStoreStateProxy(state);
|
|
69
69
|
const [, reRender] = react.useState({});
|
|
70
|
-
|
|
70
|
+
react.useEffect(() => {
|
|
71
71
|
return store.subscribe((nextState, prevState, changedKeys) => {
|
|
72
72
|
const paths = compressPaths(usedPathsRef.current);
|
|
73
73
|
for (const path of paths) {
|
|
@@ -447,7 +447,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
447
447
|
) : storeStateToBeUsed
|
|
448
448
|
);
|
|
449
449
|
const [, reRender] = react.useState({});
|
|
450
|
-
|
|
450
|
+
react.useEffect(() => {
|
|
451
451
|
return store.subscribe((nextState, prevState2, changedKeys) => {
|
|
452
452
|
if (prevState2.state === "INITIAL" && !prevState2.isPending && nextState.isPending && !nextState.isRetrying) {
|
|
453
453
|
return;
|
|
@@ -462,7 +462,7 @@ const createQuery = (queryFn, options = {}) => {
|
|
|
462
462
|
}
|
|
463
463
|
});
|
|
464
464
|
}, [store]);
|
|
465
|
-
|
|
465
|
+
react.useEffect(() => {
|
|
466
466
|
if (revalidateOnMount !== false) {
|
|
467
467
|
if (!initialDataIsStale) {
|
|
468
468
|
const dataInitiatedAt = initialDataInitiatedAt.current.get(store);
|
|
@@ -771,7 +771,7 @@ const INITIAL_STATE = {
|
|
|
771
771
|
error: void 0,
|
|
772
772
|
errorUpdatedAt: void 0
|
|
773
773
|
};
|
|
774
|
-
const
|
|
774
|
+
const createStream = (connect, disconnect, options = {}) => {
|
|
775
775
|
const {
|
|
776
776
|
disconnectOn = () => 5e3,
|
|
777
777
|
// 5 seconds after any `DisconnectTrigger`
|
|
@@ -1008,7 +1008,7 @@ exports.createMutation = createMutation;
|
|
|
1008
1008
|
exports.createQuery = createQuery;
|
|
1009
1009
|
exports.createStore = createStore;
|
|
1010
1010
|
exports.createStores = createStores;
|
|
1011
|
-
exports.
|
|
1011
|
+
exports.createStream = createStream;
|
|
1012
1012
|
exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
|
|
1013
1013
|
exports.useMutation = useMutation;
|
|
1014
1014
|
exports.useStoreState = useStoreState;
|