@webority/ui-elements 0.30.0 → 0.32.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/{fileViewerPdf-C02nR-30.js → fileViewerPdf-BnIsj-J-.js} +57 -35
- package/dist/types/chatClient.d.ts +208 -0
- package/dist/types/chatCore.d.ts +4 -0
- package/dist/types/chatLabels.d.ts +69 -0
- package/dist/types/markdownParse.d.ts +77 -0
- package/dist/types/sse.d.ts +33 -0
- package/dist/ui-chat-core.js +347 -0
- package/dist/ui-chat.global.js +10 -0
- package/dist/ui-chat.js +1066 -0
- package/dist/ui-elements.global.js +80 -66
- package/dist/ui-elements.js +1283 -1019
- package/dist/ui-file-viewer.global.js +4 -4
- package/dist/ui-file-viewer.js +6 -2
- package/package.json +8 -2
|
@@ -15140,15 +15140,45 @@ function na(e) {
|
|
|
15140
15140
|
}
|
|
15141
15141
|
ta ??= URL.createObjectURL(new Blob([Fi], { type: "text/javascript" })), jn.workerSrc = ta;
|
|
15142
15142
|
}
|
|
15143
|
-
|
|
15143
|
+
function ra(e) {
|
|
15144
|
+
let t = e ? e.replace(/\/?$/, "/") : null;
|
|
15145
|
+
return {
|
|
15146
|
+
isEvalSupported: !1,
|
|
15147
|
+
...t && {
|
|
15148
|
+
cMapUrl: `${t}cmaps/`,
|
|
15149
|
+
cMapPacked: !0,
|
|
15150
|
+
standardFontDataUrl: `${t}standard_fonts/`,
|
|
15151
|
+
wasmUrl: `${t}wasm/`
|
|
15152
|
+
}
|
|
15153
|
+
};
|
|
15154
|
+
}
|
|
15155
|
+
async function ia(e, { workerSrc: t, assetBase: n, width: r = 640 } = {}) {
|
|
15156
|
+
na(t);
|
|
15157
|
+
let i = hr({
|
|
15158
|
+
...e instanceof Blob ? { data: new Uint8Array(await e.arrayBuffer()) } : { url: e.url },
|
|
15159
|
+
...ra(n)
|
|
15160
|
+
});
|
|
15161
|
+
try {
|
|
15162
|
+
let e = await (await i.promise).getPage(1), t = e.getViewport({ scale: r / e.getViewport({ scale: 1 }).width }), n = document.createElement("canvas");
|
|
15163
|
+
return n.width = Math.floor(t.width), n.height = Math.floor(t.height), await e.render({
|
|
15164
|
+
canvas: n,
|
|
15165
|
+
viewport: t
|
|
15166
|
+
}).promise, await new Promise((e, t) => {
|
|
15167
|
+
n.toBlob((n) => n ? e(n) : t(/* @__PURE__ */ Error("The first page could not be drawn.")), "image/png");
|
|
15168
|
+
});
|
|
15169
|
+
} finally {
|
|
15170
|
+
await i.destroy();
|
|
15171
|
+
}
|
|
15172
|
+
}
|
|
15173
|
+
var aa = (e) => {
|
|
15144
15174
|
if (Wi.some((t) => t.key === e)) return e;
|
|
15145
15175
|
let t = Number(e);
|
|
15146
15176
|
return Hi.includes(t) ? t : "fit-width";
|
|
15147
|
-
},
|
|
15177
|
+
}, oa = (e) => e instanceof Element && e.closest("input, textarea, select, [contenteditable='true'], .dropdown-menu"), sa = (e) => /^(https?:|mailto:)/i.test(e), ca = class {
|
|
15148
15178
|
constructor(e, t) {
|
|
15149
15179
|
this.shell = e, this.source = t;
|
|
15150
15180
|
let n = e.prefs;
|
|
15151
|
-
this.zoom =
|
|
15181
|
+
this.zoom = aa(n.zoom), this.twoPage = n.twoPage === !0, this.showThumbs = n.thumbnails === !0, this.pdf = null, this.sizes = [], this.rows = [], this.rowOf = [], this.scale = 0, this.drawnScale = 0, this.pages = /* @__PURE__ */ new Map(), this.thumbsDrawn = /* @__PURE__ */ new Set(), this.area = {
|
|
15152
15182
|
width: 0,
|
|
15153
15183
|
height: 0
|
|
15154
15184
|
}, this.scrollPos = {
|
|
@@ -15165,32 +15195,24 @@ var ra = (e) => {
|
|
|
15165
15195
|
}, this.printRun = null, this.destroyed = !1, this._timers = /* @__PURE__ */ new Set();
|
|
15166
15196
|
}
|
|
15167
15197
|
async load() {
|
|
15168
|
-
na(this.source.workerSrc)
|
|
15169
|
-
let e = this.source.assetBase ? this.source.assetBase.replace(/\/?$/, "/") : null;
|
|
15170
|
-
this.task = hr({
|
|
15198
|
+
na(this.source.workerSrc), this.task = hr({
|
|
15171
15199
|
url: this.source.src,
|
|
15172
|
-
|
|
15173
|
-
...e && {
|
|
15174
|
-
cMapUrl: `${e}cmaps/`,
|
|
15175
|
-
cMapPacked: !0,
|
|
15176
|
-
standardFontDataUrl: `${e}standard_fonts/`,
|
|
15177
|
-
wasmUrl: `${e}wasm/`
|
|
15178
|
-
}
|
|
15200
|
+
...ra(this.source.assetBase)
|
|
15179
15201
|
});
|
|
15180
|
-
let
|
|
15202
|
+
let e;
|
|
15181
15203
|
try {
|
|
15182
|
-
|
|
15204
|
+
e = await this.task.promise;
|
|
15183
15205
|
} catch (e) {
|
|
15184
15206
|
this.destroyed || this.shell.fail(e);
|
|
15185
15207
|
return;
|
|
15186
15208
|
}
|
|
15187
15209
|
if (this.destroyed) {
|
|
15188
|
-
|
|
15210
|
+
e.destroy();
|
|
15189
15211
|
return;
|
|
15190
15212
|
}
|
|
15191
|
-
this.pdf =
|
|
15192
|
-
let
|
|
15193
|
-
this.destroyed || (this.sizes =
|
|
15213
|
+
this.pdf = e;
|
|
15214
|
+
let t = await Promise.all(Array.from({ length: e.numPages }, (t, n) => e.getPage(n + 1)));
|
|
15215
|
+
this.destroyed || (this.sizes = t.map((e) => {
|
|
15194
15216
|
let t = e.getViewport({ scale: Gi });
|
|
15195
15217
|
return {
|
|
15196
15218
|
width: t.width,
|
|
@@ -15198,7 +15220,7 @@ var ra = (e) => {
|
|
|
15198
15220
|
};
|
|
15199
15221
|
}), this._buildToolbar(), this._buildBody(), this._layout(), this.shell.loaded({
|
|
15200
15222
|
kind: "pdf",
|
|
15201
|
-
pages:
|
|
15223
|
+
pages: e.numPages
|
|
15202
15224
|
}));
|
|
15203
15225
|
}
|
|
15204
15226
|
destroy() {
|
|
@@ -15236,7 +15258,7 @@ var ra = (e) => {
|
|
|
15236
15258
|
checked: this.zoom === e.key
|
|
15237
15259
|
}))
|
|
15238
15260
|
],
|
|
15239
|
-
onPick: (e) => this._setZoom(
|
|
15261
|
+
onPick: (e) => this._setZoom(aa(e))
|
|
15240
15262
|
}), this.zoomInButton = r("zoom-in", "Zoom in"), this.zoomInButton.addEventListener("click", () => this._stepZoom(1));
|
|
15241
15263
|
let c = document.createElement("span");
|
|
15242
15264
|
c.className = "wui-file-viewer-divider", this.twoPageButton = r("two-page", "Two-page view"), this.twoPageButton.addEventListener("click", () => this._setTwoPage(!this.twoPage)), this.printButton = r("printer", "Print"), this.printButton.addEventListener("click", () => this.print()), i.prepend(this.searchButton, this.zoomOutButton, this.zoomButton, this.zoomInButton, c, this.twoPageButton, this.printButton), this._buildSearchRow(), this._syncToolbar();
|
|
@@ -15291,7 +15313,7 @@ var ra = (e) => {
|
|
|
15291
15313
|
}
|
|
15292
15314
|
_targetScale() {
|
|
15293
15315
|
if (typeof this.zoom == "number") return this.zoom;
|
|
15294
|
-
let e = this.cols(), t =
|
|
15316
|
+
let e = this.cols(), t = fa(this.sizes.map((e) => e.width)), n = fa(this.sizes.map((e) => e.height)), r = (this.area.width - 2 * Ki - (e - 1) * qi) / (t * e);
|
|
15295
15317
|
return this.zoom === "fit-page" && (r = Math.min(r, (this.area.height - 2 * Ki) / n)), Math.max(r, .1);
|
|
15296
15318
|
}
|
|
15297
15319
|
_layout() {
|
|
@@ -15465,7 +15487,7 @@ var ra = (e) => {
|
|
|
15465
15487
|
async _drawLinks(e) {
|
|
15466
15488
|
let t = await this.pdf.getPage(e.n), n = await t.getAnnotations({ intent: "display" });
|
|
15467
15489
|
if (e.released || this.destroyed) return;
|
|
15468
|
-
let r = n.filter((e) => e.subtype === "Link" && (e.dest || e.url &&
|
|
15490
|
+
let r = n.filter((e) => e.subtype === "Link" && (e.dest || e.url && sa(e.url))), i = (await Promise.all(r.map(async (e) => e.url ? { link: e } : {
|
|
15469
15491
|
link: e,
|
|
15470
15492
|
target: await this._destPage(e.dest)
|
|
15471
15493
|
}))).filter(({ link: e, target: t }) => e.url || t);
|
|
@@ -15494,7 +15516,7 @@ var ra = (e) => {
|
|
|
15494
15516
|
window.clearTimeout(this._jumpTimer), this.scroller.removeEventListener("scrollend", this._endJump), this.jumpTarget = null, this._syncToolbar();
|
|
15495
15517
|
}, Math.abs(n - this.scroller.scrollTop) >= 1 && (this.jumpTarget = t, this.scroller.addEventListener("scrollend", this._endJump), this._jumpTimer = window.setTimeout(this._endJump, Zi), this._timers.add(this._jumpTimer), this.scroller.scrollTo({
|
|
15496
15518
|
top: n,
|
|
15497
|
-
behavior:
|
|
15519
|
+
behavior: pa()
|
|
15498
15520
|
})), this._syncToolbar();
|
|
15499
15521
|
}
|
|
15500
15522
|
_commitPageInput() {
|
|
@@ -15569,7 +15591,7 @@ var ra = (e) => {
|
|
|
15569
15591
|
_followThumb() {
|
|
15570
15592
|
let e = this.current();
|
|
15571
15593
|
e === this._activeThumb || !this.thumbEls || (this.thumbEls[this._activeThumb]?.classList.remove("active"), this._activeThumb = e, this.thumbEls[e]?.classList.add("active"), this.thumbEls[e]?.scrollIntoView({
|
|
15572
|
-
behavior:
|
|
15594
|
+
behavior: pa(),
|
|
15573
15595
|
block: "nearest"
|
|
15574
15596
|
}));
|
|
15575
15597
|
}
|
|
@@ -15616,7 +15638,7 @@ var ra = (e) => {
|
|
|
15616
15638
|
let r = this.search.index?.[e - 1]?.items, i = this.search.open ? this.search.byPage?.get(e) ?? [] : [], a = this.search.marked.get(e) ?? /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set();
|
|
15617
15639
|
r && i.length && r.forEach((e, t) => {
|
|
15618
15640
|
let r = Vi(e, i);
|
|
15619
|
-
!r.length || !n[t] || (o.add(t),
|
|
15641
|
+
!r.length || !n[t] || (o.add(t), ua(n[t], r, this.search.current));
|
|
15620
15642
|
});
|
|
15621
15643
|
for (let e of a) !o.has(e) && n[e] && n[e].replaceChildren(n[e].textContent);
|
|
15622
15644
|
o.size ? this.search.marked.set(e, o) : this.search.marked.delete(e);
|
|
@@ -15650,7 +15672,7 @@ var ra = (e) => {
|
|
|
15650
15672
|
e.preventDefault();
|
|
15651
15673
|
return;
|
|
15652
15674
|
}
|
|
15653
|
-
if (e.shiftKey ||
|
|
15675
|
+
if (e.shiftKey || oa(e.target)) return;
|
|
15654
15676
|
let t = this.cols();
|
|
15655
15677
|
if (e.key === "PageDown") this.goToPage(this.current() + t);
|
|
15656
15678
|
else if (e.key === "PageUp") this.goToPage(this.current() - t);
|
|
@@ -15710,7 +15732,7 @@ var ra = (e) => {
|
|
|
15710
15732
|
}), this.printRun !== e) throw new DOMException("Print replaced", "AbortError");
|
|
15711
15733
|
}
|
|
15712
15734
|
let n = document.createElement("iframe");
|
|
15713
|
-
n.className = "wui-file-viewer-print-frame", n.title = "Document for printing", n.tabIndex = -1, n.setAttribute("aria-hidden", "true"), e.frame = n, n.srcdoc =
|
|
15735
|
+
n.className = "wui-file-viewer-print-frame", n.title = "Document for printing", n.tabIndex = -1, n.setAttribute("aria-hidden", "true"), e.frame = n, n.srcdoc = la(this.shell.name(), t), n.addEventListener("load", () => {
|
|
15714
15736
|
if (this.printRun === e) {
|
|
15715
15737
|
e.ready = !0, this._syncToolbar();
|
|
15716
15738
|
try {
|
|
@@ -15745,12 +15767,12 @@ var ra = (e) => {
|
|
|
15745
15767
|
console.warn(`[wui-file-viewer] ${e}:`, t?.message ?? t);
|
|
15746
15768
|
}
|
|
15747
15769
|
};
|
|
15748
|
-
function
|
|
15770
|
+
function la(e, t) {
|
|
15749
15771
|
let n = [...new Set(t.map((e) => `${e.width.toFixed(2)}mm ${e.height.toFixed(2)}mm`))], r = n.map((e, t) => `@page s${t} { size: ${e}; margin: 0; }`).join("\n"), i = t.map((e) => {
|
|
15750
15772
|
let t = `s${n.indexOf(`${e.width.toFixed(2)}mm ${e.height.toFixed(2)}mm`)}`;
|
|
15751
15773
|
return `<img src="${e.url}" alt="" style="page:${t};width:${e.width}mm;height:${e.height}mm">`;
|
|
15752
15774
|
}).join("");
|
|
15753
|
-
return `<!doctype html><html><head><title>${
|
|
15775
|
+
return `<!doctype html><html><head><title>${da(e)}</title><style>
|
|
15754
15776
|
@page { margin: 0; }
|
|
15755
15777
|
${r}
|
|
15756
15778
|
html, body { margin: 0; padding: 0; }
|
|
@@ -15758,7 +15780,7 @@ img { display: block; break-after: page; }
|
|
|
15758
15780
|
img:last-child { break-after: auto; }
|
|
15759
15781
|
</style></head><body>${i}</body></html>`;
|
|
15760
15782
|
}
|
|
15761
|
-
function
|
|
15783
|
+
function ua(e, t, n) {
|
|
15762
15784
|
let r = e.textContent, i = [], a = 0;
|
|
15763
15785
|
for (let { from: e, to: o, n: s } of t) {
|
|
15764
15786
|
e > a && i.push(document.createTextNode(r.slice(a, e)));
|
|
@@ -15767,11 +15789,11 @@ function ca(e, t, n) {
|
|
|
15767
15789
|
}
|
|
15768
15790
|
a < r.length && i.push(document.createTextNode(r.slice(a))), e.replaceChildren(...i);
|
|
15769
15791
|
}
|
|
15770
|
-
var
|
|
15771
|
-
function
|
|
15792
|
+
var da = (e) => String(e ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
15793
|
+
function fa(e) {
|
|
15772
15794
|
let t = [...e].sort((e, t) => e - t);
|
|
15773
15795
|
return t[Math.floor(t.length / 2)];
|
|
15774
15796
|
}
|
|
15775
|
-
var
|
|
15797
|
+
var pa = () => window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth";
|
|
15776
15798
|
//#endregion
|
|
15777
|
-
export {
|
|
15799
|
+
export { ca as PdfView, ia as renderFirstPage };
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A failed chat request. `message` is written for the person and is safe to show as-is.
|
|
3
|
+
*/
|
|
4
|
+
export declare class ChatApiError extends Error {
|
|
5
|
+
code: string;
|
|
6
|
+
status: number;
|
|
7
|
+
resetsAtUtc: string;
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} code Machine-readable reason: the server's code (`daily-limit`,
|
|
10
|
+
* `assistant-unavailable`, ...), "network" when no response arrived, "aborted" when the
|
|
11
|
+
* request was cancelled, or "unknown".
|
|
12
|
+
* @param {string} message The sentence to show the person.
|
|
13
|
+
* @param {number} [status] HTTP status, when a response arrived.
|
|
14
|
+
* @param {string|null} [resetsAtUtc] For `daily-limit`: when the allowance comes back, in UTC.
|
|
15
|
+
*/
|
|
16
|
+
constructor(code: string, message: string, status?: number, resetsAtUtc?: string | null);
|
|
17
|
+
}
|
|
18
|
+
export type ChatHttp = {
|
|
19
|
+
get: (url: string, config?: object) => Promise<{
|
|
20
|
+
data: any;
|
|
21
|
+
}>;
|
|
22
|
+
post: (url: string, data?: any, config?: object) => Promise<{
|
|
23
|
+
data: any;
|
|
24
|
+
}>;
|
|
25
|
+
put: (url: string, data?: any, config?: object) => Promise<{
|
|
26
|
+
data: any;
|
|
27
|
+
}>;
|
|
28
|
+
delete: (url: string, config?: object) => Promise<{
|
|
29
|
+
data: any;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
export type SupportAction = {
|
|
33
|
+
/**
|
|
34
|
+
* Sent back by the confirm button; nothing happens without it.
|
|
35
|
+
*/
|
|
36
|
+
token: string;
|
|
37
|
+
kind: "RaiseTicket" | "Reply" | "Reopen";
|
|
38
|
+
ticketId: string | null;
|
|
39
|
+
ticketNumber: string | null;
|
|
40
|
+
category: string | null;
|
|
41
|
+
subject: string | null;
|
|
42
|
+
body: string | null;
|
|
43
|
+
expiresDateTimeUtc: string;
|
|
44
|
+
};
|
|
45
|
+
export type ChatTurnInput = {
|
|
46
|
+
/**
|
|
47
|
+
* The person's question.
|
|
48
|
+
*/
|
|
49
|
+
message: string;
|
|
50
|
+
/**
|
|
51
|
+
* The conversation to continue; left out to start one.
|
|
52
|
+
*/
|
|
53
|
+
conversationId?: string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Product-defined context about the screen, passed through as-is.
|
|
56
|
+
*/
|
|
57
|
+
pageContext?: any;
|
|
58
|
+
};
|
|
59
|
+
export type ChatStreamOptions = {
|
|
60
|
+
/**
|
|
61
|
+
* Cancels the request.
|
|
62
|
+
*/
|
|
63
|
+
signal?: AbortSignal;
|
|
64
|
+
/**
|
|
65
|
+
* Called for each event
|
|
66
|
+
* before the end of the turn: `delta { text }` to append, `reset {}` to discard what was shown,
|
|
67
|
+
* `actions { actions }` for support cards.
|
|
68
|
+
*/
|
|
69
|
+
onEvent?: (name: "delta" | "reset" | "actions", data: any) => void;
|
|
70
|
+
};
|
|
71
|
+
export type ChatTurnResult = {
|
|
72
|
+
conversationId: string;
|
|
73
|
+
/**
|
|
74
|
+
* The stored reply's id, for rating; null when storing failed.
|
|
75
|
+
*/
|
|
76
|
+
messageId: string | null;
|
|
77
|
+
/**
|
|
78
|
+
* The reply of record. It replaces whatever was streamed.
|
|
79
|
+
*/
|
|
80
|
+
reply: string;
|
|
81
|
+
/**
|
|
82
|
+
* Null when the person has no daily limit.
|
|
83
|
+
*/
|
|
84
|
+
messagesLeftToday: number | null;
|
|
85
|
+
};
|
|
86
|
+
export type ConversationSummary = {
|
|
87
|
+
publicId: string;
|
|
88
|
+
title: string | null;
|
|
89
|
+
createdDateTimeUtc: string;
|
|
90
|
+
lastMessageDateTimeUtc: string;
|
|
91
|
+
};
|
|
92
|
+
export type ConversationMessage = {
|
|
93
|
+
publicId: string;
|
|
94
|
+
role: "User" | "Assistant";
|
|
95
|
+
content: string;
|
|
96
|
+
/**
|
|
97
|
+
* The support actions offered with an assistant reply, as a JSON array.
|
|
98
|
+
*/
|
|
99
|
+
actionsJson: string | null;
|
|
100
|
+
rating: "Up" | "Down" | null;
|
|
101
|
+
ratingNote: string | null;
|
|
102
|
+
createdDateTimeUtc: string;
|
|
103
|
+
};
|
|
104
|
+
export type Conversation = {
|
|
105
|
+
publicId: string;
|
|
106
|
+
title: string | null;
|
|
107
|
+
messages: ConversationMessage[];
|
|
108
|
+
};
|
|
109
|
+
export type ChatClient = {
|
|
110
|
+
sendMessage: (input: ChatTurnInput, options?: ChatStreamOptions) => Promise<ChatTurnResult>;
|
|
111
|
+
getAllowance: () => Promise<{
|
|
112
|
+
messagesLeftToday: number | null;
|
|
113
|
+
}>;
|
|
114
|
+
listConversations: (query?: {
|
|
115
|
+
skip?: number;
|
|
116
|
+
take?: number;
|
|
117
|
+
}) => Promise<ConversationSummary[]>;
|
|
118
|
+
getConversation: (id: string) => Promise<Conversation>;
|
|
119
|
+
deleteConversation: (id: string) => Promise<void>;
|
|
120
|
+
rateMessage: (conversationId: string, messageId: string, input: {
|
|
121
|
+
rating: "Up" | "Down";
|
|
122
|
+
note?: string | null;
|
|
123
|
+
}) => Promise<void>;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* @typedef {object} ChatHttp An axios instance (or axios-compatible) that already carries the
|
|
127
|
+
* bearer token, tenant headers and refresh. The streamed turn needs axios's XHR adapter (the
|
|
128
|
+
* browser default) to read the reply as it arrives.
|
|
129
|
+
* @property {(url: string, config?: object) => Promise<{ data: any }>} get
|
|
130
|
+
* @property {(url: string, data?: any, config?: object) => Promise<{ data: any }>} post
|
|
131
|
+
* @property {(url: string, data?: any, config?: object) => Promise<{ data: any }>} put
|
|
132
|
+
* @property {(url: string, config?: object) => Promise<{ data: any }>} delete
|
|
133
|
+
*/
|
|
134
|
+
/**
|
|
135
|
+
* @typedef {object} SupportAction An action the assistant prepared for the person to confirm.
|
|
136
|
+
* @property {string} token Sent back by the confirm button; nothing happens without it.
|
|
137
|
+
* @property {"RaiseTicket"|"Reply"|"Reopen"} kind
|
|
138
|
+
* @property {string|null} ticketId
|
|
139
|
+
* @property {string|null} ticketNumber
|
|
140
|
+
* @property {string|null} category
|
|
141
|
+
* @property {string|null} subject
|
|
142
|
+
* @property {string|null} body
|
|
143
|
+
* @property {string} expiresDateTimeUtc
|
|
144
|
+
*/
|
|
145
|
+
/**
|
|
146
|
+
* @typedef {object} ChatTurnInput
|
|
147
|
+
* @property {string} message The person's question.
|
|
148
|
+
* @property {string|null} [conversationId] The conversation to continue; left out to start one.
|
|
149
|
+
* @property {any} [pageContext] Product-defined context about the screen, passed through as-is.
|
|
150
|
+
*/
|
|
151
|
+
/**
|
|
152
|
+
* @typedef {object} ChatStreamOptions
|
|
153
|
+
* @property {AbortSignal} [signal] Cancels the request.
|
|
154
|
+
* @property {(name: "delta"|"reset"|"actions", data: any) => void} [onEvent] Called for each event
|
|
155
|
+
* before the end of the turn: `delta { text }` to append, `reset {}` to discard what was shown,
|
|
156
|
+
* `actions { actions }` for support cards.
|
|
157
|
+
*/
|
|
158
|
+
/**
|
|
159
|
+
* @typedef {object} ChatTurnResult The `done` event: the turn's outcome of record.
|
|
160
|
+
* @property {string} conversationId
|
|
161
|
+
* @property {string|null} messageId The stored reply's id, for rating; null when storing failed.
|
|
162
|
+
* @property {string} reply The reply of record. It replaces whatever was streamed.
|
|
163
|
+
* @property {number|null} messagesLeftToday Null when the person has no daily limit.
|
|
164
|
+
*/
|
|
165
|
+
/**
|
|
166
|
+
* @typedef {object} ConversationSummary
|
|
167
|
+
* @property {string} publicId
|
|
168
|
+
* @property {string|null} title
|
|
169
|
+
* @property {string} createdDateTimeUtc
|
|
170
|
+
* @property {string} lastMessageDateTimeUtc
|
|
171
|
+
*/
|
|
172
|
+
/**
|
|
173
|
+
* @typedef {object} ConversationMessage
|
|
174
|
+
* @property {string} publicId
|
|
175
|
+
* @property {"User"|"Assistant"} role
|
|
176
|
+
* @property {string} content
|
|
177
|
+
* @property {string|null} actionsJson The support actions offered with an assistant reply, as a JSON array.
|
|
178
|
+
* @property {"Up"|"Down"|null} rating
|
|
179
|
+
* @property {string|null} ratingNote
|
|
180
|
+
* @property {string} createdDateTimeUtc
|
|
181
|
+
*/
|
|
182
|
+
/**
|
|
183
|
+
* @typedef {object} Conversation
|
|
184
|
+
* @property {string} publicId
|
|
185
|
+
* @property {string|null} title
|
|
186
|
+
* @property {ConversationMessage[]} messages
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* @typedef {object} ChatClient
|
|
190
|
+
* @property {(input: ChatTurnInput, options?: ChatStreamOptions) => Promise<ChatTurnResult>} sendMessage
|
|
191
|
+
* @property {() => Promise<{ messagesLeftToday: number|null }>} getAllowance
|
|
192
|
+
* @property {(query?: { skip?: number, take?: number }) => Promise<ConversationSummary[]>} listConversations
|
|
193
|
+
* @property {(id: string) => Promise<Conversation>} getConversation
|
|
194
|
+
* @property {(id: string) => Promise<void>} deleteConversation
|
|
195
|
+
* @property {(conversationId: string, messageId: string, input: { rating: "Up"|"Down", note?: string|null }) => Promise<void>} rateMessage
|
|
196
|
+
*/
|
|
197
|
+
/**
|
|
198
|
+
* Binds the chat HTTP contract to the product's own authenticated axios instance. The package
|
|
199
|
+
* never handles auth: tokens, tenant headers and refresh stay in the instance.
|
|
200
|
+
*
|
|
201
|
+
* @param {ChatHttp} http
|
|
202
|
+
* @param {{ base: string }} options `base` is the prefix the API maps the chat endpoints under,
|
|
203
|
+
* e.g. "/api/assistant" for `POST /api/assistant/chat`.
|
|
204
|
+
* @returns {ChatClient}
|
|
205
|
+
*/
|
|
206
|
+
export declare function createChatClient(http: ChatHttp, { base }: {
|
|
207
|
+
base: string;
|
|
208
|
+
}): ChatClient;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every word the chat components show, in English. Pass a `labels` object with any subset to a
|
|
3
|
+
* component to change its wording; the rest keep these defaults. The few that take a value are
|
|
4
|
+
* functions.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_CHAT_LABELS: Readonly<{
|
|
7
|
+
launcher: "Ask the assistant";
|
|
8
|
+
panelTitle: "Assistant";
|
|
9
|
+
newChat: "New chat";
|
|
10
|
+
close: "Close";
|
|
11
|
+
thread: "Conversation";
|
|
12
|
+
you: "You";
|
|
13
|
+
assistant: "Assistant";
|
|
14
|
+
thinking: "Thinking";
|
|
15
|
+
emptyTitle: "How can I help?";
|
|
16
|
+
emptyText: "Ask a question about what you see on this page.";
|
|
17
|
+
composer: "Your question";
|
|
18
|
+
placeholder: "Ask a question";
|
|
19
|
+
send: "Send";
|
|
20
|
+
composerHint: "Press Enter to send, Shift and Enter for a new line.";
|
|
21
|
+
/** @type {(count: number) => string} */
|
|
22
|
+
allowance: (count: number) => string;
|
|
23
|
+
disclaimer: "Answers are written by AI and can be wrong. Check anything important.";
|
|
24
|
+
loadingConversation: "Loading the conversation";
|
|
25
|
+
rateUp: "Helpful";
|
|
26
|
+
rateDown: "Not helpful";
|
|
27
|
+
rated: "Thanks for the feedback.";
|
|
28
|
+
ratingNote: "What was wrong with this answer?";
|
|
29
|
+
ratingNoteHint: "Optional.";
|
|
30
|
+
ratingNoteSend: "Send";
|
|
31
|
+
ratingNoteSkip: "Skip";
|
|
32
|
+
ratingFailed: "Your rating did not save. Please try again.";
|
|
33
|
+
actionRaiseTicket: "New support ticket";
|
|
34
|
+
/** @type {(ticketNumber: string) => string} */
|
|
35
|
+
actionReply: (ticketNumber: string) => string;
|
|
36
|
+
/** @type {(ticketNumber: string) => string} */
|
|
37
|
+
actionReopen: (ticketNumber: string) => string;
|
|
38
|
+
actionNote: "Nothing is sent until you confirm.";
|
|
39
|
+
actionConfirm: "Confirm";
|
|
40
|
+
actionDismiss: "Not now";
|
|
41
|
+
actionDismissed: "Not sent.";
|
|
42
|
+
actionExpired: "This request expired and was not sent. Ask again if you still need it.";
|
|
43
|
+
actionFailed: "We could not send this. Please try again.";
|
|
44
|
+
/** @type {(ticketNumber: string) => string} */
|
|
45
|
+
actionDoneRaiseTicket: (ticketNumber: string) => string;
|
|
46
|
+
/** @type {(ticketNumber: string) => string} */
|
|
47
|
+
actionDoneReply: (ticketNumber: string) => string;
|
|
48
|
+
/** @type {(ticketNumber: string) => string} */
|
|
49
|
+
actionDoneReopen: (ticketNumber: string) => string;
|
|
50
|
+
viewTicket: "View ticket";
|
|
51
|
+
conversations: "Past chats";
|
|
52
|
+
conversationsEmptyTitle: "No past chats";
|
|
53
|
+
conversationsEmptyText: "Your conversations with the assistant show here.";
|
|
54
|
+
untitled: "Untitled chat";
|
|
55
|
+
deleteConversation: "Delete chat";
|
|
56
|
+
deleteConfirmTitle: "Delete this chat?";
|
|
57
|
+
deleteConfirmMessage: "The conversation is removed for good.";
|
|
58
|
+
deleteConfirm: "Delete";
|
|
59
|
+
deleteFailed: "We could not delete this chat. Please try again.";
|
|
60
|
+
cancel: "Cancel";
|
|
61
|
+
loadMore: "Show more";
|
|
62
|
+
loadFailed: "We could not load your chats. Please try again.";
|
|
63
|
+
retry: "Try again";
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* @param {Partial<typeof DEFAULT_CHAT_LABELS>} [labels]
|
|
67
|
+
* @returns {typeof DEFAULT_CHAT_LABELS}
|
|
68
|
+
*/
|
|
69
|
+
export declare function mergeLabels(labels?: Partial<typeof DEFAULT_CHAT_LABELS>): typeof DEFAULT_CHAT_LABELS;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export type MarkdownBlockShape = {
|
|
2
|
+
type: "paragraph";
|
|
3
|
+
lines: string[];
|
|
4
|
+
} | {
|
|
5
|
+
type: "heading";
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: "list";
|
|
9
|
+
ordered: boolean;
|
|
10
|
+
start: number;
|
|
11
|
+
items: string[];
|
|
12
|
+
} | {
|
|
13
|
+
type: "table";
|
|
14
|
+
header: string[];
|
|
15
|
+
rows: string[][];
|
|
16
|
+
} | {
|
|
17
|
+
type: "code";
|
|
18
|
+
text: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: "rule";
|
|
21
|
+
};
|
|
22
|
+
export type MarkdownBlock = MarkdownBlockShape & {
|
|
23
|
+
key: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {{ type: "paragraph", lines: string[] }
|
|
27
|
+
* | { type: "heading", text: string }
|
|
28
|
+
* | { type: "list", ordered: boolean, start: number, items: string[] }
|
|
29
|
+
* | { type: "table", header: string[], rows: string[][] }
|
|
30
|
+
* | { type: "code", text: string }
|
|
31
|
+
* | { type: "rule" }} MarkdownBlockShape
|
|
32
|
+
* @typedef {MarkdownBlockShape & { key: number }} MarkdownBlock
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Splits reply text into blocks. Each block's `key` is its position, so text arriving at the end
|
|
36
|
+
* of a streaming reply updates the last block in place and never remounts the ones before it.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} text
|
|
39
|
+
* @returns {MarkdownBlock[]}
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseBlocks(text: string): MarkdownBlock[];
|
|
42
|
+
export type InlineToken = {
|
|
43
|
+
type: "text";
|
|
44
|
+
text: string;
|
|
45
|
+
key: number;
|
|
46
|
+
} | {
|
|
47
|
+
type: "code";
|
|
48
|
+
text: string;
|
|
49
|
+
key: number;
|
|
50
|
+
} | {
|
|
51
|
+
type: "strong" | "em";
|
|
52
|
+
children: InlineToken[];
|
|
53
|
+
key: number;
|
|
54
|
+
} | {
|
|
55
|
+
type: "link";
|
|
56
|
+
href: string;
|
|
57
|
+
children: InlineToken[];
|
|
58
|
+
key: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Reads bold (`**` or `__`), italics (`*` or `_`), inline code and `[label](href)` links. A marker
|
|
62
|
+
* with no partner yet (a reply still streaming) shows as the characters typed.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} text
|
|
65
|
+
* @returns {InlineToken[]}
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseInline(text: string): InlineToken[];
|
|
68
|
+
/**
|
|
69
|
+
* The in-app route a reply link may open, or null when it may not open one. Only
|
|
70
|
+
* `scheme:kind/id` hrefs reach `resolveLink`, and only a route it returns that starts with a
|
|
71
|
+
* single "/" is used.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} href
|
|
74
|
+
* @param {((href: string) => string|null|undefined)|undefined} resolveLink
|
|
75
|
+
* @returns {string|null}
|
|
76
|
+
*/
|
|
77
|
+
export declare function linkRoute(href: string, resolveLink: ((href: string) => string | null | undefined) | undefined): string | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} SseEvent
|
|
3
|
+
* @property {string} name The `event:` field, or "message" when the block names none.
|
|
4
|
+
* @property {any} data The `data:` lines joined by newlines and parsed as JSON.
|
|
5
|
+
*/
|
|
6
|
+
export type SseEvent = {
|
|
7
|
+
/**
|
|
8
|
+
* The `event:` field, or "message" when the block names none.
|
|
9
|
+
*/
|
|
10
|
+
name: string;
|
|
11
|
+
/**
|
|
12
|
+
* The `data:` lines joined by newlines and parsed as JSON.
|
|
13
|
+
*/
|
|
14
|
+
data: any;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* An incremental reader for a `text/event-stream` body that arrives in pieces. Each `push` takes
|
|
18
|
+
* the next piece of text; only complete events (ended by a blank line) are handed on, and the
|
|
19
|
+
* incomplete tail waits for the next piece. `end` flushes a final event the stream closed
|
|
20
|
+
* without a blank line after.
|
|
21
|
+
*
|
|
22
|
+
* Line endings may be `\n`, `\r\n` or `\r`, and a `\r\n` pair may be split across two pieces.
|
|
23
|
+
* Comment lines (`:`), `id` and `retry` are ignored. A block whose data is not JSON is reported
|
|
24
|
+
* as an `error` event with the code `invalid-response`, so a caller ends the turn instead of
|
|
25
|
+
* hanging on it.
|
|
26
|
+
*
|
|
27
|
+
* @param {(event: SseEvent) => void} onEvent
|
|
28
|
+
* @returns {{ push: (text: string) => void, end: () => void }}
|
|
29
|
+
*/
|
|
30
|
+
export declare function createSseParser(onEvent: (event: SseEvent) => void): {
|
|
31
|
+
push: (text: string) => void;
|
|
32
|
+
end: () => void;
|
|
33
|
+
};
|