@epam/ai-dial-chat-hooks 1.2.0-dev.213 → 1.2.0-dev.218

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.
@@ -26,20 +26,22 @@ var e = (e) => typeof e == "object" && !!e, t = (t) => {
26
26
  }
27
27
  return e instanceof Error && e.message ? e.message : null;
28
28
  }, d = async (t) => {
29
- let r = s(t), i = r?.status, a = null, c, l = !1, u;
29
+ let r = s(t), i = r?.status, a = null, c, l = !1, u, d, f;
30
30
  if (r) try {
31
31
  let t = await (typeof r.clone == "function" ? r.clone() : r).json();
32
- a = n(t), e(t) && (u = typeof t.code == "string" ? t.code : void 0, c = o(t.traceparent));
32
+ a = n(t), e(t) && (u = typeof t.code == "string" ? t.code : void 0, d = typeof t.upstreamCode == "string" ? t.upstreamCode : void 0, f = typeof t.upstreamMessage == "string" ? t.upstreamMessage : void 0, c = o(t.traceparent));
33
33
  } catch {
34
34
  l = !0;
35
35
  }
36
36
  !l && a === null && t instanceof Error && t.message && (a = t.message);
37
- let d = c ?? o(typeof r?.headers?.get == "function" ? r.headers.get("traceparent") : void 0);
37
+ let p = c ?? o(typeof r?.headers?.get == "function" ? r.headers.get("traceparent") : void 0);
38
38
  return {
39
39
  status: i,
40
40
  message: a,
41
- traceId: d,
42
- ...u ? { code: u } : {}
41
+ traceId: p,
42
+ ...u ? { code: u } : {},
43
+ ...d ? { upstreamCode: d } : {},
44
+ ...f ? { upstreamMessage: f } : {}
43
45
  };
44
46
  };
45
47
  //#endregion
@@ -1,34 +1,53 @@
1
1
  import { safeDecodeURIComponent as e } from "../../shared/string-utils.js";
2
- import { findDeploymentByIdOrReference as t } from "../../catalog/deployment-id.js";
3
- import { getModelIdFromConversationId as n } from "../get-model-id-from-conversation-id.js";
4
- import { FilterTab as r } from "@epam/ai-dial-chat-shared";
5
- import { useMemo as i } from "react";
2
+ import { getModelIdFromConversationId as t } from "../get-model-id-from-conversation-id.js";
3
+ import { FilterTab as n } from "@epam/ai-dial-chat-shared";
4
+ import { useEffect as r, useMemo as i, useRef as a } from "react";
6
5
  //#region src/conversation/useConversationPanelItems/useConversationPanelItems.ts
7
- var a = (e) => e.sharedWithMe ? r.Shared : e.publishedWithMe ? r.Organization : r.MyChats, o = ({ items: r, deployments: o, isDeploymentsLoading: s, toPanelConversationId: c, resolveIconUrl: l, resolveIconTooltip: u, resolveHref: d, resolveTaskPresentation: f }) => i(() => r.map((r) => {
8
- let i = c(r.id), p = n(r.id), m = p ? t(o, p) : void 0, h = p ? e(p.split("/").pop() ?? p) : "", g = f?.(r);
9
- return {
10
- id: i,
11
- title: r.title,
12
- isPinned: r.isPinned ?? !1,
13
- iconUrl: l(m),
14
- iconTooltip: u(m, h),
15
- isIconLoading: s,
16
- source: a(r),
17
- href: d(i),
18
- ...g == null ? {} : {
19
- leadingIcon: g.leadingIcon,
20
- isUnread: g.isUnread
21
- }
22
- };
23
- }), [
24
- r,
25
- o,
26
- s,
27
- c,
28
- l,
29
- u,
30
- d,
31
- f
32
- ]);
6
+ var o = (e) => e.sharedWithMe ? n.Shared : e.publishedWithMe ? n.Organization : n.MyChats, s = (e) => {
7
+ let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
8
+ for (let r of e) t.has(r.id) || t.set(r.id, r), r.reference && !n.has(r.reference) && n.set(r.reference, r);
9
+ return (e) => t.get(e) ?? n.get(e);
10
+ }, c = ({ items: n, deployments: c, isDeploymentsLoading: l, toPanelConversationId: u, resolveIconUrl: d, resolveIconTooltip: f, resolveHref: p, resolveTaskPresentation: m }) => {
11
+ let h = i(() => s(c), [c]), g = i(() => (n) => {
12
+ let r = u(n.id), i = t(n.id), a = i ? h(i) : void 0, s = i ? e(i.split("/").pop() ?? i) : "", c = m?.(n);
13
+ return {
14
+ id: r,
15
+ title: n.title,
16
+ isPinned: n.isPinned ?? !1,
17
+ iconUrl: d(a),
18
+ iconTooltip: f(a, s),
19
+ isIconLoading: l,
20
+ source: o(n),
21
+ href: p(r),
22
+ ...c == null ? {} : {
23
+ leadingIcon: c.leadingIcon,
24
+ isUnread: c.isUnread
25
+ }
26
+ };
27
+ }, [
28
+ h,
29
+ l,
30
+ u,
31
+ d,
32
+ f,
33
+ p,
34
+ m
35
+ ]), _ = a(null), v = i(() => {
36
+ let e = _.current, t = e?.mapItem === g ? e.byDto : void 0, r = /* @__PURE__ */ new Map();
37
+ return {
38
+ mapped: n.map((e) => {
39
+ let n = t?.get(e) ?? g(e);
40
+ return r.set(e, n), n;
41
+ }),
42
+ cache: {
43
+ mapItem: g,
44
+ byDto: r
45
+ }
46
+ };
47
+ }, [n, g]);
48
+ return r(() => {
49
+ _.current = v.cache;
50
+ }, [v]), v.mapped;
51
+ };
33
52
  //#endregion
