@burdenoff/fe-libs 2026.1010.1 → 2026.1010.2

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.
@@ -16,15 +16,15 @@ function c(e, t) {
16
16
  for (let e of i.matchAll(r)) a = e[0];
17
17
  return a ?? t;
18
18
  }
19
- var l = 60, u = /^(?:log ?out|sign ?out|(?:log|sign) (?:me )?out(?: of (?:the |my |this )?(?:app|application|account|session))?)$/, d = "(?:workspace|workspaces|context|contexts|organi[sz]ation|organi[sz]ations|org|project)", f = "(?:switcher|selector|picker|menu|dropdown|list)", p = /^(?:another|other|a different|different|a new|new|a|the|another one|other one)$/, m = RegExp(`^${i} ${r}(?:notification|notifications) (?:panel|bell|centre|center|menu|tray|drawer|list)$`), h = RegExp(`^${i} ${r}(?:notification )?bell$`), g = RegExp(`^${i} ${r}notifications?$`), _ = RegExp(`^${i} ${r}(?:help (?:menu|panel|dialog|dialogue|centre|center)|keyboard shortcuts|keyboard help|shortcuts)$`), v = RegExp(`^${i} ${r}help$`), y = RegExp(`^(?:open|show|start|use|pull up|bring up) ${r}(?:global |app )search(?: (?:bar|box|dialog|dialogue|panel))?$|^(?:open|show|start|use|pull up|bring up) ${r}search (?:bar|box|dialog|dialogue|panel)$`), b = /^(?:open|start|use|pull up|bring up) (?:(?:the|my) )?search$/, x = [
19
+ var l = 60, u = /^(?:log ?out|sign ?out|(?:log|sign) (?:me )?out(?: of (?:the |my |this )?(?:app|application|account|session))?)$/, d = "(?:workspace|workspaces|context|contexts|organi[sz]ation|organi[sz]ations|org|project)", f = "(?:switcher|selector|picker|menu|dropdown|list)", p = /^(?:another|other|a different|different|a new|new|a|the|another one|other one)$/, m = RegExp(`^${i} ${r}(?:notification|notifications) (?:panel|bell|centre|center|menu|tray|drawer|list)$`), h = RegExp(`^${i} ${r}(?:notification )?bell$`), ee = RegExp(`^${i} ${r}notifications?$`), g = RegExp(`^${i} ${r}(?:help (?:menu|panel|dialog|dialogue|centre|center)|keyboard shortcuts|keyboard help|shortcuts)$`), _ = RegExp(`^${i} ${r}help$`), v = RegExp(`^(?:open|show|start|use|pull up|bring up) ${r}(?:global |app )search(?: (?:bar|box|dialog|dialogue|panel))?$|^(?:open|show|start|use|pull up|bring up) ${r}search (?:bar|box|dialog|dialogue|panel)$`), y = /^(?:open|start|use|pull up|bring up) (?:(?:the|my) )?search$/, b = [
20
20
  /^(?:open|start|use|pull up|bring up) (?:(?:the|my) )?(?:global |app )?search (?:for|with) (.+)$/,
21
21
  /^(?:global search|search everything|search everywhere|search globally|search the app|search all|search across the app) (?:for )?(.+)$/,
22
22
  /^search (?:the app|everything|everywhere|globally|all|across the app) for (.+)$/
23
- ], S = "(?:side ?bar|side menu|side navigation|side nav|navigation (?:bar|menu|panel|drawer)|nav (?:bar|menu|panel|drawer)|left (?:menu|sidebar|panel))", C = RegExp(`^(?:collapse|close|hide|minimi[sz]e|shrink|fold) ${r}${S}$`), w = RegExp(`^(?:expand|open|show|reveal|unhide|bring up|widen|unfold) ${r}${S}$`), T = "(?: (?:group|section|menu|folder|submenu|sub menu|list|dropdown))?", E = RegExp(`^(expand|unfold|open up|open|show) ${r}(.+?)${T}$`), D = RegExp(`^(collapse|fold up|close|hide) ${r}(.+?)${T}$`), O = [
23
+ ], x = "(?:side ?bar|side menu|side navigation|side nav|navigation (?:bar|menu|panel|drawer)|nav (?:bar|menu|panel|drawer)|left (?:menu|sidebar|panel))", S = RegExp(`^(?:collapse|close|hide|minimi[sz]e|shrink|fold) ${r}${x}$`), C = RegExp(`^(?:expand|open|show|reveal|unhide|bring up|widen|unfold) ${r}${x}$`), w = "(?: (?:group|section|menu|folder|submenu|sub menu|list|dropdown))?", T = RegExp(`^(expand|unfold|open up|open|show) ${r}(.+?)${w}$`), E = RegExp(`^(collapse|fold up|close|hide) ${r}(.+?)${w}$`), D = [
24
24
  RegExp(`^(?:change|switch|set|update|turn|put|make)(?: over)? ${r}(?:(?:app|ui|user interface|interface|screen|display|site|system|menu|application) )?language (?:to|into|as|over to) (.+)$`),
25
25
  RegExp(`^(?:switch|change|set|put|turn) ${r}(?:app|ui|user interface|interface|screen|display|site|application|menus?) (?:language )?(?:to|into) (.+)$`),
26
26
  RegExp(`^(?:show|display|use|run) ${r}(?:app|ui|user interface|interface|screen|display|site|application)(?: menus?)? in (.+)$`)
27
- ], k = RegExp(`^${i} ${r}(?:(?:assistant|ai|conversation|conversations|chat) history|history of (?:my )?(?:conversations|chats)|(?:past|previous|old|earlier) conversations)$`), A = RegExp(`^${i} ${r}history$`), j = RegExp(`^${i} ${r}(?:voice|spoken|speech) transcript$`), M = RegExp(`^${i} ${r}transcript$`), ee = RegExp(`^${i} ${r}(?:ai|assistant) preview(?: panel| pane| surface)?$`), N = RegExp(`^${i} ${r}preview(?: panel| pane)?$`), P = RegExp(`^(?:close|hide|dismiss) ${r}(?:ai|assistant) preview(?: panel| pane| surface)?$`), F = RegExp(`^(?:close|hide) ${r}preview(?: panel| pane)?$`), I = /^(?:(?:start|begin|open) (?:a |an |another )?(?:new |fresh |blank )?conversation|new conversation|(?:start|begin) (?:a )?(?:new|fresh) conversation with you)$/, L = [RegExp(`^(?:go to|open|show|show me|switch to|select|view|change to|move to|take me to|bring up) ${r}(.+) tab$`), /^(?:switch|change|move) tabs? to (.+)$/], R = "(?:filter|narrow|limit)(?: down)?", z = [RegExp(`^${R}(?: ${r}(?:page|list|table|results|items|rows|view))? (?:by|to|for|on) ${r}(.+)$`)], B = [/^(?:show|display|list|keep) only (.+)$/, /^only (?:show|display|list|keep) (.+)$/], V = [
27
+ ], O = RegExp(`^(?:switch|change)(?: over)? to ${r}(.+)$`), k = RegExp(`^${i} ${r}(?:(?:assistant|ai|conversation|conversations|chat) history|history of (?:my )?(?:conversations|chats)|(?:past|previous|old|earlier) conversations)$`), A = RegExp(`^${i} ${r}history$`), j = RegExp(`^${i} ${r}(?:voice|spoken|speech) transcript$`), M = RegExp(`^${i} ${r}transcript$`), N = RegExp(`^${i} ${r}(?:ai|assistant) preview(?: panel| pane| surface)?$`), P = RegExp(`^${i} ${r}preview(?: panel| pane)?$`), F = RegExp(`^(?:close|hide|dismiss) ${r}(?:ai|assistant) preview(?: panel| pane| surface)?$`), te = RegExp(`^(?:close|hide) ${r}preview(?: panel| pane)?$`), I = /^(?:(?:start|begin|open) (?:a |an |another )?(?:new |fresh |blank )?conversation|new conversation|(?:start|begin) (?:a )?(?:new|fresh) conversation with you)$/, L = [RegExp(`^(?:go to|open|show|show me|switch to|select|view|change to|move to|take me to|bring up) ${r}(.+) tab$`), /^(?:switch|change|move) tabs? to (.+)$/], R = "(?:filter|narrow|limit)(?: down)?", z = [RegExp(`^${R}(?: ${r}(?:page|list|table|results|items|rows|view))? (?:by|to|for|on) ${r}(.+)$`)], B = [/^(?:show|display|list|keep) only (.+)$/, /^only (?:show|display|list|keep) (.+)$/], V = [
28
28
  RegExp(`^(?:set|change|switch|put|make) ${r}(.+?) filter (?:to|as|on) (.+)$`),
29
29
  RegExp(`^${R} ${r}(.+?) (?:by|to|for|on) (.+)$`),
30
30
  RegExp(`^(?:use|apply) ${r}(.+?) filter (?:of|with|for|set to) (.+)$`)
@@ -62,60 +62,60 @@ function $(e) {
62
62
  let t = e.replace(/\b(?:please|pls)$/, "").trim();
63
63
  return !t || t.length > l ? null : t;
64
64
  }
65
- function te(s, l, S) {
66
- let T = S.registered;
65
+ function ne(s, l, x) {
66
+ let w = x.registered;
67
67
  if (X.test(s)) return null;
68
- if (T["account.logout"] && u.test(s)) return a({ control: "account.logout" });
69
- if (T["header.workspace"] || T["header.context"]) {
68
+ if (w["account.logout"] && u.test(s)) return a({ control: "account.logout" });
69
+ if (w["header.workspace"] || w["header.context"]) {
70
70
  let e = RegExp(`^(?:switch|change|move|go|jump|hop)(?: over)? to ${r}(.+?) ${d}$`).exec(s) ?? RegExp(`^(?:switch|change|move) ${r}${d} (?:to|over to) ${r}(.+)$`).exec(s);
71
- if (e && T["header.workspace"]) {
71
+ if (e && w["header.workspace"]) {
72
72
  let t = (e[1] ?? "").trim();
73
73
  if (t && !p.test(t)) return a({
74
74
  control: "header.workspace",
75
75
  target: t
76
76
  });
77
- if (T["header.context"]) return a({ control: "header.context" });
77
+ if (w["header.context"]) return a({ control: "header.context" });
78
78
  }
79
- if (T["header.context"] && (RegExp(`^${i} ${r}${d} ${f}$`).test(s) || RegExp(`^(?:switch|change) ${r}${d}$`).test(s))) return a({ control: "header.context" });
79
+ if (w["header.context"] && (RegExp(`^${i} ${r}${d} ${f}$`).test(s) || RegExp(`^(?:switch|change) ${r}${d}$`).test(s))) return a({ control: "header.context" });
80
80
  }
81
- if (T["header.notifications"]) {
81
+ if (w["header.notifications"]) {
82
82
  if (m.test(s) || h.test(s)) return a({ control: "header.notifications" });
83
- if (g.test(s)) return o({ control: "header.notifications" });
83
+ if (ee.test(s)) return o({ control: "header.notifications" });
84
84
  }
85
- if (T["header.help"]) {
86
- if (_.test(s)) return a({ control: "header.help" });
87
- if (v.test(s)) return o({ control: "header.help" });
85
+ if (w["header.help"]) {
86
+ if (g.test(s)) return a({ control: "header.help" });
87
+ if (_.test(s)) return o({ control: "header.help" });
88
88
  }
89
- if (T["header.search"]) {
90
- for (let e of x) {
89
+ if (w["header.search"]) {
90
+ for (let e of b) {
91
91
  let t = e.exec(s), n = t ? $(t[1] ?? "") : null;
92
92
  if (n) return a({
93
93
  control: "header.search",
94
94
  query: c(l, n)
95
95
  });
96
96
  }
97
- if (y.test(s)) return a({
97
+ if (v.test(s)) return a({
98
98
  control: "header.search",
99
99
  query: null
100
100
  });
101
- if (b.test(s)) return o({
101
+ if (y.test(s)) return o({
102
102
  control: "header.search",
103
103
  query: null
104
104
  });
105
105
  }
106
- if (T.sidebar) {
107
- if (C.test(s)) return a({
106
+ if (w.sidebar) {
107
+ if (S.test(s)) return a({
108
108
  control: "sidebar",
109
109
  collapsed: !0
110
110
  });
111
- if (w.test(s)) return a({
111
+ if (C.test(s)) return a({
112
112
  control: "sidebar",
113
113
  collapsed: !1
114
114
  });
115
- let e = E.exec(s), t = e ? null : D.exec(s), r = e ?? t;
116
- if (r && S.sidebarEntries.length > 0) {
115
+ let e = T.exec(s), t = e ? null : E.exec(s), r = e ?? t;
116
+ if (r && x.sidebarEntries.length > 0) {
117
117
  let t = (r[2] ?? "").trim(), i = r[1] ?? "";
118
- if (t && n(t, S.sidebarEntries).kind !== "none") return {
118
+ if (t && n(t, x.sidebarEntries).kind !== "none") return {
119
119
  request: {
120
120
  control: "sidebar.entry",
121
121
  name: t,
@@ -125,31 +125,38 @@ function te(s, l, S) {
125
125
  };
126
126
  }
127
127
  }
128
- if (T.language) for (let e of O) {
129
- let n = e.exec(s);
130
- if (!n) continue;
131
- let r = t(n[1] ?? "");
132
- if (r) return a({
128
+ if (w.language) {
129
+ for (let e of D) {
130
+ let n = e.exec(s);
131
+ if (!n) continue;
132
+ let r = t(n[1] ?? "");
133
+ if (r) return a({
134
+ control: "language",
135
+ code: r
136
+ });
137
+ }
138
+ let e = O.exec(s), n = e ? t(e[1] ?? "") : null;
139
+ if (n) return o({
133
140
  control: "language",
134
- code: r
141
+ code: n
135
142
  });
136
143
  }
137
- if (T["assistant.history"]) {
144
+ if (w["assistant.history"]) {
138
145
  if (k.test(s)) return a({ control: "assistant.history" });
139
146
  if (A.test(s)) return o({ control: "assistant.history" });
140
147
  }
141
- if (T["assistant.transcript"]) {
148
+ if (w["assistant.transcript"]) {
142
149
  if (j.test(s)) return a({ control: "assistant.transcript" });
143
150
  if (M.test(s)) return o({ control: "assistant.transcript" });
144
151
  }
145
- if (T["assistant.preview"]) {
146
- if (ee.test(s)) return a({ control: "assistant.preview" });
147
- if (N.test(s)) return o({ control: "assistant.preview" });
148
- if (P.test(s)) return a({ control: "assistant.preview.close" });
149
- if (F.test(s)) return o({ control: "assistant.preview.close" });
152
+ if (w["assistant.preview"]) {
153
+ if (N.test(s)) return a({ control: "assistant.preview" });
154
+ if (P.test(s)) return o({ control: "assistant.preview" });
155
+ if (F.test(s)) return a({ control: "assistant.preview.close" });
156
+ if (te.test(s)) return o({ control: "assistant.preview.close" });
150
157
  }
151
- if (T["assistant.conversation.new"] && I.test(s)) return a({ control: "assistant.conversation.new" });
152
- let R = S.page;
158
+ if (w["assistant.conversation.new"] && I.test(s)) return a({ control: "assistant.conversation.new" });
159
+ let R = x.page;
153
160
  if (!R) return null;
154
161
  if (R.tabs.length > 0) {
155
162
  let e = Z(L, s), t = e ? (e[1] ?? "").trim() : "";
@@ -235,4 +242,4 @@ function te(s, l, S) {
235
242
  return null;
236
243
  }
237
244
  //#endregion
238
- export { te as matchAppControl, c as queryAsSaid };
245
+ export { ne as matchAppControl, c as queryAsSaid };
@@ -1,5 +1,25 @@
1
1
  import { ApolloClient, InMemoryCache } from '@apollo/client/core';
2
+ import { RetryLink } from '@apollo/client/link/retry';
2
3
  import { Gateway } from '../config';
4
+ import { RetryPolicyOperation } from './retryPolicy';
5
+ /**
6
+ * Decide whether the transport may retry a failed operation. Pure so it can be
7
+ * unit-tested without a client. Mutations are never retried (an ambiguous
8
+ * 504/timeout may have committed the write; a replay could duplicate it) unless
9
+ * the operation context sets `retryMutation: true`.
10
+ */
11
+ export declare function shouldRetryOperationError(error: Error | undefined | null, operation: RetryPolicyOperation | undefined, circuitOpen: boolean): boolean;
12
+ export interface CreateRetryLinkOptions {
13
+ maxAttempts: number;
14
+ /** Backoff override (tests); defaults to 1s..8s with jitter. */
15
+ delay?: {
16
+ initial: number;
17
+ max: number;
18
+ jitter: boolean;
19
+ };
20
+ }
21
+ /** Shared RetryLink: transient-failure retries for queries only (mutations opt in). */
22
+ export declare function createRetryLink({ maxAttempts, delay }: CreateRetryLinkOptions): RetryLink;
3
23
  /**
4
24
  * Check if the network circuit breaker is currently open (backend unreachable).
5
25
  * Useful for showing "backend offline" banners in the UI.
@@ -1,97 +1,116 @@
1
- import { GATEWAYS as e, getGatewayUrl as t } from "../../shared-config.js";
2
- import { validateGatewayBaseUrl as n } from "./security.js";
3
- import { isWorkspaceTokenValidForContext as r } from "./workspaceToken.js";
4
- import { dispatchBackendErrorEvent as i, markConnectionHealthy as a } from "../utils/backendErrors.js";
5
- import { clearGraphqlFetchResponseCache as o, enqueueGraphQLFetch as s, ensureWorkspaceToken as c } from "./fetch.js";
6
- import { SSELink as l } from "./links/sse-link.js";
7
- import { onError as u } from "@apollo/client/link/error";
8
- import { RetryLink as d } from "@apollo/client/link/retry";
9
- import { setContext as f } from "@apollo/client/link/context";
10
- import { ApolloClient as p, ApolloLink as m, InMemoryCache as ee, Observable as h, from as te, split as ne } from "@apollo/client/core";
11
- import { getMainDefinition as g } from "@apollo/client/utilities";
12
- import { print as _ } from "graphql";
1
+ import { isOperationRetryable as e } from "./retryPolicy.js";
2
+ import { GATEWAYS as t, getGatewayUrl as n } from "../../shared-config.js";
3
+ import { validateGatewayBaseUrl as r } from "./security.js";
4
+ import { isWorkspaceTokenValidForContext as i } from "./workspaceToken.js";
5
+ import { dispatchBackendErrorEvent as a, markConnectionHealthy as o } from "../utils/backendErrors.js";
6
+ import { clearGraphqlFetchResponseCache as s, enqueueGraphQLFetch as c, ensureWorkspaceToken as l } from "./fetch.js";
7
+ import { SSELink as u } from "./links/sse-link.js";
8
+ import { onError as d } from "@apollo/client/link/error";
9
+ import { RetryLink as f } from "@apollo/client/link/retry";
10
+ import { setContext as p } from "@apollo/client/link/context";
11
+ import { ApolloClient as m, ApolloLink as h, InMemoryCache as ee, Observable as g, from as te, split as _ } from "@apollo/client/core";
12
+ import { getMainDefinition as v } from "@apollo/client/utilities";
13
+ import { print as y } from "graphql";
13
14
  //#region src/shared/graphql/client.ts
14
- var v = {
15
+ var b = {
15
16
  consecutiveFailures: 0,
16
17
  lastFailureTime: 0,
17
18
  isOpen: !1,
18
19
  openCount: 0,
19
20
  nextRetryTime: 0
20
- }, y = 20, b = 5e3, x = 3e4;
21
- function re() {
22
- if (v.consecutiveFailures++, v.lastFailureTime = Date.now(), !v.isOpen && v.consecutiveFailures >= y) {
23
- v.isOpen = !0, v.openCount++;
24
- let e = Math.min(b * 2 ** (v.openCount - 1), x);
25
- v.nextRetryTime = Date.now() + e;
21
+ }, x = 20, S = 5e3, C = 3e4;
22
+ function ne() {
23
+ if (b.consecutiveFailures++, b.lastFailureTime = Date.now(), !b.isOpen && b.consecutiveFailures >= x) {
24
+ b.isOpen = !0, b.openCount++;
25
+ let e = Math.min(S * 2 ** (b.openCount - 1), C);
26
+ b.nextRetryTime = Date.now() + e;
26
27
  }
27
- return v.isOpen;
28
+ return b.isOpen;
29
+ }
30
+ function w() {
31
+ b.consecutiveFailures = 0, b.isOpen = !1, b.openCount = 0, b.nextRetryTime = 0, o();
28
32
  }
29
- function S() {
30
- v.consecutiveFailures = 0, v.isOpen = !1, v.openCount = 0, v.nextRetryTime = 0, a();
33
+ function re() {
34
+ return !(!b.isOpen || Date.now() >= b.nextRetryTime);
31
35
  }
32
- function C() {
33
- return !(!v.isOpen || Date.now() >= v.nextRetryTime);
36
+ function T(t, n, r) {
37
+ if (r || !t) return !1;
38
+ let i = t.message?.toLowerCase?.() ?? "";
39
+ return !(i.includes("401") || i.includes("403") || i.includes("unauthorized") || i.includes("forbidden") || i.includes("unauthenticated") || !e(n));
34
40
  }
35
- var w = /(?:\b40[13]\b|status code 40[13]|unauthori[sz]ed|unauthenticated|forbidden|invalid email or password)/i;
36
- function T(e) {
41
+ function ie({ maxAttempts: e, delay: t }) {
42
+ return new f({
43
+ delay: t ?? {
44
+ initial: 1e3,
45
+ max: 8e3,
46
+ jitter: !0
47
+ },
48
+ attempts: {
49
+ max: e,
50
+ retryIf: (e, t) => T(e, t, re())
51
+ }
52
+ });
53
+ }
54
+ var E = /(?:\b40[13]\b|status code 40[13]|unauthori[sz]ed|unauthenticated|forbidden|invalid email or password)/i;
55
+ function D(e) {
37
56
  return typeof e == "number" && Number.isInteger(e) ? e : typeof e == "string" && /^\d{3}$/.test(e) ? Number(e) : null;
38
57
  }
39
- function ie(e) {
58
+ function ae(e) {
40
59
  let t = /* @__PURE__ */ new Set(), n = (e, r) => {
41
60
  if (r > 3 || e == null || t.has(e)) return !1;
42
- if (typeof e == "string") return w.test(e);
61
+ if (typeof e == "string") return E.test(e);
43
62
  if (typeof e != "object") return !1;
44
63
  t.add(e);
45
- let i = e, a = T(i.status) ?? T(i.statusCode) ?? T(i.response?.status);
64
+ let i = e, a = D(i.status) ?? D(i.statusCode) ?? D(i.response?.status);
46
65
  if (a === 401 || a === 403) return !0;
47
66
  let o = i.message;
48
- return typeof o == "string" && w.test(o) ? !0 : n(i.cause, r + 1);
67
+ return typeof o == "string" && E.test(o) ? !0 : n(i.cause, r + 1);
49
68
  };
50
69
  return n(e, 0);
51
70
  }
52
- function ae(e) {
71
+ function oe(e) {
53
72
  if (!e || typeof e != "object") return null;
54
73
  let t = e, n = t.workspaceId || t.input?.workspaceId;
55
74
  return typeof n == "string" && n.trim() ? n : null;
56
75
  }
57
- function oe(e) {
76
+ function se(e) {
58
77
  if (!e || typeof e != "object") return null;
59
78
  let t = e.projectId;
60
79
  return typeof t == "string" && t.trim() ? t : null;
61
80
  }
62
- function se(e) {
63
- let t = g(e);
81
+ function ce(e) {
82
+ let t = v(e);
64
83
  return t.kind === "OperationDefinition" && t.operation === "mutation";
65
84
  }
66
- function ce(e) {
85
+ function le(e) {
67
86
  let t = e.errors;
68
87
  return Array.isArray(t) && t.length > 0;
69
88
  }
70
- function E(e) {
89
+ function O(e) {
71
90
  let t = e.headers;
72
91
  if (!t || typeof t != "object" || Array.isArray(t)) return {};
73
92
  let n = {};
74
93
  for (let [e, r] of Object.entries(t)) typeof r == "string" && (n[e] = r);
75
94
  return n;
76
95
  }
77
- function D(e) {
96
+ function k(e) {
78
97
  let t = e.fetchOptions;
79
98
  if (!t || typeof t != "object" || !("signal" in t)) return;
80
99
  let n = t.signal;
81
100
  return n instanceof AbortSignal ? n : void 0;
82
101
  }
83
- function le({ uri: e, batchMax: t, batchInterval: n }) {
84
- return new m((r) => new h((i) => {
85
- let a = r.getContext(), o = { query: _(r.query) };
102
+ function ue({ uri: e, batchMax: t, batchInterval: n }) {
103
+ return new h((r) => new g((i) => {
104
+ let a = r.getContext(), o = { query: y(r.query) };
86
105
  r.operationName && (o.operationName = r.operationName);
87
- let c = r.variables ?? {}, l = r.extensions ?? {};
88
- Object.keys(c).length > 0 && (o.variables = c), Object.keys(l).length > 0 && (o.extensions = l);
106
+ let s = r.variables ?? {}, l = r.extensions ?? {};
107
+ Object.keys(s).length > 0 && (o.variables = s), Object.keys(l).length > 0 && (o.extensions = l);
89
108
  let u = !1;
90
- return s(e, {
109
+ return c(e, {
91
110
  "content-type": "application/json",
92
111
  "Apollo-Require-Preflight": "true",
93
- ...E(a)
94
- }, o, D(a), {
112
+ ...O(a)
113
+ }, o, k(a), {
95
114
  batchMax: t,
96
115
  batchInterval: n
97
116
  }).then((e) => {
@@ -103,136 +122,122 @@ function le({ uri: e, batchMax: t, batchInterval: n }) {
103
122
  };
104
123
  }));
105
124
  }
106
- function O(a) {
107
- let { gateway: s, baseUrl: _, authToken: y, workspaceToken: b, locale: x, geography: w, organizationId: T, productId: E, productSlug: D, workspaceId: O, projectId: k, tenantId: A, cache: j, enableSubscriptions: M = !1, sseUrl: N, onAuthError: P, onRefreshToken: F, onNetworkError: I, onNetworkStatusChange: L, onMutationSuccess: R, maxRetryAttempts: ue = 3, batchMax: de = 10, batchInterval: fe, debug: z = !1 } = a, B = null, V = null, pe = (e) => {
108
- V ||= setTimeout(() => {
109
- V = null, B && B.refetchQueries({ include: "active" }).catch((t) => {
110
- z && console.warn("[GraphQL] Active query refresh failed after mutation:", {
111
- gateway: s,
125
+ function A(e) {
126
+ let { gateway: o, baseUrl: c, authToken: f, workspaceToken: y, locale: x, geography: S, organizationId: C, productId: T, productSlug: E, workspaceId: D, projectId: O, tenantId: k, cache: A, enableSubscriptions: j = !1, sseUrl: M, onAuthError: N, onRefreshToken: P, onNetworkError: F, onNetworkStatusChange: I, onMutationSuccess: L, maxRetryAttempts: de = 3, batchMax: fe = 10, batchInterval: pe, debug: R = !1 } = e, z = null, B = null, me = (e) => {
127
+ B ||= setTimeout(() => {
128
+ B = null, z && z.refetchQueries({ include: "active" }).catch((t) => {
129
+ R && console.warn("[GraphQL] Active query refresh failed after mutation:", {
130
+ gateway: o,
112
131
  operationName: e,
113
132
  error: t
114
133
  });
115
134
  });
116
135
  }, 0);
117
- }, H = e[s], U = n(t(_, s)), W = le({
118
- uri: U,
119
- batchMax: de,
120
- batchInterval: fe
121
- }), G = f((e, t) => {
122
- let n = t.headers ?? {}, r = typeof y == "function" ? y() : y;
136
+ }, V = t[o], H = r(n(c, o)), he = ue({
137
+ uri: H,
138
+ batchMax: fe,
139
+ batchInterval: pe
140
+ }), U = p((e, t) => {
141
+ let n = t.headers ?? {}, r = typeof f == "function" ? f() : f;
123
142
  return { headers: {
124
143
  ...n,
125
144
  ...r ? { authorization: `Bearer ${r}` } : {}
126
145
  } };
127
- }), K = f((e, t) => {
146
+ }), W = p((e, t) => {
128
147
  let n = t.headers ?? {}, r = typeof x == "function" ? x() : x;
129
148
  return { headers: {
130
149
  ...n,
131
150
  ...r ? { "accept-language": r } : {}
132
151
  } };
133
- }), q = f((e, t) => {
134
- let n = t.headers ?? {}, r = typeof w == "function" ? w() : null;
152
+ }), G = p((e, t) => {
153
+ let n = t.headers ?? {}, r = typeof S == "function" ? S() : null;
135
154
  return { headers: {
136
155
  ...n,
137
156
  ...r?.country ? { "x-geo-country": r.country } : {},
138
157
  ...r?.currency ? { "x-geo-currency": r.currency } : {},
139
158
  ...r?.timezone ? { "x-geo-timezone": r.timezone } : {}
140
159
  } };
141
- }), J = f((e, t) => {
142
- let n = t.headers ?? {}, r = typeof T == "function" ? T() : T;
160
+ }), K = p((e, t) => {
161
+ let n = t.headers ?? {}, r = typeof C == "function" ? C() : C;
143
162
  return { headers: {
144
163
  ...n,
145
164
  ...r ? { "x-org-id": r } : {}
146
165
  } };
147
- }), me = f((e, t) => {
148
- let n = t.headers ?? {}, r = typeof E == "function" ? E() : E, i = typeof D == "function" ? D() : D;
166
+ }), q = p((e, t) => {
167
+ let n = t.headers ?? {}, r = typeof T == "function" ? T() : T, i = typeof E == "function" ? E() : E;
149
168
  return { headers: {
150
169
  ...n,
151
170
  ...r ? { "x-product-id": r } : {},
152
171
  ...i ? { "x-product-slug": i } : {}
153
172
  } };
154
- }), he = f((e, t) => {
155
- let n = t.headers ?? {}, r = (typeof O == "function" ? O() : O) || ae(e.variables);
173
+ }), J = p((e, t) => {
174
+ let n = t.headers ?? {}, r = (typeof D == "function" ? D() : D) || oe(e.variables);
156
175
  return { headers: {
157
176
  ...n,
158
177
  ...r ? { "x-workspace-id": r } : {}
159
178
  } };
160
- }), ge = f((e, t) => {
161
- let n = t.headers ?? {}, r = (typeof k == "function" ? k() : k) || oe(e.variables);
179
+ }), Y = p((e, t) => {
180
+ let n = t.headers ?? {}, r = (typeof O == "function" ? O() : O) || se(e.variables);
162
181
  return { headers: {
163
182
  ...n,
164
183
  ...r ? { "x-project-id": r } : {}
165
184
  } };
166
- }), Y = f((e, t) => {
167
- let n = t.headers ?? {}, r = typeof A == "function" ? A() : A;
185
+ }), ge = p((e, t) => {
186
+ let n = t.headers ?? {}, r = typeof k == "function" ? k() : k;
168
187
  return { headers: {
169
188
  ...n,
170
189
  ...r ? { "x-tenant-id": r } : {}
171
190
  } };
172
- }), _e = f(async (e, n) => {
173
- let i = n.headers ?? {}, a = n.requiredWorkspaceAuth === !0;
174
- if (s === "global" && !a) return { headers: i };
175
- let o = typeof y == "function" ? y() : y, l = typeof b == "function" ? b() : b, u = typeof O == "function" ? O() : O, d = typeof T == "function" ? T() : T, f = typeof A == "function" ? A() : A, p = typeof k == "function" ? k() : k, m = r(l, {
191
+ }), X = p(async (e, t) => {
192
+ let r = t.headers ?? {}, a = t.requiredWorkspaceAuth === !0;
193
+ if (o === "global" && !a) return { headers: r };
194
+ let s = typeof f == "function" ? f() : f, c = typeof y == "function" ? y() : y, u = typeof D == "function" ? D() : D, d = typeof C == "function" ? C() : C, p = typeof k == "function" ? k() : k, m = typeof O == "function" ? O() : O, h = i(c, {
176
195
  workspaceId: u,
177
196
  organizationId: d,
178
- tenantId: f,
179
- projectId: p
180
- }) ? l : null;
181
- if (a && n.requiredWorkspaceId && n.requiredWorkspaceId !== u) throw Error("The active workspace changed; retry the request");
197
+ tenantId: p,
198
+ projectId: m
199
+ }) ? c : null;
200
+ if (a && t.requiredWorkspaceId && t.requiredWorkspaceId !== u) throw Error("The active workspace changed; retry the request");
182
201
  if (a && !u) throw Error("Workspace authentication requires an active workspace");
183
- if (!m && (s === "workspace" || a)) try {
184
- let n = typeof y == "function" ? y() : y;
185
- if (n) {
186
- let i = await Promise.race([c({
187
- url: s === "workspace" ? U : t(void 0, "workspace"),
188
- authToken: n,
202
+ if (!h && (o === "workspace" || a)) try {
203
+ let t = typeof f == "function" ? f() : f;
204
+ if (t) {
205
+ let r = await Promise.race([l({
206
+ url: o === "workspace" ? H : n(void 0, "workspace"),
207
+ authToken: t,
189
208
  workspaceId: u ?? void 0,
190
209
  organizationId: d ?? void 0,
191
- projectId: p ?? void 0,
210
+ projectId: m ?? void 0,
192
211
  currentQuery: e.operationName ?? ""
193
212
  }), new Promise((e) => setTimeout(() => e(null), 4e3))]);
194
- r(i, {
213
+ i(r, {
195
214
  workspaceId: u,
196
215
  organizationId: d,
197
- tenantId: f,
198
- projectId: p
199
- }) && (m = i);
216
+ tenantId: p,
217
+ projectId: m
218
+ }) && (h = r);
200
219
  }
201
220
  } catch {}
202
221
  if (a) {
203
- if (!m) throw Error("Workspace authentication is unavailable; retry the request");
204
- if (o !== (typeof y == "function" ? y() : y) || u !== (typeof O == "function" ? O() : O) || d !== (typeof T == "function" ? T() : T) || p !== (typeof k == "function" ? k() : k) || f !== (typeof A == "function" ? A() : A)) throw Error("The active workspace changed; retry the request");
222
+ if (!h) throw Error("Workspace authentication is unavailable; retry the request");
223
+ if (s !== (typeof f == "function" ? f() : f) || u !== (typeof D == "function" ? D() : D) || d !== (typeof C == "function" ? C() : C) || m !== (typeof O == "function" ? O() : O) || p !== (typeof k == "function" ? k() : k)) throw Error("The active workspace changed; retry the request");
205
224
  }
206
225
  return { headers: {
207
- ...i,
208
- ...m ? { "x-workspace-authorization": `Bearer ${m}` } : {}
226
+ ...r,
227
+ ...h ? { "x-workspace-authorization": `Bearer ${h}` } : {}
209
228
  } };
210
- }), ve = new d({
211
- delay: {
212
- initial: 1e3,
213
- max: 8e3,
214
- jitter: !0
215
- },
216
- attempts: {
217
- max: ue,
218
- retryIf: (e) => {
219
- if (C() || !e) return !1;
220
- let t = e.message?.toLowerCase?.() ?? "";
221
- return !(t.includes("401") || t.includes("403") || t.includes("unauthorized") || t.includes("forbidden") || t.includes("unauthenticated"));
222
- }
223
- }
224
- }), ye = new m((e, t) => {
225
- if (C()) {
226
- z && console.warn("[CircuitBreaker] Circuit is open, blocking request:", e.operationName);
227
- let t = Math.max(0, Math.ceil((v.nextRetryTime - Date.now()) / 1e3)), n = /* @__PURE__ */ Error(`Network circuit breaker is open — backend appears unreachable. Retrying in ${t} seconds.`);
228
- return I?.(n), new h((e) => {
229
+ }), _e = ie({ maxAttempts: de }), ve = new h((e, t) => {
230
+ if (re()) {
231
+ R && console.warn("[CircuitBreaker] Circuit is open, blocking request:", e.operationName);
232
+ let t = Math.max(0, Math.ceil((b.nextRetryTime - Date.now()) / 1e3)), n = /* @__PURE__ */ Error(`Network circuit breaker is open — backend appears unreachable. Retrying in ${t} seconds.`);
233
+ return F?.(n), new g((e) => {
229
234
  e.error(n);
230
235
  });
231
236
  }
232
- return new h((n) => {
237
+ return new g((n) => {
233
238
  let r = t(e).subscribe({
234
239
  next: (e) => {
235
- S(), v.consecutiveFailures === 0 && L?.(!1), n.next(e);
240
+ w(), b.consecutiveFailures === 0 && I?.(!1), n.next(e);
236
241
  },
237
242
  error: (e) => {
238
243
  n.error(e);
@@ -245,16 +250,16 @@ function O(a) {
245
250
  r.unsubscribe();
246
251
  };
247
252
  });
248
- }), X = !1, Z = [];
249
- function Q(e) {
250
- Z.forEach(({ resolve: t }) => t(e)), Z = [];
253
+ }), Z = !1, Q = [];
254
+ function $(e) {
255
+ Q.forEach(({ resolve: t }) => t(e)), Q = [];
251
256
  }
252
- let be = u(({ error: e, operation: t, forward: n }) => {
257
+ let ye = d(({ error: e, operation: t, forward: n }) => {
253
258
  let r = e.errors;
254
259
  if (r) {
255
- let a = r.some((e) => e.extensions?.code === "UNAUTHENTICATED" || e.message.includes("Unauthorized") || e.message.includes("Unauthenticated"));
256
- for (let e of r) z && console.error("[GraphQL Error]:", e.message);
257
- a && F || i({ errors: r }, { operationName: t.operationName });
260
+ let i = r.some((e) => e.extensions?.code === "UNAUTHENTICATED" || e.message.includes("Unauthorized") || e.message.includes("Unauthenticated"));
261
+ for (let e of r) R && console.error("[GraphQL Error]:", e.message);
262
+ i && P || a({ errors: r }, { operationName: t.operationName });
258
263
  let o = new Set(["STORAGE_QUOTA_EXCEEDED", "RESOURCE_CAP_EXCEEDED"]);
259
264
  for (let e of r) {
260
265
  let t = e.extensions?.code;
@@ -263,65 +268,65 @@ function O(a) {
263
268
  break;
264
269
  }
265
270
  }
266
- if (a && F) return new h((r) => {
271
+ if (i && P) return new g((r) => {
267
272
  (async () => {
268
- if (X) if (await new Promise((e) => {
269
- Z.push({ resolve: e });
273
+ if (Z) if (await new Promise((e) => {
274
+ Q.push({ resolve: e });
270
275
  })) {
271
276
  let e = n(t).subscribe(r);
272
277
  return () => e.unsubscribe();
273
- } else return P?.(), r.error(e), () => {};
274
- X = !0;
278
+ } else return N?.(), r.error(e), () => {};
279
+ Z = !0;
275
280
  try {
276
- let i = await F();
277
- if (X = !1, i) {
278
- Q(!0);
281
+ let i = await P();
282
+ if (Z = !1, i) {
283
+ $(!0);
279
284
  let e = n(t).subscribe(r);
280
285
  return () => e.unsubscribe();
281
- } else return Q(!1), P?.(), r.error(e), () => {};
286
+ } else return $(!1), N?.(), r.error(e), () => {};
282
287
  } catch {
283
- return X = !1, Q(!1), P?.(), r.error(e), () => {};
288
+ return Z = !1, $(!1), N?.(), r.error(e), () => {};
284
289
  }
285
290
  })();
286
291
  });
287
- a && P?.(), S();
292
+ i && N?.(), w();
288
293
  } else {
289
- if (z && console.error("[Network Error]:", e), ie(e)) {
290
- S(), e instanceof Error && i(e, {
294
+ if (R && console.error("[Network Error]:", e), ae(e)) {
295
+ w(), e instanceof Error && a(e, {
291
296
  operationName: t.operationName,
292
297
  fallbackMessage: "Your session is no longer valid. Please sign in again."
293
298
  });
294
299
  return;
295
300
  }
296
- if (re() && L?.(!0), e instanceof Error) I?.(e), i(e, {
301
+ if (ne() && I?.(!0), e instanceof Error) F?.(e), a(e, {
297
302
  operationName: t.operationName,
298
303
  fallbackMessage: "We could not reach the server. Please check your connection and try again."
299
304
  });
300
305
  else {
301
306
  let n = Error(String(e));
302
- I?.(n), i(n, {
307
+ F?.(n), a(n, {
303
308
  operationName: t.operationName,
304
309
  fallbackMessage: "We could not reach the server. Please check your connection and try again."
305
310
  });
306
311
  }
307
312
  }
308
- }), xe = new m((e, t) => {
309
- let n = se(e.query), r = n && e.getContext().autoRefreshAfterMutation !== !1 && e.getContext().skipMutationAutoRefresh !== !0;
310
- return new h((i) => {
313
+ }), be = new h((e, t) => {
314
+ let n = ce(e.query), r = n && e.getContext().autoRefreshAfterMutation !== !1 && e.getContext().skipMutationAutoRefresh !== !0;
315
+ return new g((i) => {
311
316
  let a = t(e).subscribe({
312
317
  next: (t) => {
313
- if (i.next(t), ce(t) || (n && o(), !r)) return;
318
+ if (i.next(t), le(t) || (n && s(), !r)) return;
314
319
  let a = e.operationName || "anonymous mutation";
315
- R ? Promise.resolve(R({
316
- gateway: s,
320
+ L ? Promise.resolve(L({
321
+ gateway: o,
317
322
  operationName: a
318
323
  })).catch((e) => {
319
- z && console.warn("[GraphQL] Mutation refresh callback failed:", {
320
- gateway: s,
324
+ R && console.warn("[GraphQL] Mutation refresh callback failed:", {
325
+ gateway: o,
321
326
  operationName: a,
322
327
  error: e
323
328
  });
324
- }) : pe(a);
329
+ }) : me(a);
325
330
  },
326
331
  error: (e) => {
327
332
  i.error(e);
@@ -334,51 +339,51 @@ function O(a) {
334
339
  a.unsubscribe();
335
340
  };
336
341
  });
337
- }), $ = te([
342
+ }), xe = te([
343
+ _e,
338
344
  ve,
339
345
  ye,
340
346
  be,
341
- xe,
342
- G,
343
- _e,
344
- J,
345
- me,
346
- he,
347
- ge,
348
- Y,
347
+ U,
348
+ X,
349
349
  K,
350
350
  q,
351
- ne(({ query: e }) => {
352
- let t = g(e);
351
+ J,
352
+ Y,
353
+ ge,
354
+ W,
355
+ G,
356
+ _(({ query: e }) => {
357
+ let t = v(e);
353
358
  return t.kind === "OperationDefinition" && t.operation === "subscription";
354
- }, new m((e) => new h((t) => {
359
+ }, new h((e) => new g((t) => {
355
360
  t.error(/* @__PURE__ */ Error(`[graphql] Refusing to send subscription "${e.operationName ?? "anonymous"}" over the batched HTTP transport — this gateway client was created without enableSubscriptions/SSE. Enable subscriptions on this client so it routes over SSE.`));
356
- })), W)
361
+ })), he)
357
362
  ]);
358
- if (M) {
359
- let e = H.sse, t = N || (e ? n(_ || H.defaultBaseUrl) + e : void 0);
360
- t && ($ = te([
363
+ if (j) {
364
+ let e = V.sse, t = M || (e ? r(c || V.defaultBaseUrl) + e : void 0);
365
+ t && (xe = te([
366
+ _e,
361
367
  ve,
362
368
  ye,
363
369
  be,
364
- xe,
365
- G,
366
- _e,
367
- J,
368
- me,
369
- he,
370
- ge,
371
- Y,
370
+ U,
371
+ X,
372
372
  K,
373
373
  q,
374
- ne(({ query: e }) => {
375
- let t = g(e);
374
+ J,
375
+ Y,
376
+ ge,
377
+ W,
378
+ G,
379
+ _(({ query: e }) => {
380
+ let t = v(e);
376
381
  return t.kind === "OperationDefinition" && t.operation === "subscription";
377
- }, new l({
382
+ }, new u({
378
383
  url: t,
379
384
  headers: {},
380
- debug: z
381
- }), W)
385
+ debug: R
386
+ }), he)
382
387
  ]));
383
388
  }
384
389
  let Se = new ee({ typePolicies: {
@@ -416,9 +421,9 @@ function O(a) {
416
421
  VibecontrolsAgent: { keyFields: ["id"] },
417
422
  Query: { fields: { vibes: { keyArgs: ["filter"] } } }
418
423
  } });
419
- return B = new p({
420
- link: $,
421
- cache: j ?? Se,
424
+ return z = new m({
425
+ link: xe,
426
+ cache: A ?? Se,
422
427
  defaultOptions: {
423
428
  watchQuery: {
424
429
  fetchPolicy: "cache-and-network",
@@ -430,19 +435,19 @@ function O(a) {
430
435
  },
431
436
  mutate: { errorPolicy: "all" }
432
437
  }
433
- }), B;
438
+ }), z;
434
439
  }
435
- var k = null, A = null;
436
- function j(e) {
440
+ var j = null, M = null;
441
+ function N(e) {
437
442
  let { workspaceBaseUrl: t, globalBaseUrl: n, authToken: r, enableSubscriptions: i = !1, onAuthError: a, debug: o = !1 } = e;
438
- k = O({
443
+ j = A({
439
444
  gateway: "workspace",
440
445
  baseUrl: t,
441
446
  authToken: r,
442
447
  enableSubscriptions: i,
443
448
  onAuthError: a,
444
449
  debug: o
445
- }), A = O({
450
+ }), M = A({
446
451
  gateway: "global",
447
452
  baseUrl: n,
448
453
  authToken: r,
@@ -450,16 +455,16 @@ function j(e) {
450
455
  debug: o
451
456
  });
452
457
  }
453
- function M() {
454
- if (!k) throw Error("Workspace client not initialized. Call initializeAppClients first.");
455
- return k;
458
+ function P() {
459
+ if (!j) throw Error("Workspace client not initialized. Call initializeAppClients first.");
460
+ return j;
456
461
  }
457
- function N() {
458
- if (!A) throw Error("Global client not initialized. Call initializeAppClients first.");
459
- return A;
462
+ function F() {
463
+ if (!M) throw Error("Global client not initialized. Call initializeAppClients first.");
464
+ return M;
460
465
  }
461
- function P() {
462
- k &&= (k.clearStore(), null), A &&= (A.clearStore(), null);
466
+ function I() {
467
+ j &&= (j.clearStore(), null), M &&= (M.clearStore(), null);
463
468
  }
464
469
  //#endregion
465
- export { O as createGraphQLClient, N as getGlobalClient, M as getWorkspaceClient, j as initializeAppClients, P as resetAppClients };
470
+ export { A as createGraphQLClient, F as getGlobalClient, P as getWorkspaceClient, N as initializeAppClients, I as resetAppClients };
@@ -0,0 +1,27 @@
1
+ import { DocumentNode } from 'graphql';
2
+ /**
3
+ * Operation-context key that explicitly opts a MUTATION in to automatic
4
+ * transport-level retries. Nothing opts in today.
5
+ *
6
+ * A mutation can change server state even when the response never arrives
7
+ * (a 504 / dropped connection is ambiguous: the write may have committed).
8
+ * Replaying it blindly can duplicate or silently re-apply the write, so the
9
+ * shared retry links never retry mutations unless the caller sets
10
+ * `context: { retryMutation: true }` AND guarantees the mutation is idempotent
11
+ * (for example a keyed upsert). Callers that need recovery from an ambiguous
12
+ * failure should reconcile explicitly (read the state back) instead.
13
+ */
14
+ export declare const RETRY_MUTATION_CONTEXT_KEY = "retryMutation";
15
+ /** The minimal operation surface the retry policy needs (ApolloLink.Operation fits). */
16
+ export interface RetryPolicyOperation {
17
+ query: DocumentNode;
18
+ getContext: () => Record<string, unknown>;
19
+ }
20
+ /** True when any operation definition in the document is a mutation. */
21
+ export declare function isMutationOperation(operation: Pick<RetryPolicyOperation, 'query'>): boolean;
22
+ /**
23
+ * Whether the transport may replay this operation after a failure. Queries and
24
+ * subscriptions are replayable; mutations only with an explicit
25
+ * `retryMutation: true` context opt-in.
26
+ */
27
+ export declare function isOperationRetryable(operation: RetryPolicyOperation | undefined): boolean;
@@ -0,0 +1,10 @@
1
+ //#region src/shared/graphql/retryPolicy.ts
2
+ var e = "retryMutation";
3
+ function t(e) {
4
+ return e.query.definitions.some((e) => e.kind === "OperationDefinition" && e.operation === "mutation");
5
+ }
6
+ function n(n) {
7
+ return !n || !t(n) ? !0 : n.getContext()[e] === !0;
8
+ }
9
+ //#endregion
10
+ export { n as isOperationRetryable };
@@ -1,4 +1,5 @@
1
1
  import { ApolloClient, InMemoryCache } from '@apollo/client';
2
+ import { RetryPolicyOperation } from '../graphql/retryPolicy';
2
3
  export interface CreateApolloClientOptions {
3
4
  uri: string;
4
5
  getAuthToken?: () => string | null | undefined;
@@ -15,11 +16,14 @@ export declare function withBrowserTraceHeader(headersInit?: HeadersInit): Heade
15
16
  *
16
17
  * Retries any unrecognised error (default-true) so genuine transient
17
18
  * network / 5xx failures still benefit from the link's retry budget;
18
- * permanent failures are filtered via three signals, in order:
19
+ * permanent failures are filtered via three signals, in order.
20
+ * Mutations are never retried (an ambiguous 5xx/timeout may have committed the
21
+ * write) unless the operation context sets `retryMutation: true`.
22
+ * Signals:
19
23
  * 1. Numeric `statusCode` (Apollo Client 4's `ServerError`)
20
24
  * 2. `errors[].extensions.code` (GraphQL response auth codes)
21
25
  * 3. Substring match on `message` (fallback for link errors that
22
26
  * surface auth codes only in their message string)
23
27
  */
24
- export declare function shouldRetryApolloError(error: unknown): boolean;
28
+ export declare function shouldRetryApolloError(error: unknown, operation?: RetryPolicyOperation): boolean;
25
29
  export declare function createApolloClient(options: CreateApolloClientOptions): ApolloClient;
@@ -1,28 +1,29 @@
1
1
  import { createBrowserTraceContext as e } from "../events/metadata.js";
2
- import { ApolloClient as t, InMemoryCache as n, from as r } from "@apollo/client";
3
- import { BatchHttpLink as i } from "@apollo/client/link/batch-http";
4
- import { onError as a } from "@apollo/client/link/error";
5
- import { RetryLink as o } from "@apollo/client/link/retry";
6
- import { setContext as s } from "@apollo/client/link/context";
2
+ import { isOperationRetryable as t } from "../graphql/retryPolicy.js";
3
+ import { ApolloClient as n, InMemoryCache as r, from as i } from "@apollo/client";
4
+ import { BatchHttpLink as a } from "@apollo/client/link/batch-http";
5
+ import { onError as o } from "@apollo/client/link/error";
6
+ import { RetryLink as s } from "@apollo/client/link/retry";
7
+ import { setContext as c } from "@apollo/client/link/context";
7
8
  //#region src/shared/utils/apollo.ts
8
- function c(t) {
9
+ function l(t) {
9
10
  let n = new Headers(t);
10
11
  return n.has("traceparent") || n.set("traceparent", e().traceparent), n;
11
12
  }
12
- var l = new Set([
13
+ var u = new Set([
13
14
  401,
14
15
  403,
15
16
  413
16
17
  ]);
17
- function u(e) {
18
- if (!e) return !1;
19
- let t = e.statusCode;
20
- if (typeof t == "number" && l.has(t) || e.errors?.some((e) => e.extensions?.code === "UNAUTHENTICATED" || e.extensions?.code === "FORBIDDEN")) return !1;
21
- let n = e.message;
22
- return !(n && /UNAUTHENTICATED|FORBIDDEN/.test(n));
18
+ function d(e, n) {
19
+ if (!e || !t(n)) return !1;
20
+ let r = e.statusCode;
21
+ if (typeof r == "number" && u.has(r) || e.errors?.some((e) => e.extensions?.code === "UNAUTHENTICATED" || e.extensions?.code === "FORBIDDEN")) return !1;
22
+ let i = e.message;
23
+ return !(i && /UNAUTHENTICATED|FORBIDDEN/.test(i));
23
24
  }
24
- function d(e) {
25
- let { uri: l, getAuthToken: d, onAuthError: f, onNetworkError: p, cache: m = new n(), retryAttempts: h = 3, retryDelay: g = 1e3 } = e, _ = new o({
25
+ function f(e) {
26
+ let { uri: t, getAuthToken: u, onAuthError: f, onNetworkError: p, cache: m = new r(), retryAttempts: h = 3, retryDelay: g = 1e3 } = e, _ = new s({
26
27
  delay: {
27
28
  initial: g,
28
29
  max: g * 4,
@@ -30,15 +31,15 @@ function d(e) {
30
31
  },
31
32
  attempts: {
32
33
  max: h,
33
- retryIf: u
34
+ retryIf: d
34
35
  }
35
- }), v = a(({ error: e }) => {
36
+ }), v = o(({ error: e }) => {
36
37
  let t = e.errors;
37
38
  t ? t.forEach((e) => {
38
39
  console.error(`[GraphQL error]: Message: ${e.message}, Location: ${JSON.stringify(e.locations)}, Path: ${e.path}`), e.extensions?.code === "UNAUTHENTICATED" && f?.();
39
40
  }) : e && (console.error(`[Network error]: ${e.message}`), p?.(e));
40
- }), y = s((e, { headers: t }) => {
41
- let n = d?.();
41
+ }), y = c((e, { headers: t }) => {
42
+ let n = u?.();
42
43
  console.log("[fe-libs apollo] getAuthToken returned:", n ? n.substring(0, 20) + "..." : "null");
43
44
  let r = { headers: {
44
45
  ...t,
@@ -47,15 +48,15 @@ function d(e) {
47
48
  return console.log("[fe-libs apollo] Authorization header:", r.headers.authorization ? r.headers.authorization.substring(0, 30) + "..." : "MISSING"), r;
48
49
  }), b = fetch, x = ((e, t) => fetch(e, {
49
50
  ...t,
50
- headers: c(t?.headers)
51
+ headers: l(t?.headers)
51
52
  }));
52
- return b.preconnect && (x.preconnect = b.preconnect), new t({
53
- link: r([
53
+ return b.preconnect && (x.preconnect = b.preconnect), new n({
54
+ link: i([
54
55
  _,
55
56
  v,
56
57
  y,
57
- new i({
58
- uri: l,
58
+ new a({
59
+ uri: t,
59
60
  credentials: "include",
60
61
  batchMax: 10,
61
62
  batchInterval: 100,
@@ -77,4 +78,4 @@ function d(e) {
77
78
  });
78
79
  }
79
80
  //#endregion
80
- export { d as createApolloClient };
81
+ export { f as createApolloClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fe-libs",
3
- "version": "2026.1010.1",
3
+ "version": "2026.1010.2",
4
4
  "description": "Burdenoff frontend primitives and domain libraries",
5
5
  "type": "module",
6
6
  "bin": {
@@ -314,7 +314,7 @@
314
314
  "test:package-css-exports": "node scripts/validate-package-css-exports.mjs",
315
315
  "verify:package": "node scripts/verify-package-contents.mjs",
316
316
  "test:handsfree-browser": "node scripts/handsfree-browser-run.mjs",
317
- "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/connections src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/graphql/fetch.test.ts src/shared/graphql/tourWorkspaceAuth.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/gatewayFallback.test.ts scripts/__tests__ src/shared/config/products.test.ts src/shared/config/productSlug.test.ts src/shared/hooks/shell/useProducts.test.ts src/shared/providers/shell/brandAttribute.test.ts src/chrome/ProductSwitcher.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/providers/shell/interpolate.test.ts src/shared/providers/shell/resolveTranslation.test.ts src/shared/providers/shell/I18nProvider.render.test.tsx src/shared/providers/shell/I18nProvider.client.test.tsx src/shared/providers/shell/translationStore.test.ts src/shared/providers/shell/translationLayers.test.ts src/shared/providers/shell/directionMode.test.ts src/shared/providers/shell/authProvider/ssoRelay.test.ts src/shared/providers/shell/personaSurfaceRemote.test.ts src/shared/providers/shell/workspaceSwitch.client.test.tsx src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/shared/navigation src/shared/tours src/chrome/__tests__ src/ui/__tests__",
317
+ "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/connections src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/graphql/fetch.test.ts src/shared/graphql/client.test.ts src/shared/utils/apollo.test.ts src/shared/graphql/tourWorkspaceAuth.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/gatewayFallback.test.ts scripts/__tests__ src/shared/config/products.test.ts src/shared/config/productSlug.test.ts src/shared/hooks/shell/useProducts.test.ts src/shared/providers/shell/brandAttribute.test.ts src/chrome/ProductSwitcher.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/providers/shell/interpolate.test.ts src/shared/providers/shell/resolveTranslation.test.ts src/shared/providers/shell/I18nProvider.render.test.tsx src/shared/providers/shell/I18nProvider.client.test.tsx src/shared/providers/shell/translationStore.test.ts src/shared/providers/shell/translationLayers.test.ts src/shared/providers/shell/directionMode.test.ts src/shared/providers/shell/authProvider/ssoRelay.test.ts src/shared/providers/shell/personaSurfaceRemote.test.ts src/shared/providers/shell/workspaceSwitch.client.test.tsx src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/shared/navigation src/shared/tours src/chrome/__tests__ src/ui/__tests__",
318
318
  "sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build && bun run verify:package'",
319
319
  "switch:status": "bun scripts/deps-mode.ts status",
320
320
  "switch:remote": "bun scripts/deps-mode.ts remote",