@calimero-network/mero-js 25.3.2 → 25.3.3

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.
@@ -91,6 +91,14 @@ export declare class SseClient {
91
91
  onMigrationEvent(handler: (e: GroupMigrationEventData) => void): () => void;
92
92
  private emit;
93
93
  connect(): Promise<void>;
94
+ /**
95
+ * Whether `controller`'s connection is no longer the one this client holds:
96
+ * closed, or replaced by a later connect. Its abort lands asynchronously,
97
+ * after a `close()` + `connect()` has already cleared `closed`, so `closed`
98
+ * alone cannot tell; reporting it, and reconnecting for it, would abort the
99
+ * live connection, whose own abort would do the same, without end.
100
+ */
101
+ private superseded;
94
102
  private readStream;
95
103
  private handleMessage;
96
104
  subscribe(idsOrOpts: string[] | {
@@ -142,7 +142,8 @@ export class SseClient {
142
142
  return;
143
143
  }
144
144
  this.closed = false;
145
- this.abortController = new AbortController();
145
+ const controller = new AbortController();
146
+ this.abortController = controller;
146
147
  try {
147
148
  const url = `${this.baseUrl}/sse`;
148
149
  const headers = {
@@ -152,7 +153,7 @@ export class SseClient {
152
153
  const proofAttached = carriesProof(headers);
153
154
  const response = await this.fetchImpl(url, {
154
155
  headers,
155
- signal: this.abortController.signal,
156
+ signal: controller.signal,
156
157
  ...(proofAttached && { redirect: 'manual' }),
157
158
  });
158
159
  if (proofAttached)
@@ -174,8 +175,8 @@ export class SseClient {
174
175
  if (!response.body) {
175
176
  throw new Error('SSE response has no body');
176
177
  }
177
- this.readStream(response.body).catch((err) => {
178
- if (this.closed)
178
+ this.readStream(response.body, controller).catch((err) => {
179
+ if (this.superseded(controller))
179
180
  return;
180
181
  const error = err instanceof Error ? err : new Error(String(err));
181
182
  this.emit('error', error);
@@ -183,7 +184,7 @@ export class SseClient {
183
184
  });
184
185
  }
185
186
  catch (err) {
186
- if (this.closed)
187
+ if (this.superseded(controller))
187
188
  return;
188
189
  const error = err instanceof Error ? err : new Error(String(err));
189
190
  this.emit('error', error);
@@ -195,7 +196,17 @@ export class SseClient {
195
196
  this.scheduleReconnect();
196
197
  }
197
198
  }
198
- async readStream(body) {
199
+ /**
200
+ * Whether `controller`'s connection is no longer the one this client holds:
201
+ * closed, or replaced by a later connect. Its abort lands asynchronously,
202
+ * after a `close()` + `connect()` has already cleared `closed`, so `closed`
203
+ * alone cannot tell; reporting it, and reconnecting for it, would abort the
204
+ * live connection, whose own abort would do the same, without end.
205
+ */
206
+ superseded(controller) {
207
+ return this.closed || controller.signal.aborted || this.abortController !== controller;
208
+ }
209
+ async readStream(body, controller) {
199
210
  const reader = body.getReader();
200
211
  const decoder = new TextDecoder();
201
212
  let buffer = '';
@@ -227,13 +238,13 @@ export class SseClient {
227
238
  }
228
239
  }
229
240
  catch (err) {
230
- if (this.closed)
241
+ if (this.superseded(controller))
231
242
  return;
232
243
  const error = err instanceof Error ? err : new Error(String(err));
233
244
  this.emit('error', error);
234
245
  }
235
246
  // Stream ended, reconnect
236
- if (!this.closed) {
247
+ if (!this.superseded(controller)) {
237
248
  this.scheduleReconnect();
238
249
  }
239
250
  }