@forgecart/sdk 1.202607281310.0 → 1.202608041455.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/dist/client.generated.js +19 -2
- package/package.json +1 -1
- package/src/client.generated.ts +19 -2
package/dist/client.generated.js
CHANGED
|
@@ -230,6 +230,16 @@ class BaseGraphQLClient {
|
|
|
230
230
|
return new QueryObservable((subscriber) => {
|
|
231
231
|
const client = this.getWsClient();
|
|
232
232
|
let disposed = false;
|
|
233
|
+
// Delivery latch: once ANY sink callback has fired, the wire has
|
|
234
|
+
// spoken and a socket close can no longer mean "delivery unknown".
|
|
235
|
+
// Without it, a close event dispatched inside the delivery window
|
|
236
|
+
// (observed: between the error-result notify and the subscriber
|
|
237
|
+
// settling — CD runs 30845909288/30852033370/30855605921, where the
|
|
238
|
+
// server's NOT_VERIFIED answer was on the wire yet the consumer
|
|
239
|
+
// received WS_MUTATION_DELIVERY_INTERRUPTED, 3/3 deterministic)
|
|
240
|
+
// retro-fails an ALREADY-ANSWERED mutation. `settled` flips before
|
|
241
|
+
// any handler logic so every interleave is covered.
|
|
242
|
+
let settled = false;
|
|
233
243
|
const offConnectionEvents = [];
|
|
234
244
|
const cleanup = client.subscribe({
|
|
235
245
|
query: document,
|
|
@@ -237,6 +247,7 @@ class BaseGraphQLClient {
|
|
|
237
247
|
extensions: this.getPerOperationExtensions(),
|
|
238
248
|
}, {
|
|
239
249
|
next: (result) => {
|
|
250
|
+
settled = true;
|
|
240
251
|
if (disposed)
|
|
241
252
|
return;
|
|
242
253
|
if (result.errors && result.errors.length > 0) {
|
|
@@ -247,8 +258,12 @@ class BaseGraphQLClient {
|
|
|
247
258
|
})),
|
|
248
259
|
};
|
|
249
260
|
const error = new ClientError(response, result.errors[0].message);
|
|
250
|
-
|
|
261
|
+
// Terminal delivery FIRST, side-channel notification after:
|
|
262
|
+
// the notify hook runs arbitrary app code (toasts, logging,
|
|
263
|
+
// change detection), and anything it lets re-enter must find
|
|
264
|
+
// this operation already settled, never still interruptible.
|
|
251
265
|
subscriber.error(error);
|
|
266
|
+
this.notifyErrorHandler(error);
|
|
252
267
|
return;
|
|
253
268
|
}
|
|
254
269
|
if (result.data) {
|
|
@@ -257,11 +272,13 @@ class BaseGraphQLClient {
|
|
|
257
272
|
}
|
|
258
273
|
},
|
|
259
274
|
error: (err) => {
|
|
275
|
+
settled = true;
|
|
260
276
|
if (disposed)
|
|
261
277
|
return;
|
|
262
278
|
subscriber.error(this.toStreamError(err));
|
|
263
279
|
},
|
|
264
280
|
complete: () => {
|
|
281
|
+
settled = true;
|
|
265
282
|
if (disposed)
|
|
266
283
|
return;
|
|
267
284
|
subscriber.complete();
|
|
@@ -271,7 +288,7 @@ class BaseGraphQLClient {
|
|
|
271
288
|
let armed = WS_CONNECTION_STATE.get(client)?.connected ?? false;
|
|
272
289
|
offConnectionEvents.push(client.on("connected", () => { armed = true; }));
|
|
273
290
|
offConnectionEvents.push(client.on("closed", () => {
|
|
274
|
-
if (disposed || !armed)
|
|
291
|
+
if (disposed || settled || !armed)
|
|
275
292
|
return;
|
|
276
293
|
const message = "WS_MUTATION_DELIVERY_INTERRUPTED";
|
|
277
294
|
// subscriber.error tears the subscription down synchronously,
|
package/package.json
CHANGED
package/src/client.generated.ts
CHANGED
|
@@ -334,6 +334,16 @@ export class BaseGraphQLClient {
|
|
|
334
334
|
return new QueryObservable<T>((subscriber) => {
|
|
335
335
|
const client = this.getWsClient();
|
|
336
336
|
let disposed = false;
|
|
337
|
+
// Delivery latch: once ANY sink callback has fired, the wire has
|
|
338
|
+
// spoken and a socket close can no longer mean "delivery unknown".
|
|
339
|
+
// Without it, a close event dispatched inside the delivery window
|
|
340
|
+
// (observed: between the error-result notify and the subscriber
|
|
341
|
+
// settling — CD runs 30845909288/30852033370/30855605921, where the
|
|
342
|
+
// server's NOT_VERIFIED answer was on the wire yet the consumer
|
|
343
|
+
// received WS_MUTATION_DELIVERY_INTERRUPTED, 3/3 deterministic)
|
|
344
|
+
// retro-fails an ALREADY-ANSWERED mutation. `settled` flips before
|
|
345
|
+
// any handler logic so every interleave is covered.
|
|
346
|
+
let settled = false;
|
|
337
347
|
const offConnectionEvents: (() => void)[] = [];
|
|
338
348
|
|
|
339
349
|
const cleanup = client.subscribe<Record<string, unknown>>(
|
|
@@ -344,6 +354,7 @@ export class BaseGraphQLClient {
|
|
|
344
354
|
},
|
|
345
355
|
{
|
|
346
356
|
next: (result) => {
|
|
357
|
+
settled = true;
|
|
347
358
|
if (disposed) return;
|
|
348
359
|
if (result.errors && result.errors.length > 0) {
|
|
349
360
|
const response: GraphQLErrorResponse = {
|
|
@@ -353,8 +364,12 @@ export class BaseGraphQLClient {
|
|
|
353
364
|
})),
|
|
354
365
|
};
|
|
355
366
|
const error = new ClientError(response, result.errors[0].message);
|
|
356
|
-
|
|
367
|
+
// Terminal delivery FIRST, side-channel notification after:
|
|
368
|
+
// the notify hook runs arbitrary app code (toasts, logging,
|
|
369
|
+
// change detection), and anything it lets re-enter must find
|
|
370
|
+
// this operation already settled, never still interruptible.
|
|
357
371
|
subscriber.error(error);
|
|
372
|
+
this.notifyErrorHandler(error);
|
|
358
373
|
return;
|
|
359
374
|
}
|
|
360
375
|
if (result.data) {
|
|
@@ -363,10 +378,12 @@ export class BaseGraphQLClient {
|
|
|
363
378
|
}
|
|
364
379
|
},
|
|
365
380
|
error: (err) => {
|
|
381
|
+
settled = true;
|
|
366
382
|
if (disposed) return;
|
|
367
383
|
subscriber.error(this.toStreamError(err));
|
|
368
384
|
},
|
|
369
385
|
complete: () => {
|
|
386
|
+
settled = true;
|
|
370
387
|
if (disposed) return;
|
|
371
388
|
subscriber.complete();
|
|
372
389
|
},
|
|
@@ -377,7 +394,7 @@ export class BaseGraphQLClient {
|
|
|
377
394
|
let armed = WS_CONNECTION_STATE.get(client)?.connected ?? false;
|
|
378
395
|
offConnectionEvents.push(client.on("connected", () => { armed = true; }));
|
|
379
396
|
offConnectionEvents.push(client.on("closed", () => {
|
|
380
|
-
if (disposed || !armed) return;
|
|
397
|
+
if (disposed || settled || !armed) return;
|
|
381
398
|
const message = "WS_MUTATION_DELIVERY_INTERRUPTED";
|
|
382
399
|
// subscriber.error tears the subscription down synchronously,
|
|
383
400
|
// disposing the pending graphql-ws operation BEFORE its retry
|