34
- export { a as getConversationSource, o as useConversationPanelItems };
53
+ export { o as getConversationSource, c as useConversationPanelItems };
package/conversation.d.ts CHANGED
@@ -1072,6 +1072,11 @@ export declare interface UseConversationLookupMapsParams {
1072
1072
  * Returns a memoised array whose shape is compatible with the conversation
1073
1073
  * panel's item contract. All app-specific concerns (icon URL resolution,
1074
1074
  * route generation, id normalisation) are injected via resolver callbacks.
1075
+ *
1076
+ * While every input except `items` is unchanged, a DTO that is referentially
1077
+ * the same as in the previous render maps to the same item object, so a list
1078
+ * change (or a navigation that re-derives the list) re-renders only the rows
1079
+ * whose DTO actually changed.
1075
1080
  */
1076
1081
  export declare const useConversationPanelItems: ({ items, deployments, isDeploymentsLoading, toPanelConversationId, resolveIconUrl, resolveIconTooltip, resolveHref, resolveTaskPresentation, }: UseConversationPanelItemsParams) => {
1077
1082
  leadingIcon?: ReactNode;
@@ -127,10 +127,14 @@ export declare const hasAttachmentTextSource: (attachment: DisplayAttachment, re
127
127
  declare interface HtmlCanvasContent {
128
128
  /** Discriminates the content type to select the correct renderer. */
129
129
  type: AttachmentContentType.Html;
130
- /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Used for file attachments. */
130
+ /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Populated only when no `url` is available (local, non-downloadable file attachments); when `url` is set, "View source" instead calls `resolveSourceText`. */
131
131
  srcdoc?: string;
132
- /** External URL rendered via `src` in a sandboxed iframe. Used for external link sources. */
132
+ /** URL rendered via `src` in a sandboxed iframe when `srcdoc` is absent, or in preference to `srcdoc` when `isSameOriginUrl` is set. Also used as the download-button/"Open in new tab" target. */
133
133
  url?: string;
134
+ /** True when `url`'s origin matches the embedding document's own origin. Forces the iframe sandbox to omit `allow-same-origin` — granting it would let a same-origin framed document reach this page's own cookies/storage — and makes `src` take precedence over `srcdoc`; also skips the `contentDocument` block-detection check, since the iframe is intentionally opaque-origin either way. */
135
+ isSameOriginUrl?: boolean;
136
+ /** Lazily fetches the full HTML source text for the "View source" toggle. Used instead of an eagerly-populated `srcdoc` when `url` is set; absent when `srcdoc` is already populated. */
137
+ resolveSourceText?: () => Promise<string>;
134
138
  }
135
139
 
136
140
  /** Content payload for image attachments. */
@@ -330,9 +334,16 @@ export declare const resolveGroupedVisualizerCanvasContent: (attachments: Displa
330
334
 
331
335
  /**
332
336
  * Resolves an HTML canvas content payload from a DisplayAttachment.
333
- * Fetches and inlines the HTML as `srcdoc` when the attachment has a download URL or inline data.
334
- * Returns `null` if no source is available, or an `ErrorCanvasContent` on fetch failure.
335
- * Rejects `srcdoc` payloads larger than 1 MiB to prevent browser truncation.
337
+ * When the attachment has a download URL, that URL is the primary render
338
+ * target so the preview loads via `src` and gets its own response-level CSP
339
+ * instead of inheriting the host document's — no HTML text is fetched up
340
+ * front; `resolveSourceText` fetches it lazily, only when the "View source"
341
+ * toggle is used, and rejects if that fetch fails. `isSameOriginUrl` reflects
342
+ * a real comparison against the embedding document's own origin.
343
+ * With no download URL (local file or inline data), falls back to `srcdoc`
344
+ * only, rejecting payloads larger than 1 MiB to prevent browser truncation.
345
+ * Returns `null` if no source is available, or an `ErrorCanvasContent` when
346
+ * that fallback fetch fails.
336
347
  */
337
348
  export declare const resolveHtmlCanvasContent: (attachment: DisplayAttachment, resolvers: AttachmentCanvasUrlResolvers) => Promise<HtmlCanvasContent | ErrorCanvasContent | null>;
338
349
 
@@ -124,18 +124,30 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
124
124
  text: i,
125
125
  language: r
126
126
  } : i;
127
- }, I = async (e, n) => {
128
- let r = await k(e, n);
129
- if (r == null) return null;
130
- if (typeof r != "string") return r;
131
- if (r.length > P) return null;
132
- let i = n.resolveDialUrl(e) ?? void 0;
133
- return {
127
+ }, I = (e) => {
128
+ try {
129
+ return new URL(e, window.location.href).origin;
130
+ } catch {
131
+ return;
132
+ }
133
+ }, L = async (e, n) => {
134
+ let r = n.resolveDialUrl(e) ?? void 0;
135
+ if (r != null) return {
134
136
  type: t.Html,
135
- srcdoc: r,
136
- url: i
137
+ url: r,
138
+ isSameOriginUrl: I(r) === I(window.location.href),
139
+ resolveSourceText: async () => {
140
+ let t = await k(e, n);
141
+ if (t == null || typeof t != "string") throw Error("Failed to resolve HTML source text");
142
+ return t;
143
+ }
137
144
  };
138
- }, L = (n, r, i) => {
145
+ let i = await k(e, n);
146
+ return i == null ? null : typeof i == "string" ? i.length > P ? null : {
147
+ type: t.Html,
148
+ srcdoc: i
149
+ } : i;
150
+ }, R = (n, r, i) => {
139
151
  let a = n.body?.source?.attachment;
140
152
  if (a?.type !== o.PDF) return null;
141
153
  let s = e(a.url) ? i.resolveDialFileDownloadUrl(a.url) : a.url;
@@ -148,7 +160,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
148
160
  selectedHighlightId: f.some((e) => e.id === m) ? m : void 0,
149
161
  page: p(n)
150
162
  };
151
- }, R = (e) => {
163
+ }, z = (e) => {
152
164
  switch (e.type) {
153
165
  case "docx_text_anchor": return {
154
166
  kind: i.DocxTableRow,
@@ -184,7 +196,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
184
196
  end: e.end
185
197
  };
186
198
  }
187
- }, z = (n, i, o) => {
199
+ }, B = (n, i, o) => {
188
200
  let s = n.body?.source?.attachment;
189
201
  if (s?.url == null) return null;
190
202
  let c = a(s.title ?? s.url, s.type);
@@ -198,7 +210,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
198
210
  let i = l(e, t);
199
211
  m.push({
200
212
  id: i,
201
- locations: r.map(R)
213
+ locations: r.map(z)
202
214
  }), e === n && (h = i);
203
215
  }), {
204
216
  type: t.Ooxml,
@@ -209,7 +221,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
209
221
  selectedHighlightId: h
210
222
  } : {}
