@forgecart/sdk 1.202610251643.0 → 1.202610251830.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.d.ts +19 -0
- package/dist/client.generated.js +51 -3
- package/package.json +1 -1
- package/src/client.generated.ts +71 -12
|
@@ -200,6 +200,25 @@ export declare class BaseGraphQLClient {
|
|
|
200
200
|
* error.
|
|
201
201
|
*/
|
|
202
202
|
private getFirstValueBudgetMs;
|
|
203
|
+
/**
|
|
204
|
+
* The longest graphql-ws waits before any re-dial (#3452): half the shorter
|
|
205
|
+
* of the handshake bound and a read's first-value deadline, so 5_000 ms at
|
|
206
|
+
* the defaults and 1_000 ms at a connectionTimeout of 2_000. A wait that
|
|
207
|
+
* starts with an operation therefore ends inside that operation's own
|
|
208
|
+
* bound, and the dial it leads to keeps the other half to be answered.
|
|
209
|
+
* A get*, not a find*: derived configuration, never a lookup.
|
|
210
|
+
*/
|
|
211
|
+
private getRetryWaitCeilingMs;
|
|
212
|
+
/**
|
|
213
|
+
* graphql-ws's retryWait (#3452): the library's own randomised exponential
|
|
214
|
+
* delay, never longer than getRetryWaitCeilingMs(). graphql-ws resets its
|
|
215
|
+
* retry count only on an ack, so uncapped the delay doubles past its ladder
|
|
216
|
+
* for as long as an outage lasts; capped, the next operation after the
|
|
217
|
+
* outage re-dials within seconds. The timer stays a plain, reffed
|
|
218
|
+
* setTimeout: it replaces graphql-ws's own one for one and changes only
|
|
219
|
+
* how long it runs.
|
|
220
|
+
*/
|
|
221
|
+
private waitBeforeRedial;
|
|
203
222
|
/**
|
|
204
223
|
* The name the document declares: `query ChannelPlugins` gives
|
|
205
224
|
* "ChannelPlugins". Every generated document is a named operation, so the
|
package/dist/client.generated.js
CHANGED
|
@@ -89,6 +89,18 @@ var WsTimeoutBudgetMs;
|
|
|
89
89
|
WsTimeoutBudgetMs[WsTimeoutBudgetMs["QUERY_FIRST_VALUE"] = 10000] = "QUERY_FIRST_VALUE";
|
|
90
90
|
WsTimeoutBudgetMs[WsTimeoutBudgetMs["MUTATION_FIRST_VALUE"] = 60000] = "MUTATION_FIRST_VALUE";
|
|
91
91
|
})(WsTimeoutBudgetMs || (WsTimeoutBudgetMs = {}));
|
|
92
|
+
/**
|
|
93
|
+
* graphql-ws's own randomised exponential backoff, which the library does
|
|
94
|
+
* not export: it waits BASE * 2 ** retries plus JITTER_MIN..JITTER_MAX of
|
|
95
|
+
* jitter before every re-dial. Restated so waitBeforeRedial can keep that
|
|
96
|
+
* delay and only cap it (#3452).
|
|
97
|
+
*/
|
|
98
|
+
var WsRetryBackoffMs;
|
|
99
|
+
(function (WsRetryBackoffMs) {
|
|
100
|
+
WsRetryBackoffMs[WsRetryBackoffMs["BASE"] = 1000] = "BASE";
|
|
101
|
+
WsRetryBackoffMs[WsRetryBackoffMs["JITTER_MIN"] = 300] = "JITTER_MIN";
|
|
102
|
+
WsRetryBackoffMs[WsRetryBackoffMs["JITTER_MAX"] = 3000] = "JITTER_MAX";
|
|
103
|
+
})(WsRetryBackoffMs || (WsRetryBackoffMs = {}));
|
|
92
104
|
/**
|
|
93
105
|
* The per-OPERATION first-value budgets (#2245). A kind default sizes the
|
|
94
106
|
* average operation of that kind; an operation that holds the socket for a
|
|
@@ -160,7 +172,8 @@ class BaseGraphQLClient {
|
|
|
160
172
|
// A healthy handshake is milliseconds, and graphql-ws waits ~1-4 s before
|
|
161
173
|
// its first re-dial — so 10 s still lets ONE transient non-101 refusal heal
|
|
162
174
|
// (the retry-safety in getWsClient) while cutting the SILENT window from the
|
|
163
|
-
//
|
|
175
|
+
// retry ladder (18.6-24 s at the default bounds, every wait capped by
|
|
176
|
+
// getRetryWaitCeilingMs, #3452) to a bounded, logged failure (#2102).
|
|
164
177
|
this.connectionTimeout = options?.connectionTimeout ?? 10_000;
|
|
165
178
|
this.tokenStorageKey = `forgecart:auth:${this.endpoint}:${this.baseHeaders["forgecart-token"] ?? ""}`;
|
|
166
179
|
if (this.persistSession) {
|
|
@@ -206,8 +219,17 @@ class BaseGraphQLClient {
|
|
|
206
219
|
// exponential backoff. A DISPOSED client answers false (#1994):
|
|
207
220
|
// graphql-ws consults its own disposed flag before asking, so a
|
|
208
221
|
// pending operation completes at dispose() instead of re-dialing
|
|
209
|
-
// a dead endpoint
|
|
222
|
+
// a dead endpoint through the rest of the ladder and erroring onto
|
|
223
|
+
// whoever runs then.
|
|
210
224
|
shouldRetry: () => !this.disposed,
|
|
225
|
+
// graphql-ws waits BEFORE it checks that an operation still holds
|
|
226
|
+
// the socket, and resets its count only on an ack: past the ladder
|
|
227
|
+
// every refused dial adds one, so its own waits double without end
|
|
228
|
+
// (32, 64, 128, 256 s) while every operation gives up at its bound
|
|
229
|
+
// first — after a long outage a quiet client never dialled again.
|
|
230
|
+
// The cap keeps every wait inside the bound of the operation that
|
|
231
|
+
// waits on it, so the shared socket heals on the next call (#3452).
|
|
232
|
+
retryWait: (retries) => this.waitBeforeRedial(retries),
|
|
211
233
|
});
|
|
212
234
|
const connectionState = { connected: false, disposed: false, pending: new Set() };
|
|
213
235
|
WS_CONNECTION_STATE.set(this.wsClient, connectionState);
|
|
@@ -539,7 +561,7 @@ class BaseGraphQLClient {
|
|
|
539
561
|
},
|
|
540
562
|
});
|
|
541
563
|
// Armed only while the socket is not ACK-live. An unanswered handshake
|
|
542
|
-
// otherwise rides the whole graphql-ws retry ladder (
|
|
564
|
+
// otherwise rides the whole graphql-ws retry ladder (18.6-24 s) with
|
|
543
565
|
// nothing logged anywhere — the shape a pathless endpoint produces, and
|
|
544
566
|
// a Suspense hole with no line to explain it. The shared socket is NOT
|
|
545
567
|
// disposed and shouldRetry is untouched: graphql-ws keeps healing for the
|
|
@@ -692,6 +714,32 @@ class BaseGraphQLClient {
|
|
|
692
714
|
return WsTimeoutBudgetMs.QUERY_FIRST_VALUE;
|
|
693
715
|
return WsTimeoutBudgetMs.MUTATION_FIRST_VALUE;
|
|
694
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* The longest graphql-ws waits before any re-dial (#3452): half the shorter
|
|
719
|
+
* of the handshake bound and a read's first-value deadline, so 5_000 ms at
|
|
720
|
+
* the defaults and 1_000 ms at a connectionTimeout of 2_000. A wait that
|
|
721
|
+
* starts with an operation therefore ends inside that operation's own
|
|
722
|
+
* bound, and the dial it leads to keeps the other half to be answered.
|
|
723
|
+
* A get*, not a find*: derived configuration, never a lookup.
|
|
724
|
+
*/
|
|
725
|
+
getRetryWaitCeilingMs() {
|
|
726
|
+
return Math.min(this.connectionTimeout, WsTimeoutBudgetMs.QUERY_FIRST_VALUE) / 2;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* graphql-ws's retryWait (#3452): the library's own randomised exponential
|
|
730
|
+
* delay, never longer than getRetryWaitCeilingMs(). graphql-ws resets its
|
|
731
|
+
* retry count only on an ack, so uncapped the delay doubles past its ladder
|
|
732
|
+
* for as long as an outage lasts; capped, the next operation after the
|
|
733
|
+
* outage re-dials within seconds. The timer stays a plain, reffed
|
|
734
|
+
* setTimeout: it replaces graphql-ws's own one for one and changes only
|
|
735
|
+
* how long it runs.
|
|
736
|
+
*/
|
|
737
|
+
async waitBeforeRedial(retries) {
|
|
738
|
+
const jitterMs = Math.floor(Math.random() * (WsRetryBackoffMs.JITTER_MAX - WsRetryBackoffMs.JITTER_MIN) + WsRetryBackoffMs.JITTER_MIN);
|
|
739
|
+
const backoffMs = WsRetryBackoffMs.BASE * 2 ** retries + jitterMs;
|
|
740
|
+
const waitMs = Math.min(backoffMs, this.getRetryWaitCeilingMs());
|
|
741
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
742
|
+
}
|
|
695
743
|
/**
|
|
696
744
|
* The name the document declares: `query ChannelPlugins` gives
|
|
697
745
|
* "ChannelPlugins". Every generated document is a named operation, so the
|
package/package.json
CHANGED
package/src/client.generated.ts
CHANGED
|
@@ -21,9 +21,12 @@ export interface ForgeCartAdminClientConfig {
|
|
|
21
21
|
// Upper bound (ms) on an UNANSWERED graphql-ws handshake, per operation.
|
|
22
22
|
// Defaults to 10_000. A healthy handshake is milliseconds and graphql-ws
|
|
23
23
|
// waits ~1-4 s before its first re-dial, so the default still lets one
|
|
24
|
-
// transient refusal heal while the caller stops waiting out the
|
|
25
|
-
// retry ladder in silence (#2102).
|
|
26
|
-
//
|
|
24
|
+
// transient refusal heal while the caller stops waiting out the 18.6-24 s
|
|
25
|
+
// retry ladder in silence (#2102). Half the shorter of this and a read's
|
|
26
|
+
// 10 s deadline caps every wait before a re-dial — 5 s at the default —
|
|
27
|
+
// so after an outage of any length the next operation re-dials within
|
|
28
|
+
// that cap (#3452). Never bounds a connected operation: a live
|
|
29
|
+
// subscription runs for as long as the server streams.
|
|
27
30
|
connectionTimeout?: number;
|
|
28
31
|
channelToken: string;
|
|
29
32
|
adminSecret?: string;
|
|
@@ -51,9 +54,12 @@ export interface ForgeCartShopClientConfig {
|
|
|
51
54
|
// Upper bound (ms) on an UNANSWERED graphql-ws handshake, per operation.
|
|
52
55
|
// Defaults to 10_000. A healthy handshake is milliseconds and graphql-ws
|
|
53
56
|
// waits ~1-4 s before its first re-dial, so the default still lets one
|
|
54
|
-
// transient refusal heal while the caller stops waiting out the
|
|
55
|
-
// retry ladder in silence (#2102).
|
|
56
|
-
//
|
|
57
|
+
// transient refusal heal while the caller stops waiting out the 18.6-24 s
|
|
58
|
+
// retry ladder in silence (#2102). Half the shorter of this and a read's
|
|
59
|
+
// 10 s deadline caps every wait before a re-dial — 5 s at the default —
|
|
60
|
+
// so after an outage of any length the next operation re-dials within
|
|
61
|
+
// that cap (#3452). Never bounds a connected operation: a live
|
|
62
|
+
// subscription runs for as long as the server streams.
|
|
57
63
|
connectionTimeout?: number;
|
|
58
64
|
channelToken: string;
|
|
59
65
|
uploadEndpoint?: string;
|
|
@@ -77,9 +83,12 @@ export interface ForgeCartClientConfig {
|
|
|
77
83
|
// Upper bound (ms) on an UNANSWERED graphql-ws handshake, per operation.
|
|
78
84
|
// Defaults to 10_000. A healthy handshake is milliseconds and graphql-ws
|
|
79
85
|
// waits ~1-4 s before its first re-dial, so the default still lets one
|
|
80
|
-
// transient refusal heal while the caller stops waiting out the
|
|
81
|
-
// retry ladder in silence (#2102).
|
|
82
|
-
//
|
|
86
|
+
// transient refusal heal while the caller stops waiting out the 18.6-24 s
|
|
87
|
+
// retry ladder in silence (#2102). Half the shorter of this and a read's
|
|
88
|
+
// 10 s deadline caps every wait before a re-dial — 5 s at the default —
|
|
89
|
+
// so after an outage of any length the next operation re-dials within
|
|
90
|
+
// that cap (#3452). Never bounds a connected operation: a live
|
|
91
|
+
// subscription runs for as long as the server streams.
|
|
83
92
|
connectionTimeout?: number;
|
|
84
93
|
channelToken: string;
|
|
85
94
|
adminSecret?: string;
|
|
@@ -214,6 +223,18 @@ enum WsTimeoutBudgetMs {
|
|
|
214
223
|
MUTATION_FIRST_VALUE = 60_000,
|
|
215
224
|
}
|
|
216
225
|
|
|
226
|
+
/**
|
|
227
|
+
* graphql-ws's own randomised exponential backoff, which the library does
|
|
228
|
+
* not export: it waits BASE * 2 ** retries plus JITTER_MIN..JITTER_MAX of
|
|
229
|
+
* jitter before every re-dial. Restated so waitBeforeRedial can keep that
|
|
230
|
+
* delay and only cap it (#3452).
|
|
231
|
+
*/
|
|
232
|
+
enum WsRetryBackoffMs {
|
|
233
|
+
BASE = 1_000,
|
|
234
|
+
JITTER_MIN = 300,
|
|
235
|
+
JITTER_MAX = 3_000,
|
|
236
|
+
}
|
|
237
|
+
|
|
217
238
|
/**
|
|
218
239
|
* The per-OPERATION first-value budgets (#2245). A kind default sizes the
|
|
219
240
|
* average operation of that kind; an operation that holds the socket for a
|
|
@@ -302,7 +323,8 @@ export class BaseGraphQLClient {
|
|
|
302
323
|
// A healthy handshake is milliseconds, and graphql-ws waits ~1-4 s before
|
|
303
324
|
// its first re-dial — so 10 s still lets ONE transient non-101 refusal heal
|
|
304
325
|
// (the retry-safety in getWsClient) while cutting the SILENT window from the
|
|
305
|
-
//
|
|
326
|
+
// retry ladder (18.6-24 s at the default bounds, every wait capped by
|
|
327
|
+
// getRetryWaitCeilingMs, #3452) to a bounded, logged failure (#2102).
|
|
306
328
|
this.connectionTimeout = options?.connectionTimeout ?? 10_000;
|
|
307
329
|
this.tokenStorageKey = `forgecart:auth:${this.endpoint}:${this.baseHeaders["forgecart-token"] ?? ""}`;
|
|
308
330
|
if (this.persistSession) {
|
|
@@ -349,8 +371,17 @@ export class BaseGraphQLClient {
|
|
|
349
371
|
// exponential backoff. A DISPOSED client answers false (#1994):
|
|
350
372
|
// graphql-ws consults its own disposed flag before asking, so a
|
|
351
373
|
// pending operation completes at dispose() instead of re-dialing
|
|
352
|
-
// a dead endpoint
|
|
374
|
+
// a dead endpoint through the rest of the ladder and erroring onto
|
|
375
|
+
// whoever runs then.
|
|
353
376
|
shouldRetry: () => !this.disposed,
|
|
377
|
+
// graphql-ws waits BEFORE it checks that an operation still holds
|
|
378
|
+
// the socket, and resets its count only on an ack: past the ladder
|
|
379
|
+
// every refused dial adds one, so its own waits double without end
|
|
380
|
+
// (32, 64, 128, 256 s) while every operation gives up at its bound
|
|
381
|
+
// first — after a long outage a quiet client never dialled again.
|
|
382
|
+
// The cap keeps every wait inside the bound of the operation that
|
|
383
|
+
// waits on it, so the shared socket heals on the next call (#3452).
|
|
384
|
+
retryWait: (retries) => this.waitBeforeRedial(retries),
|
|
354
385
|
});
|
|
355
386
|
const connectionState = { connected: false, disposed: false, pending: new Set<PendingOperation>() };
|
|
356
387
|
WS_CONNECTION_STATE.set(this.wsClient, connectionState);
|
|
@@ -700,7 +731,7 @@ export class BaseGraphQLClient {
|
|
|
700
731
|
);
|
|
701
732
|
|
|
702
733
|
// Armed only while the socket is not ACK-live. An unanswered handshake
|
|
703
|
-
// otherwise rides the whole graphql-ws retry ladder (
|
|
734
|
+
// otherwise rides the whole graphql-ws retry ladder (18.6-24 s) with
|
|
704
735
|
// nothing logged anywhere — the shape a pathless endpoint produces, and
|
|
705
736
|
// a Suspense hole with no line to explain it. The shared socket is NOT
|
|
706
737
|
// disposed and shouldRetry is untouched: graphql-ws keeps healing for the
|
|
@@ -851,6 +882,34 @@ export class BaseGraphQLClient {
|
|
|
851
882
|
return WsTimeoutBudgetMs.MUTATION_FIRST_VALUE;
|
|
852
883
|
}
|
|
853
884
|
|
|
885
|
+
/**
|
|
886
|
+
* The longest graphql-ws waits before any re-dial (#3452): half the shorter
|
|
887
|
+
* of the handshake bound and a read's first-value deadline, so 5_000 ms at
|
|
888
|
+
* the defaults and 1_000 ms at a connectionTimeout of 2_000. A wait that
|
|
889
|
+
* starts with an operation therefore ends inside that operation's own
|
|
890
|
+
* bound, and the dial it leads to keeps the other half to be answered.
|
|
891
|
+
* A get*, not a find*: derived configuration, never a lookup.
|
|
892
|
+
*/
|
|
893
|
+
private getRetryWaitCeilingMs(): number {
|
|
894
|
+
return Math.min(this.connectionTimeout, WsTimeoutBudgetMs.QUERY_FIRST_VALUE) / 2;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* graphql-ws's retryWait (#3452): the library's own randomised exponential
|
|
899
|
+
* delay, never longer than getRetryWaitCeilingMs(). graphql-ws resets its
|
|
900
|
+
* retry count only on an ack, so uncapped the delay doubles past its ladder
|
|
901
|
+
* for as long as an outage lasts; capped, the next operation after the
|
|
902
|
+
* outage re-dials within seconds. The timer stays a plain, reffed
|
|
903
|
+
* setTimeout: it replaces graphql-ws's own one for one and changes only
|
|
904
|
+
* how long it runs.
|
|
905
|
+
*/
|
|
906
|
+
private async waitBeforeRedial(retries: number): Promise<void> {
|
|
907
|
+
const jitterMs = Math.floor(Math.random() * (WsRetryBackoffMs.JITTER_MAX - WsRetryBackoffMs.JITTER_MIN) + WsRetryBackoffMs.JITTER_MIN);
|
|
908
|
+
const backoffMs = WsRetryBackoffMs.BASE * 2 ** retries + jitterMs;
|
|
909
|
+
const waitMs = Math.min(backoffMs, this.getRetryWaitCeilingMs());
|
|
910
|
+
await new Promise<void>((resolve) => setTimeout(resolve, waitMs));
|
|
911
|
+
}
|
|
912
|
+
|
|
854
913
|
/**
|
|
855
914
|
* The name the document declares: `query ChannelPlugins` gives
|
|
856
915
|
* "ChannelPlugins". Every generated document is a named operation, so the
|