@marianmeres/fetch-store 3.1.0 → 3.1.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/README.md CHANGED
@@ -99,10 +99,12 @@ const feed = createFetchStreamStore<Message>((emit, url: string) => {
99
99
  const es = new EventSource(url);
100
100
  es.onmessage = (e) => emit("data", JSON.parse(e.data));
101
101
  es.onerror = (e) => emit("error", e);
102
- return () => { es.close(); emit("end"); };
102
+ return () => es.close();
103
103
  });
104
104
 
105
105
  const stop = feed.fetchStream(["/api/events"]);
106
+ // ...later: closes the connection, sets isFetching: false
107
+ stop();
106
108
  ```
107
109
 
108
110
  ## Features
@@ -19,11 +19,11 @@ import type { FetchStreamEventName, FetchStreamStore, FetchStreamStoreOptions }
19
19
  * const eventSource = new EventSource(url);
20
20
  * eventSource.onmessage = (e) => emit("data", JSON.parse(e.data));
21
21
  * eventSource.onerror = (e) => emit("error", e);
22
- * return () => { eventSource.close(); emit("end"); };
22
+ * return () => eventSource.close();
23
23
  * });
24
24
  *
25
25
  * const stop = sseStore.fetchStream(["/api/events"]);
26
- * // Later: stop() to close the connection
26
+ * // Later: stop() closes the connection and the run (isFetching: false, lastFetchEnd)
27
27
  * ```
28
28
  */
29
29
  export declare const createFetchStreamStore: <T, A extends unknown[] = unknown[]>(fetchStreamWorker: (emit: (eventName: FetchStreamEventName, eventData?: T | Error) => void, ...args: A) => (() => void) | void, initial?: T | null, options?: Partial<FetchStreamStoreOptions<T>>) => FetchStreamStore<T, A>;
@@ -19,11 +19,11 @@ const DEFAULT_OPTIONS = {};
19
19
  * const eventSource = new EventSource(url);
20
20
  * eventSource.onmessage = (e) => emit("data", JSON.parse(e.data));
21
21
  * eventSource.onerror = (e) => emit("error", e);
22
- * return () => { eventSource.close(); emit("end"); };
22
+ * return () => eventSource.close();
23
23
  * });
24
24
  *
25
25
  * const stop = sseStore.fetchStream(["/api/events"]);
26
- * // Later: stop() to close the connection
26
+ * // Later: stop() closes the connection and the run (isFetching: false, lastFetchEnd)
27
27
  * ```
28
28
  */
29
29
  export const createFetchStreamStore = (fetchStreamWorker, initial = null, options = {}) => {
@@ -40,13 +40,17 @@ export const createFetchStreamStore = (fetchStreamWorker, initial = null, option
40
40
  const _dataStore = createStore(initial);
41
41
  const _metaStore = createStore(_createMetaObj());
42
42
  const { subscribe, get } = createDerivedStore([_dataStore, _metaStore], ([data, meta]) => ({ data, ...meta }));
43
- // Tracks the cancel fn of the currently running stream so reset() can stop it.
44
- let _currentCancel = null;
43
+ // Tracks the stop fn of the currently running stream so reset() and a new
44
+ // fetchStream() can stop it.
45
+ let _currentStop = null;
45
46
  const fetchStream = (fetchArgs = [], recursiveDelayMs = 0) => {
46
47
  let _timer;
47
48
  let _aborted = false;
48
49
  let _abortFn;
49
- const cancel = () => {
50
+ // `closeRun` is false when the caller is about to overwrite meta anyway
51
+ // (reset, or a new fetchStream superseding this one), so subscribers see no
52
+ // intermediate `isFetching: false` flicker.
53
+ const stop = (closeRun) => {
50
54
  if (_aborted)
51
55
  return;
52
56
  _aborted = true;
@@ -60,9 +64,18 @@ export const createFetchStreamStore = (fetchStreamWorker, initial = null, option
60
64
  // cleanup should not throw, but guard anyway
61
65
  }
62
66
  }
63
- if (_currentCancel === cancel)
64
- _currentCancel = null;
67
+ if (_currentStop === stop)
68
+ _currentStop = null;
69
+ // Every emit from here on is ignored (including an "end" from the cleanup
70
+ // above), so the store closes the run itself. Nothing to close when idle
71
+ // between recursive runs.
72
+ const meta = _metaStore.get();
73
+ if (closeRun && meta.isFetching) {
74
+ _metaStore.set({ ...meta, isFetching: false, lastFetchEnd: new Date() });
75
+ }
65
76
  };
77
+ // Public cancel fn takes no args (safe to pass directly as an event handler).
78
+ const cancel = () => stop(true);
66
79
  const normalizedArgs = (Array.isArray(fetchArgs) ? fetchArgs : [fetchArgs]);
67
80
  const runOnce = () => {
68
81
  if (_aborted)
@@ -131,19 +144,19 @@ export const createFetchStreamStore = (fetchStreamWorker, initial = null, option
131
144
  });
132
145
  }
133
146
  };
134
- // If a previous stream was still running, cancel it before starting a new one.
135
- if (_currentCancel)
136
- _currentCancel();
137
- _currentCancel = cancel;
147
+ // If a previous stream was still running, stop it before starting a new one.
148
+ if (_currentStop)
149
+ _currentStop(false);
150
+ _currentStop = stop;
138
151
  runOnce();
139
152
  return cancel;
140
153
  };
141
154
  const reset = () => {
142
155
  // Stop any running stream (calls the worker's cleanup function).
143
- if (_currentCancel) {
144
- const c = _currentCancel;
145
- _currentCancel = null;
146
- c();
156
+ if (_currentStop) {
157
+ const s = _currentStop;
158
+ _currentStop = null;
159
+ s(false);
147
160
  }
148
161
  _dataStore.set(initial);
149
162
  _metaStore.set(_createMetaObj());
package/dist/types.d.ts CHANGED
@@ -171,7 +171,8 @@ export interface FetchStreamStore<T, A extends unknown[] = unknown[]> extends St
171
171
  * Starts the stream and optionally restarts it after completion.
172
172
  * @param args - Arguments passed to the stream worker
173
173
  * @param recursiveDelayMs - Delay before restarting stream after "end" event (0 = no restart)
174
- * @returns Cancel function to stop the stream
174
+ * @returns Cancel function: calls the worker's cleanup, ignores any later emits,
175
+ * and closes the run (`isFetching: false`, `lastFetchEnd`) if it was still active.
175
176
  */
176
177
  fetchStream: (args?: A | unknown, recursiveDelayMs?: number | (() => number)) => () => void;
177
178
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/fetch-store",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "main": "dist/mod.js",
6
6
  "types": "dist/mod.d.ts",
@@ -14,7 +14,7 @@
14
14
  "url": "https://github.com/marianmeres/fetch-store/issues"
15
15
  },
16
16
  "dependencies": {
17
- "@marianmeres/pubsub": "^3.0.0",
18
- "@marianmeres/store": "^3.0.0"
17
+ "@marianmeres/pubsub": "^3.1.0",
18
+ "@marianmeres/store": "^3.0.1"
19
19
  }
20
20
  }