211
223
  };
212
- }, B = (n, r) => {
224
+ }, V = (n, r) => {
213
225
  let i = m(n.url);
214
226
  if (i == null) return null;
215
227
  let a = e(i.baseUrl) ? r.resolveDialFileDownloadUrl(i.baseUrl) : i.baseUrl;
@@ -239,38 +251,38 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
239
251
  selectedHighlightId: o,
240
252
  page: i.page
241
253
  };
242
- }, V = (e) => {
254
+ }, H = (e) => {
243
255
  try {
244
256
  let t = new URL(e).protocol;
245
257
  return t === "http:" || t === "https:" || t === "blob:";
246
258
  } catch {
247
259
  return !1;
248
260
  }
249
- }, H = (t) => t.url != null && !e(t.url) && V(t.url) ? t.url : void 0, U = async (e, n) => {
261
+ }, U = (t) => t.url != null && !e(t.url) && H(t.url) ? t.url : void 0, W = async (e, n) => {
250
262
  let r = await O(e, n);
251
263
  if (r != null) return typeof r == "string" ? {
252
264
  type: t.Pdf,
253
265
  url: r
254
266
  } : r;
255
- let i = H(e);
267
+ let i = U(e);
256
268
  return i == null ? null : {
257
269
  type: t.Pdf,
258
270
  url: i
259
271
  };
260
- }, W = async (e, n, r) => {
272
+ }, G = async (e, n, r) => {
261
273
  let i = await O(e, n);
262
274
  if (i != null) return typeof i == "string" ? {
263
275
  type: t.Ooxml,
264
276
  url: i,
265
277
  format: r
266
278
  } : i;
267
- let a = H(e);
279
+ let a = U(e);
268
280
  return a == null ? null : {
269
281
  type: t.Ooxml,
270
282
  url: a,
271
283
  format: r
272
284
  };
273
- }, G = async (e, n) => {
285
+ }, K = async (e, n) => {
274
286
  let r = await k(e, n);
275
287
  if (r == null) return null;
276
288
  if (typeof r != "string") return r;
@@ -286,7 +298,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
286
298
  text: r
287
299
  };
288
300
  }
289
- }, K = async (e, n, r, i) => {
301
+ }, q = async (e, n, r, i) => {
290
302
  let a = await k(e, n);
291
303
  if (a == null || typeof a != "string") return null;
292
304
  let o = {};
@@ -308,7 +320,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
308
320
  visualizerName: r.title,
309
321
  requestTimeout: r.requestTimeout
310
322
  };
311
- }, q = (e, n, r, i) => {
323
+ }, J = (e, n, r, i) => {
312
324
  let a = {
313
325
  width: r.width,
314
326
  height: r.height,
@@ -338,4 +350,4 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
338
350
  };
339
351
  };
340
352
  //#endregion
341
- export { z as annotationToOoxmlCanvasContent, L as annotationToPdfCanvasContent, S as clearAttachmentCache, A as hasAttachmentTextSource, B as referenceAttachmentToPdfCanvasContent, F as resolveCodeCanvasContent, q as resolveGroupedVisualizerCanvasContent, I as resolveHtmlCanvasContent, j as resolveImageCanvasContent, G as resolveJsonCanvasContent, N as resolveMarkdownCanvasContent, W as resolveOoxmlCanvasContent, U as resolvePdfCanvasContent, M as resolveTextCanvasContent, K as resolveVisualizerCanvasContent };
353
+ export { B as annotationToOoxmlCanvasContent, R as annotationToPdfCanvasContent, S as clearAttachmentCache, A as hasAttachmentTextSource, V as referenceAttachmentToPdfCanvasContent, F as resolveCodeCanvasContent, J as resolveGroupedVisualizerCanvasContent, L as resolveHtmlCanvasContent, j as resolveImageCanvasContent, K as resolveJsonCanvasContent, N as resolveMarkdownCanvasContent, G as resolveOoxmlCanvasContent, W as resolvePdfCanvasContent, M as resolveTextCanvasContent, q as resolveVisualizerCanvasContent };
@@ -15,22 +15,22 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
15
15
  }, [T]);
16
16
  let [O, k] = p(() => /* @__PURE__ */ new Map()), [se, A] = p(S), [ce, le] = p(S);
17
17
  ce !== S && (le(S), A(S));
18
- let [ue, j] = p(null), [M, de] = p(0), [N, P] = p(void 0), [fe, F] = p(() => /* @__PURE__ */ new Set()), I = f(/* @__PURE__ */ new Map()), [pe, L] = p(!1), [me, R] = p(null), z = f(null), B = f(null), V = f(/* @__PURE__ */ new Set()), H = f(/* @__PURE__ */ new Set()), [U, W] = p(() => /* @__PURE__ */ new Set()), [he, G] = p(() => /* @__PURE__ */ new Set()), [K, q] = p(() => /* @__PURE__ */ new Set()), J = `${b}|${oe ?? ""}`, Y = f(J);
18
+ let [ue, j] = p(null), [M, N] = p(0), [P, F] = p(void 0), [de, I] = p(() => /* @__PURE__ */ new Set()), L = f(/* @__PURE__ */ new Map()), [fe, R] = p(!1), [pe, z] = p(null), B = f(null), V = f(null), H = f(/* @__PURE__ */ new Set()), U = f(/* @__PURE__ */ new Set()), [W, G] = p(() => /* @__PURE__ */ new Set()), [me, K] = p(() => /* @__PURE__ */ new Set()), [q, J] = p(() => /* @__PURE__ */ new Set()), Y = `${b}|${oe ?? ""}`, X = f(Y);
19
19
  u(() => {
20
- Y.current !== J && (Y.current = J, E(/* @__PURE__ */ new Map()), k(/* @__PURE__ */ new Map()), w(""), P(void 0), I.current = /* @__PURE__ */ new Map(), V.current = /* @__PURE__ */ new Set(), H.current = /* @__PURE__ */ new Set(), G(/* @__PURE__ */ new Set()), q(/* @__PURE__ */ new Set()), z.current != null && (clearTimeout(z.current), z.current = null), B.current?.(), B.current = null, R(null), L(!1), W(/* @__PURE__ */ new Set()));
21
- }, [J]), u(() => () => {
22
- z.current != null && clearTimeout(z.current), B.current?.();
20
+ X.current !== Y && (X.current = Y, E(/* @__PURE__ */ new Map()), k(/* @__PURE__ */ new Map()), w(""), F(void 0), L.current = /* @__PURE__ */ new Map(), H.current = /* @__PURE__ */ new Set(), U.current = /* @__PURE__ */ new Set(), K(/* @__PURE__ */ new Set()), J(/* @__PURE__ */ new Set()), B.current != null && (clearTimeout(B.current), B.current = null), V.current?.(), V.current = null, z(null), R(!1), G(/* @__PURE__ */ new Set()), N((e) => e + 1));
21
+ }, [Y]), u(() => () => {
22
+ B.current != null && clearTimeout(B.current), V.current?.();
23
23
  }, []), u(() => {
24
24
  if (!S) {
25
25
  A(!1);
26
26
  return;
27
27
  }
28
28
  let t = !1;
29
- return A(!0), j(null), s(_, b, v, C, I.current).then(({ items: e, permissions: i }) => {
29
+ return A(!0), j(null), s(_, b, v, C, L.current).then(({ items: e, permissions: i }) => {
30
30
  t || (E((t) => {
31
31
  let n = new Map(t);
32
32
  return n.set(C, e), n;
33
- }), k((e) => new Map(e).set(C, i)), b === g.Shared && C === "" && (P(e.map((e) => n(r(e.path, e.bucket ?? ""), y, e.nodeType === m.Folder))), I.current = new Map(e.map((e) => [e.name, {
33
+ }), k((e) => new Map(e).set(C, i)), b === g.Shared && C === "" && (F(e.map((e) => n(r(e.path, e.bucket ?? ""), y, e.nodeType === m.Folder))), L.current = new Map(e.map((e) => [e.name, {
34
34
  bucket: e.bucket ?? "",
35
35
  dialCorePath: e.path
36
36
  }]))));
@@ -57,14 +57,14 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
57
57
  y
58
58
  ]), u(() => {
59
59
  if (!S || b !== g.MyFiles) {
60
- F(/* @__PURE__ */ new Set());
60
+ I(/* @__PURE__ */ new Set());
61
61
  return;
62
62
  }
63
63
  let e = !1;
64
64
  return _.listSharedByMe(v).then((t) => {
65
- e || F(new Set(t.items.map((e) => n(r(e.path, v), y, e.nodeType === m.Folder))));
65
+ e || I(new Set(t.items.map((e) => n(r(e.path, v), y, e.nodeType === m.Folder))));
66
66
  }).catch(() => {
67
- e || F(/* @__PURE__ */ new Set());
67
+ e || I(/* @__PURE__ */ new Set());
68
68
  }), () => {
69
69
  e = !0;
70
70
  };
@@ -76,7 +76,7 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
76
76
  M,
77
77
  y
78
78
  ]);
79
- let X = d(() => [{
79
+ let Z = d(() => [{
80
80
  id: v,
81
81
  name: y,
82
82
  path: `/${y}`,
@@ -90,7 +90,7 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
90
90
  O,
91
91
  y,
92
92
  v
93
- ]), ge = l((e) => {
93
+ ]), he = l((e) => {
94
94
  if (e == null) {
95
95
  w("");
96
96
  return;
@@ -108,11 +108,11 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
108
108
  r = t.startsWith(n) ? t.slice(n.length) : t;
109
109
  }
110
110
  w(r && !r.endsWith("/") ? `${r}/` : r);
111
- }, [y]), Z = l(() => {
112
- de((e) => e + 1);
113
- }, []), _e = Z, ve = l((e) => {
111
+ }, [y]), Q = l(() => {
112
+ N((e) => e + 1);
113
+ }, []), ge = Q, _e = l((e) => {
114
114
  if (e.length === 0) return;
115
- let n = new Set([...U].map((e) => o(e, y))), r = (e) => e === C || C.startsWith(e) || n.has(e), i = e.filter((e) => !r(e)), a = e.filter((e) => r(e) && e !== C);
115
+ let n = new Set([...W].map((e) => o(e, y))), r = (e) => e === C || C.startsWith(e) || n.has(e), i = e.filter((e) => !r(e)), a = e.filter((e) => r(e) && e !== C);
116
116
  i.length > 0 && (E((e) => {
117
117
  let t = new Map(e);
118
118
  return i.forEach((e) => t.delete(e)), t;
@@ -122,7 +122,7 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
122
122
  })), a.forEach((e) => {
123
123
  (async () => {
124
124
  try {
125
- let { items: t, permissions: n } = await s(_, b, v, e, I.current);
125
+ let { items: t, permissions: n } = await s(_, b, v, e, L.current);
126
126
  E((n) => new Map(n).set(e, t)), n != null && k((t) => new Map(t).set(e, n));
127
127
  } catch {
128
128
  x?.({
@@ -137,40 +137,40 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
137
137
  v,
138
138
  _,
139
139
  C,
140
- U,
140
+ W,
141
141
  y,
142
142
  x
143
- ]), Q = l((e, t, n) => {
143
+ ]), ve = l((e, t, n) => {
144
144
  E((r) => ie(r, e, t, n));
145
145
  }, []), ye = l((e) => {
146
146
  if (!S) return;
147
147
  let n = e == null ? "" : o(e, y), r = e ?? `/${y}`;
148
- if (q((e) => {
148
+ if (J((e) => {
149
149
  if (e.has(r)) return e;
150
150
  let t = new Set(e);
151
151
  return t.add(r), t;
152
152
  }), !D.current.has(n)) {
153
- if (V.current.has(n)) {
154
- G((e) => {
153
+ if (H.current.has(n)) {
154
+ K((e) => {
155
155
  let t = new Set(e);
156
156
  return t.add(r), t;
157
157
  });
158
158
  return;
159
159
  }
160
- V.current.add(n), G((e) => {
160
+ H.current.add(n), K((e) => {
161
161
  let t = new Set(e);
162
162
  return t.add(r), t;
163
163
  }), (async () => {
164
164
  try {
165
- let { items: e, permissions: t } = await s(_, b, v, n, I.current);
166
- E((t) => new Map(t).set(n, e)), t != null && k((e) => new Map(e).set(n, t)), H.current.delete(n);
165
+ let { items: e, permissions: t } = await s(_, b, v, n, L.current);
166
+ E((t) => new Map(t).set(n, e)), t != null && k((e) => new Map(e).set(n, t)), U.current.delete(n);
167
167
  } catch {
168
168
  x?.({
169
169
  variant: h.Error,
170
170
  reason: t.FolderLoadFailed
171
171
  });
172
172
  } finally {
173
- V.current.delete(n), G((e) => {
173
+ H.current.delete(n), K((e) => {
174
174
  let t = new Set(e);
175
175
  return t.delete(r), t;
176
176
  });
@@ -185,36 +185,36 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
185
185
  x,
186
186
  y
187
187
  ]), be = d(() => {
188
- let e = /* @__PURE__ */ new Set(), t = new Set([...U, ...K]);
188
+ let e = /* @__PURE__ */ new Set(), t = new Set([...W, ...q]);
189
189
  for (let n of t) {
190
190
  let t = o(n, y);
191
191
  T.has(t) && e.add(n);
192
192
  }
193
193
  return e;
194
194
  }, [
195
- U,
196
- K,
195
+ W,
196
+ q,
197
197
  T,
198
198
  y
199
199
  ]), xe = l((e) => {
200
- S && (U.forEach((t) => {
201
- e.has(t) || H.current.delete(o(t, y));
202
- }), W(e), [...e].filter((e) => {
200
+ S && (W.forEach((t) => {
201
+ e.has(t) || U.current.delete(o(t, y));
202
+ }), G(e), [...e].filter((e) => {
203
203
  let t = o(e, y);
204
- return !D.current.has(t) && !V.current.has(t) && !H.current.has(t);
204
+ return !D.current.has(t) && !H.current.has(t) && !U.current.has(t);
205
205
  }).forEach((e) => {
206
206
  let n = o(e, y);
207
- V.current.add(n), (async () => {
207
+ H.current.add(n), (async () => {
208
208
  try {
209
- let { items: e, permissions: t } = await s(_, b, v, n, I.current);
209
+ let { items: e, permissions: t } = await s(_, b, v, n, L.current);
210
210
  E((t) => new Map(t).set(n, e)), t != null && k((e) => new Map(e).set(n, t));
211
211
  } catch {
212
- H.current.add(n), x?.({
212
+ U.current.add(n), x?.({
213
213
  variant: h.Error,
214
214
  reason: t.FolderLoadFailed
215
215
  });
216
216
  } finally {
217
- V.current.delete(n), G((t) => {
217
+ H.current.delete(n), K((t) => {
218
218
  let n = new Set(t);
219
219
  return n.delete(e), n;
220
220
  });
@@ -225,35 +225,35 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
225
225
  b,
226
226
  v,
227
227
  _,
228
- U,
228
+ W,
229
229
  S,
230
230
  x,
231
231
  y
232
232
  ]), Se = l(() => {
233
- z.current != null && (clearTimeout(z.current), z.current = null), B.current?.(), B.current = null, R(null), L(!1);
233
+ B.current != null && (clearTimeout(B.current), B.current = null), V.current?.(), V.current = null, z(null), R(!1);
234
234
  }, []), Ce = l((e, t) => {
235
235
  if (S) {
236
- if (z.current != null && (clearTimeout(z.current), z.current = null), B.current?.(), B.current = null, !t.trim()) {
237
- R(null), L(!1);
236
+ if (B.current != null && (clearTimeout(B.current), B.current = null), V.current?.(), V.current = null, !t.trim()) {
237
+ z(null), R(!1);
238
238
  return;
239
239
  }
240
- z.current = setTimeout(() => {
241
- if (z.current = null, b === g.Shared && C === "") {
242
- B.current?.(), B.current = null, L(!0), R((T.get("") ?? []).map((e) => c(e, e.bucket ?? v, y))), L(!1);
240
+ B.current = setTimeout(() => {
241
+ if (B.current = null, b === g.Shared && C === "") {
242
+ V.current?.(), V.current = null, R(!0), z((T.get("") ?? []).map((e) => c(e, e.bucket ?? v, y))), R(!1);
243
243
  return;
244
244
  }
245
245
  let e = !1;
246
- B.current = () => {
246
+ V.current = () => {
247
247
  e = !0;
248
- }, L(!0), (async () => {
248
+ }, R(!0), (async () => {
249
249
  try {
250
- let { items: t } = await ne(_, b, v, C, I.current);
250
+ let { items: t } = await ne(_, b, v, C, L.current);
251
251
  if (e) return;
252
- R(t.map((e) => c(e, e.bucket ?? v, y)));
252
+ z(t.map((e) => c(e, e.bucket ?? v, y)));
253
253
  } catch {
254
- e || R([]);
254
+ e || z([]);
255
255
  } finally {
256
- e || L(!1);
256
+ e || R(!1);
257
257
  }
258
258
  })();
259
259
  }, 300);
@@ -267,40 +267,40 @@ var _ = ({ filesApi: _, bucket: v, rootLabel: y, activeTab: b, onNotification: x
267
267
  S,
268
268
  y
269
269
  ]), $ = C ? `/${y}/${C}` : `/${y}`, we = d(() => {
270
- let e = X[0];
270
+ let e = Z[0];
271
271
  if (e) return a($) === a(`/${y}`) ? e : i(e.items ?? [], $);
272
272
  }, [
273
- X,
273
+ Z,
274
274
  $,
275
275
  y
276
276
  ]);
277
277
  return {
278
- items: X,
278
+ items: Z,
279
279
  isLoading: se,
280
280
  error: ue,
281
281
  path: $,
282
282
  folderPath: C,
283
- onPathChange: ge,
284
- retry: Z,
283
+ onPathChange: he,
284
+ retry: Q,
285
285
  onSearchFiles: Ce,
286
- isSearching: pe,
287
- searchResults: me,
286
+ isSearching: fe,
287
+ searchResults: pe,
288
288
  clearSearchResults: Se,
289
- expandedPaths: U,
289
+ expandedPaths: W,
290
290
  loadedPaths: be,
291
291
  onExpandedPathsChange: xe,
292
292
  onFolderPopupPathChange: ye,
293
- folderPopupLoadingPaths: he,
294
- sharedWithMeIds: d(() => b === g.Shared ? N : void 0, [b, N]),
295
- sharedByMePaths: fe,
293
+ folderPopupLoadingPaths: me,
294
+ sharedWithMeIds: d(() => b === g.Shared ? P : void 0, [b, P]),
295
+ sharedByMePaths: de,
296
296
  currentFolder: we,
297
297
  cache: T,
298
298
  listingPermissionsCache: O,
299
- sharedRootMetaRef: I,
299
+ sharedRootMetaRef: L,
300
300
  setFolderPath: w,
301
- invalidateFolders: ve,
302
- mergeCreatedFolder: Q,
303
- bumpRetry: _e
301
+ invalidateFolders: _e,
302
+ mergeCreatedFolder: ve,
303
+ bumpRetry: ge
304
304
  };
305
305
  };
306
306
  //#endregion
package/index.d.ts CHANGED
@@ -266,6 +266,16 @@ export declare interface ApiErrorDetails {
266
266
  message: string | null;
267
267
  /** Extracted W3C trace ID, when the error's response carries a valid `traceparent`. */
268
268
  traceId?: string;
269
+ /**
270
+ * Error code reported by the service behind the API, when the API forwards one
271
+ * (`upstreamCode`). Passed through as-is; the host decides whether to act on it.
272
+ */
273
+ upstreamCode?: string;
274
+ /**
275
+ * Error reason reported by the service behind the API, when the API forwards one
276
+ * (`upstreamMessage`). Untranslated; the host decides whether to display it.
277
+ */
278
+ upstreamMessage?: string;
269
279
  }
270
280
 
271
281
  /** Appends a locale's uppercased code to a field label, e.g. `'Name [EN]'`. */
@@ -1788,7 +1798,7 @@ export declare class GenerationPersistenceError extends Error {
1788
1798
  constructor();
1789
1799
  }
1790
1800
 
1791
- /** Normalizes any API error into a `{ status?, message, traceId?, code? }` shape. */
1801
+ /** Normalizes any API error into a `{ status?, message, traceId?, code?, upstreamCode?, upstreamMessage? }` shape. */
1792
1802
  export declare const getApiErrorDetails: (error: unknown) => Promise<ApiErrorDetails>;
1793
1803
 
1794
1804
  /** Resolves a human-readable message from an API error's response body, or falls back to `Error.message`. */
@@ -2072,10 +2082,14 @@ export declare const hasStructuredAnnouncement: ({ title, description, }: Announ
2072
2082
  declare interface HtmlCanvasContent {
2073
2083
  /** Discriminates the content type to select the correct renderer. */
2074
2084
  type: AttachmentContentType.Html;
2075
- /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Used for file attachments. */
2085
+ /** Full HTML text rendered via `srcdoc` in a sandboxed iframe. Populated only when no `url` is available (local, non-downloadable file attachments); when `url` is set, "View source" instead calls `resolveSourceText`. */
2076
2086
  srcdoc?: string;
2077
- /** External URL rendered via `src` in a sandboxed iframe. Used for external link sources. */
2087
+ /** URL rendered via `src` in a sandboxed iframe when `srcdoc` is absent, or in preference to `srcdoc` when `isSameOriginUrl` is set. Also used as the download-button/"Open in new tab" target. */
2078
2088
  url?: string;
2089
+ /** True when `url`'s origin matches the embedding document's own origin. Forces the iframe sandbox to omit `allow-same-origin` — granting it would let a same-origin framed document reach this page's own cookies/storage — and makes `src` take precedence over `srcdoc`; also skips the `contentDocument` block-detection check, since the iframe is intentionally opaque-origin either way. */
2090
+ isSameOriginUrl?: boolean;
2091
+ /** Lazily fetches the full HTML source text for the "View source" toggle. Used instead of an eagerly-populated `srcdoc` when `url` is set; absent when `srcdoc` is already populated. */
2092
+ resolveSourceText?: () => Promise<string>;
2079
2093
  }
2080
2094
 
2081
2095
  /** Content payload for image attachments. */
@@ -3407,9 +3421,16 @@ export declare const resolveGroupedVisualizerCanvasContent: (attachments: Displa
3407
3421
 
3408
3422
  /**
3409
3423
  * Resolves an HTML canvas content payload from a DisplayAttachment.
3410
- * Fetches and inlines the HTML as `srcdoc` when the attachment has a download URL or inline data.
3411
- * Returns `null` if no source is available, or an `ErrorCanvasContent` on fetch failure.
3412
- * Rejects `srcdoc` payloads larger than 1 MiB to prevent browser truncation.
3424
+ * When the attachment has a download URL, that URL is the primary render
3425
+ * target so the preview loads via `src` and gets its own response-level CSP
3426
+ * instead of inheriting the host document's — no HTML text is fetched up
3427
+ * front; `resolveSourceText` fetches it lazily, only when the "View source"
3428
+ * toggle is used, and rejects if that fetch fails. `isSameOriginUrl` reflects
3429
+ * a real comparison against the embedding document's own origin.
3430
+ * With no download URL (local file or inline data), falls back to `srcdoc`
3431
+ * only, rejecting payloads larger than 1 MiB to prevent browser truncation.
3432
+ * Returns `null` if no source is available, or an `ErrorCanvasContent` when
3433
+ * that fallback fetch fails.
3413
3434
  */
3414
3435
  export declare const resolveHtmlCanvasContent: (attachment: DisplayAttachment, resolvers: AttachmentCanvasUrlResolvers) => Promise<HtmlCanvasContent | ErrorCanvasContent | null>;
3415
3436
 
@@ -5077,6 +5098,11 @@ export declare interface UseConversationLookupMapsParams {
5077
5098
  * Returns a memoised array whose shape is compatible with the conversation
5078
5099
  * panel's item contract. All app-specific concerns (icon URL resolution,
5079
5100
  * route generation, id normalisation) are injected via resolver callbacks.
5101
+ *
5102
+ * While every input except `items` is unchanged, a DTO that is referentially
5103
+ * the same as in the previous render maps to the same item object, so a list
5104
+ * change (or a navigation that re-derives the list) re-renders only the rows
5105
+ * whose DTO actually changed.
5080
5106
  */
5081
5107
  export declare const useConversationPanelItems: ({ items, deployments, isDeploymentsLoading, toPanelConversationId, resolveIconUrl, resolveIconTooltip, resolveHref, resolveTaskPresentation, }: UseConversationPanelItemsParams) => {
5082
5108
  leadingIcon?: ReactNode;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@epam/ai-dial-chat-hooks",
3
3
  "description": "Framework-level React hooks extracted from AI DIAL Chat for building custom chat interfaces",
4
- "version": "1.2.0-dev.213",
4
+ "version": "1.2.0-dev.218",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./index.js",
@@ -111,7 +111,7 @@
111
111
  }
112
112
  },
113
113
  "dependencies": {
114
- "@epam/ai-dial-chat-api-client": "1.2.0-dev.213",
114
+ "@epam/ai-dial-chat-api-client": "1.2.0-dev.218",
115
115
  "dompurify": "3.4.15",
116
116
  "fflate": "^0.8.3",
117
117
  "lru-cache": "^10.4.3",
@@ -120,21 +120,21 @@
120
120
  },
121
121
  "peerDependencies": {
122
122
  "react": "^19.2.8",
123
- "@epam/ai-dial-attachment-canvas": "1.2.0-dev.213",
124
- "@epam/ai-dial-attachment-input": "1.2.0-dev.213",
125
- "@epam/ai-dial-catalog": "1.2.0-dev.213",
126
- "@epam/ai-dial-chat-overlay": "1.2.0-dev.213",
127
- "@epam/ai-dial-chat-shared": "1.2.0-dev.213",
128
- "@epam/ai-dial-mcp-apps": "1.2.0-dev.213",
129
- "@epam/ai-dial-publish-panel": "1.2.0-dev.213",
130
- "@epam/ai-dial-quotations": "1.2.0-dev.213",
123
+ "@epam/ai-dial-attachment-canvas": "1.2.0-dev.218",
124
+ "@epam/ai-dial-attachment-input": "1.2.0-dev.218",
125
+ "@epam/ai-dial-catalog": "1.2.0-dev.218",
126
+ "@epam/ai-dial-chat-overlay": "1.2.0-dev.218",
127
+ "@epam/ai-dial-chat-shared": "1.2.0-dev.218",
128
+ "@epam/ai-dial-mcp-apps": "1.2.0-dev.218",
129
+ "@epam/ai-dial-publish-panel": "1.2.0-dev.218",
130
+ "@epam/ai-dial-quotations": "1.2.0-dev.218",
131
131
  "@epam/ai-dial-react-file-manager": "^0.3.0-dev.19",
132
- "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.213",
133
- "@epam/ai-dial-share": "1.2.0-dev.213",
134
- "@epam/ai-dial-skill-editor": "1.2.0-dev.213",
135
- "@epam/ai-dial-source-panel": "1.2.0-dev.213",
132
+ "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.218",
133
+ "@epam/ai-dial-share": "1.2.0-dev.218",
134
+ "@epam/ai-dial-skill-editor": "1.2.0-dev.218",
135
+ "@epam/ai-dial-source-panel": "1.2.0-dev.218",
136
136
  "@epam/ai-dial-ui-kit": "^0.15.0-dev.27",
137
- "@epam/ai-dial-usage-dashboard": "1.2.0-dev.213",
137
+ "@epam/ai-dial-usage-dashboard": "1.2.0-dev.218",
138
138
  "@modelcontextprotocol/sdk": "^1.29.0",
139
139
  "@epam/pdf-highlighter-kit": "^0.0.19",
140
140
  "@mcp-ui/client": "^7.1.1"
package/utils.d.ts CHANGED
@@ -18,6 +18,16 @@ export declare interface ApiErrorDetails {
18
18
  message: string | null;
19
19
  /** Extracted W3C trace ID, when the error's response carries a valid `traceparent`. */
20
20
  traceId?: string;
21
+ /**
22
+ * Error code reported by the service behind the API, when the API forwards one
23
+ * (`upstreamCode`). Passed through as-is; the host decides whether to act on it.
24
+ */
25
+ upstreamCode?: string;
26
+ /**
27
+ * Error reason reported by the service behind the API, when the API forwards one
28
+ * (`upstreamMessage`). Untranslated; the host decides whether to display it.
29
+ */
30
+ upstreamMessage?: string;
21
31
  }
22
32
 
23
33
  /** Appends a locale's uppercased code to a field label, e.g. `'Name [EN]'`. */
@@ -134,7 +144,7 @@ export declare interface ExportedPrompt {
134
144
  /** Formats a Unix timestamp (ms) as a locale-formatted calendar date, e.g. `'22/7/2026'`. */
135
145
  export declare const formatCalendarDate: (timestampMs: number) => string;
136
146
 
137
- /** Normalizes any API error into a `{ status?, message, traceId?, code? }` shape. */
147
+ /** Normalizes any API error into a `{ status?, message, traceId?, code?, upstreamCode?, upstreamMessage? }` shape. */
138
148
  export declare const getApiErrorDetails: (error: unknown) => Promise<ApiErrorDetails>;
139
149
 
140
150
  /** Resolves a human-readable message from an API error's response body, or falls back to `Error.message`. */