@memberjunction/realtime-widget 6.2.0-edge.4 → 6.2.0-edge.6
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/README.md +11 -2
- package/dist/embed/chunks/UserViewEngine-IVGLM2DH.js +7 -0
- package/dist/embed/chunks/chunk-MRWWS7FK.js +162091 -0
- package/dist/embed/chunks/chunk-N3BM2W5J.js +36503 -0
- package/dist/embed/chunks/chunk-RAIOBPHZ.js +6127 -0
- package/dist/embed/chunks/chunk-S3LX5KYE.js +46 -0
- package/dist/embed/chunks/chunk-VZ6KR7K2.js +2492 -0
- package/dist/embed/chunks/chunk-ZX4SRAYD.js +17043 -0
- package/dist/embed/chunks/dist-P2JMWJFV.js +66 -0
- package/dist/embed/chunks/guest-tool-relay-GAWXNIUD.js +30 -0
- package/dist/embed/chunks/guest-voice-mint-KJMP4VTK.js +94 -0
- package/dist/embed/chunks/realtime-voice-controller-PCOD3UBR.js +30558 -0
- package/dist/embed/chunks/runtime-widget-transport-AFGCQC7N.js +161 -0
- package/dist/embed/mj-widget.js +1056 -0
- package/dist/embed.js +3 -2
- package/dist/embed.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +9 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +56 -7
- package/dist/loader.js.map +1 -1
- package/dist/session/widget-session-client.d.ts +46 -5
- package/dist/session/widget-session-client.d.ts.map +1 -1
- package/dist/session/widget-session-client.js +118 -17
- package/dist/session/widget-session-client.js.map +1 -1
- package/dist/transport/runtime-widget-transport.d.ts +0 -6
- package/dist/transport/runtime-widget-transport.d.ts.map +1 -1
- package/dist/transport/runtime-widget-transport.js +2 -31
- package/dist/transport/runtime-widget-transport.js.map +1 -1
- package/package.json +10 -10
package/dist/embed.js
CHANGED
|
@@ -15,13 +15,14 @@
|
|
|
15
15
|
* @module @memberjunction/realtime-widget
|
|
16
16
|
*/
|
|
17
17
|
import { DefineSupportWidgetElement } from './ui/support-widget-element.js';
|
|
18
|
-
import {
|
|
18
|
+
import { StartEmbeddedWidget } from './loader.js';
|
|
19
19
|
// When loaded in a browser, register the element and attempt auto-bootstrap from the host's
|
|
20
20
|
// [data-widget-key] element. No-ops cleanly server-side or when nothing matches.
|
|
21
21
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
22
22
|
DefineSupportWidgetElement();
|
|
23
23
|
const run = () => {
|
|
24
|
-
|
|
24
|
+
// StartEmbeddedWidget never rejects: a failure (e.g. a plain-http page without Web Crypto) is logged.
|
|
25
|
+
void StartEmbeddedWidget();
|
|
25
26
|
};
|
|
26
27
|
if (document.readyState === 'loading') {
|
|
27
28
|
document.addEventListener('DOMContentLoaded', run, { once: true });
|
package/dist/embed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed.js","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"embed.js","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,4FAA4F;AAC5F,iFAAiF;AACjF,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IACnE,0BAA0B,EAAE,CAAC;IAC7B,MAAM,GAAG,GAAG,GAAS,EAAE;QACnB,sGAAsG;QACtG,KAAK,mBAAmB,EAAE,CAAC;IAC/B,CAAC,CAAC;IACF,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACJ,GAAG,EAAE,CAAC;IACV,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @module @memberjunction/realtime-widget
|
|
7
7
|
*/
|
|
8
8
|
export * from './types.js';
|
|
9
|
-
export { WidgetSessionClient, type FetchLike } from './session/widget-session-client.js';
|
|
9
|
+
export { WidgetSessionClient, WidgetSessionError, type FetchLike } from './session/widget-session-client.js';
|
|
10
10
|
export type { IWidgetTransport, WidgetProgressCallback, WidgetTurnResult } from './transport/widget-transport.js';
|
|
11
11
|
export { MockWidgetTransport } from './transport/mock-widget-transport.js';
|
|
12
12
|
export { RuntimeWidgetTransport } from './transport/runtime-widget-transport.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,KAAK,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAC7G,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAClH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,YAAY,EACR,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,GACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EACH,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,eAAe,GACvB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,eAAe,EACf,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,iBAAiB,EACjB,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,GAC5B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC9G,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC/I,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @module @memberjunction/realtime-widget
|
|
7
7
|
*/
|
|
8
8
|
export * from './types.js';
|
|
9
|
-
export { WidgetSessionClient } from './session/widget-session-client.js';
|
|
9
|
+
export { WidgetSessionClient, WidgetSessionError } from './session/widget-session-client.js';
|
|
10
10
|
export { MockWidgetTransport } from './transport/mock-widget-transport.js';
|
|
11
11
|
export { RuntimeWidgetTransport } from './transport/runtime-widget-transport.js';
|
|
12
12
|
export { MockVoiceController } from './voice/mock-voice-controller.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAkB,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAkB,MAAM,oCAAoC,CAAC;AAE7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAOjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EACH,uBAAuB,GAG1B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,eAAe,EACf,oBAAoB,GAGvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACH,iBAAiB,GAGpB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAA+B,MAAM,yCAAyC,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC9G,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC/I,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,qBAAqB,EAAE,qBAAqB,EAAwB,MAAM,aAAa,CAAC;AAE3H,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,qFAAqF;AACrF,wFAAwF;AACxF,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;IACnE,0BAA0B,EAAE,CAAC;IAC7B,MAAM,GAAG,GAAG,GAAS,EAAE;QACnB,KAAK,qBAAqB,EAAE,CAAC;IACjC,CAAC,CAAC;IACF,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACJ,GAAG,EAAE,CAAC;IACV,CAAC;AACL,CAAC"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -31,6 +31,15 @@ export declare function MountWidget(options: WidgetMountOptions, deps?: WidgetMo
|
|
|
31
31
|
export declare function mountWidget(options: WidgetMountOptions, deps?: WidgetMountDeps): Promise<SupportWidgetElement>;
|
|
32
32
|
/** Reads data-attributes from the host and mounts. Safe to call once on script load. */
|
|
33
33
|
export declare function BootstrapFromDocument(doc?: Document): Promise<SupportWidgetElement | null>;
|
|
34
|
+
/**
|
|
35
|
+
* What the embed bundle runs on load: {@link BootstrapFromDocument}, with any failure reported on the console
|
|
36
|
+
* instead of left as an unhandled rejection. The host page has nobody else to tell. Never rejects.
|
|
37
|
+
*
|
|
38
|
+
* The widget signs its session refreshes with a Web Crypto key, and browsers expose Web Crypto (`crypto.subtle`)
|
|
39
|
+
* only in a secure context (HTTPS, or localhost). On a plain-http page the widget cannot start, by design (there is
|
|
40
|
+
* no fallback without proof of possession), so that case gets a message the site owner can act on.
|
|
41
|
+
*/
|
|
42
|
+
export declare function StartEmbeddedWidget(doc?: Document): Promise<void>;
|
|
34
43
|
/** @deprecated Use {@link BootstrapFromDocument}. */
|
|
35
44
|
export declare function bootstrapFromDocument(doc?: Document): Promise<SupportWidgetElement | null>;
|
|
36
45
|
//# sourceMappingURL=loader.d.ts.map
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAsB,MAAM,oCAAoC,CAAC;AAE7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAA+C,MAAM,gCAAgC,CAAC;AAEnH,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC5B,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,mBAAmB,CAAC;IAClF,6HAA6H;IAC7H,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpF,4IAA4I;IAC5I,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClG,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2CxH;AAED,2CAA2C;AAC3C,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAExH;AAED,wFAAwF;AACxF,wBAAsB,qBAAqB,CAAC,GAAG,GAAE,QAAmB,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAe1G;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,GAAE,QAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAajF;AAED,qDAAqD;AACrD,wBAAsB,qBAAqB,CAAC,GAAG,GAAE,QAAmB,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAE1G"}
|
package/dist/loader.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module @memberjunction/realtime-widget
|
|
9
9
|
*/
|
|
10
|
-
import { WidgetSessionClient } from './session/widget-session-client.js';
|
|
10
|
+
import { WidgetSessionClient, WidgetSessionError } from './session/widget-session-client.js';
|
|
11
11
|
import { ReadVisitorKey, WriteVisitorKey, ClearVisitorKey } from './session/visitor-key-cookie.js';
|
|
12
12
|
import { DEFAULT_VOICE_LIMITS } from './voice/voice-abuse-guard.js';
|
|
13
13
|
import { DefineSupportWidgetElement, WIDGET_TAG_NAME } from './ui/support-widget-element.js';
|
|
@@ -72,6 +72,26 @@ export async function BootstrapFromDocument(doc = document) {
|
|
|
72
72
|
greeting: mountEl.dataset.greeting,
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* What the embed bundle runs on load: {@link BootstrapFromDocument}, with any failure reported on the console
|
|
77
|
+
* instead of left as an unhandled rejection. The host page has nobody else to tell. Never rejects.
|
|
78
|
+
*
|
|
79
|
+
* The widget signs its session refreshes with a Web Crypto key, and browsers expose Web Crypto (`crypto.subtle`)
|
|
80
|
+
* only in a secure context (HTTPS, or localhost). On a plain-http page the widget cannot start, by design (there is
|
|
81
|
+
* no fallback without proof of possession), so that case gets a message the site owner can act on.
|
|
82
|
+
*/
|
|
83
|
+
export async function StartEmbeddedWidget(doc = document) {
|
|
84
|
+
try {
|
|
85
|
+
await BootstrapFromDocument(doc);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (typeof crypto === 'undefined' || !crypto.subtle) {
|
|
89
|
+
console.error('[mj-widget] The support widget needs a secure context (HTTPS, or localhost) for the Web Crypto API, which this page does not have, so it is not shown. Serve the page over HTTPS.', error);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.error('[mj-widget] Could not start the support widget:', error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
75
95
|
/** @deprecated Use {@link BootstrapFromDocument}. */
|
|
76
96
|
export async function bootstrapFromDocument(doc = document) {
|
|
77
97
|
return BootstrapFromDocument(doc);
|
|
@@ -155,17 +175,46 @@ function scheduleRefresh(client, transport, element, session, scheduler) {
|
|
|
155
175
|
scheduler(() => {
|
|
156
176
|
void (async () => {
|
|
157
177
|
try {
|
|
158
|
-
const refreshed = await client.Refresh(session.visitorKey);
|
|
178
|
+
const refreshed = await client.Refresh(session.token, session.visitorKey);
|
|
159
179
|
transport.UpdateToken(refreshed.token);
|
|
160
180
|
scheduleRefresh(client, transport, element, refreshed, scheduler);
|
|
161
181
|
}
|
|
162
|
-
catch {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (error instanceof WidgetSessionError && error.IsRefused) {
|
|
184
|
+
// The server will never renew this session (past the grace window, past its hard end,
|
|
185
|
+
// or minted before key-bound refresh), so retrying it cannot work: start a new one.
|
|
186
|
+
await restartSession(client, transport, element, session, scheduler);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
showRefreshRetry(client, transport, element, session, scheduler);
|
|
167
190
|
}
|
|
168
191
|
})();
|
|
169
192
|
}, delay);
|
|
170
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Mints a new session after the server refused to renew `previous`, and moves the transport and element onto it.
|
|
196
|
+
* The visitor gets a new `mj_sid`, so the previous conversation is no longer readable and a new one starts; a
|
|
197
|
+
* widget that remembers returning visitors still chains it to the previous one through the visitor key.
|
|
198
|
+
*/
|
|
199
|
+
async function restartSession(client, transport, element, previous, scheduler) {
|
|
200
|
+
try {
|
|
201
|
+
const fresh = await client.Mint(previous.visitorKey);
|
|
202
|
+
await transport.Initialize(fresh);
|
|
203
|
+
element.SetSession(fresh);
|
|
204
|
+
element.ShowSystemMessage('Your previous chat ended. You can start a new one.');
|
|
205
|
+
scheduleRefresh(client, transport, element, fresh, scheduler);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.error('[mj-widget] Could not start a new session after the previous one was refused:', error);
|
|
209
|
+
showRefreshRetry(client, transport, element, previous, scheduler);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* A temporary failure leaves the current (soon-to-expire) token. Surface the connection-lost banner so the
|
|
214
|
+
* visitor can retry the refresh; on success the banner clears and the refresh timer re-arms (graceful
|
|
215
|
+
* degradation, W6). A refused retry goes on to start a new session.
|
|
216
|
+
*/
|
|
217
|
+
function showRefreshRetry(client, transport, element, session, scheduler) {
|
|
218
|
+
element.ShowConnectionError('Connection to support was lost.', () => scheduleRefresh(client, transport, element, session, scheduler));
|
|
219
|
+
}
|
|
171
220
|
//# sourceMappingURL=loader.js.map
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,17 @@ export type FetchLike = (input: string, init?: RequestInit) => Promise<{
|
|
|
13
13
|
status: number;
|
|
14
14
|
json: () => Promise<unknown>;
|
|
15
15
|
}>;
|
|
16
|
+
/** A session endpoint answered with a failure. `Status` is the HTTP status, `Code` the server's `errorCode`. */
|
|
17
|
+
export declare class WidgetSessionError extends Error {
|
|
18
|
+
readonly Status: number;
|
|
19
|
+
readonly Code: string | null;
|
|
20
|
+
constructor(message: string, Status: number, Code: string | null);
|
|
21
|
+
/**
|
|
22
|
+
* True when the server refused for good (401/403): retrying the same request cannot succeed, so the
|
|
23
|
+
* caller must start a new session. Rate limits (429), server faults (5xx) and network failures are temporary.
|
|
24
|
+
*/
|
|
25
|
+
get IsRefused(): boolean;
|
|
26
|
+
}
|
|
16
27
|
/**
|
|
17
28
|
* Talks to the widget guest-session endpoints. One instance per mounted widget.
|
|
18
29
|
*/
|
|
@@ -20,6 +31,21 @@ export declare class WidgetSessionClient {
|
|
|
20
31
|
private readonly apiUrl;
|
|
21
32
|
private readonly widgetKey;
|
|
22
33
|
private readonly fetchImpl;
|
|
34
|
+
/**
|
|
35
|
+
* The key the current session is bound to: created at each mint, held only in memory, and never
|
|
36
|
+
* exportable. The server signs its thumbprint into the token, and refresh must be signed with it, so a
|
|
37
|
+
* token copied off this page cannot be renewed elsewhere.
|
|
38
|
+
*/
|
|
39
|
+
private proofKey;
|
|
40
|
+
/**
|
|
41
|
+
* How far the server's clock is ahead of this browser's (ms), learned from the `iat` of each token the server
|
|
42
|
+
* issues. A visitor's device clock can be minutes off, and the server refuses a refresh proof more than 60 s
|
|
43
|
+
* from its own time, so the proof's `iat` and the refresh timer both run on server time. The token's `iat`
|
|
44
|
+
* rather than the HTTP `Date` header, because a cross-origin embed cannot read `Date` (not CORS-safelisted).
|
|
45
|
+
* `WidgetKeyClient` (`@memberjunction/ng-realtime-widget`) does the same; the two packages share no code, so
|
|
46
|
+
* the duplication is deliberate.
|
|
47
|
+
*/
|
|
48
|
+
private serverOffsetMs;
|
|
23
49
|
constructor(apiUrl: string, widgetKey: string, fetchImpl?: FetchLike);
|
|
24
50
|
/**
|
|
25
51
|
* Mints a fresh guest session. Throws on a non-2xx / unsuccessful response.
|
|
@@ -28,9 +54,10 @@ export declare class WidgetSessionClient {
|
|
|
28
54
|
* RememberReturningVisitors toggle). Omit on a first visit; the server mints one when remembering is on.
|
|
29
55
|
*/
|
|
30
56
|
Mint(visitorKey?: string): Promise<WidgetSession>;
|
|
31
|
-
/** Refreshes the guest session (server re-mints by the same key
|
|
32
|
-
* refreshed session keeps the same
|
|
33
|
-
|
|
57
|
+
/** Refreshes the guest session (server re-mints by the same key while verifying the current token to
|
|
58
|
+
* preserve `mj_sid`). Carries the visitor anchor so the refreshed session keeps the same
|
|
59
|
+
* returning-visitor identity. */
|
|
60
|
+
Refresh(currentToken: string, visitorKey?: string): Promise<WidgetSession>;
|
|
34
61
|
/**
|
|
35
62
|
* W5 magic-link upgrade ("Verify it's you"): asks the server to email a verification link scoped to
|
|
36
63
|
* the widget's app. On success the visitor receives an email; clicking it redeems a VERIFIED session
|
|
@@ -64,10 +91,24 @@ export declare class WidgetSessionClient {
|
|
|
64
91
|
mergedConversations?: number;
|
|
65
92
|
error?: string;
|
|
66
93
|
}>;
|
|
67
|
-
/** Milliseconds until the given session should be refreshed (
|
|
94
|
+
/** Milliseconds until the given session should be refreshed (at least {@link MIN_REFRESH_DELAY_MS}). */
|
|
68
95
|
static MsUntilRefresh(session: WidgetSession, nowMs: number): number;
|
|
96
|
+
/**
|
|
97
|
+
* POSTs to a session endpoint. A mint (no `bearerToken`) registers `key`'s public half; a refresh sends the
|
|
98
|
+
* token and a proof signed by `key` for this URL and token.
|
|
99
|
+
*/
|
|
69
100
|
private call;
|
|
70
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Records the server's clock offset from a token it just issued (`iat` is its "now"). The offset is off by the
|
|
103
|
+
* response's one-way latency, far inside the server's 60 s window. A token without a readable `iat` keeps the
|
|
104
|
+
* previous offset: the server stamps `iat` on every token it signs, so this is never a guess about server time.
|
|
105
|
+
*/
|
|
106
|
+
private learnServerOffset;
|
|
107
|
+
/**
|
|
108
|
+
* Maps the API response to the in-memory session, validating required fields. `expiresAtMs` is put on this
|
|
109
|
+
* browser's clock (the server's expiry less the learned offset), so `expiresAtMs - Date.now()` is the time the
|
|
110
|
+
* token really has left even on a device whose clock is off.
|
|
111
|
+
*/
|
|
71
112
|
private toSession;
|
|
72
113
|
private trimmedApiUrl;
|
|
73
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-session-client.d.ts","sourceRoot":"","sources":["../../src/session/widget-session-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"widget-session-client.d.ts","sourceRoot":"","sources":["../../src/session/widget-session-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAkB,aAAa,EAAyB,MAAM,aAAa,CAAC;AAExF,mGAAmG;AACnG,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC;IACnE,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAChC,CAAC,CAAC;AAEH,gHAAgH;AAChH,qBAAa,kBAAmB,SAAQ,KAAK;aAGrB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM,GAAG,IAAI;gBAFnC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,IAAI;IAMvC;;;OAGG;IACH,IAAW,SAAS,IAAI,OAAO,CAE9B;CACJ;AAYD;;GAEG;AACH,qBAAa,mBAAmB;IAmBxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAnB9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAqC;IACrD;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc,CAAK;gBAGN,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAClC,SAAS,CAAC,EAAE,SAAS;IAMzB;;;;;OAKG;IACU,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAO9D;;sCAEkC;IACrB,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAOvF;;;;;;OAMG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiB9G;;;;OAIG;IACU,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiB9G;;;;;OAKG;IACU,eAAe,CACxB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiB9E,wGAAwG;WAC1F,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAI3E;;;OAGG;YACW,IAAI;IA2BlB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,aAAa;CAGxB"}
|
|
@@ -6,8 +6,31 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module @memberjunction/realtime-widget
|
|
8
8
|
*/
|
|
9
|
+
import { CreateProofOfPossessionJwt, CreateProofOfPossessionKey } from '@memberjunction/global';
|
|
10
|
+
/** A session endpoint answered with a failure. `Status` is the HTTP status, `Code` the server's `errorCode`. */
|
|
11
|
+
export class WidgetSessionError extends Error {
|
|
12
|
+
constructor(message, Status, Code) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.Status = Status;
|
|
15
|
+
this.Code = Code;
|
|
16
|
+
this.name = 'WidgetSessionError';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* True when the server refused for good (401/403): retrying the same request cannot succeed, so the
|
|
20
|
+
* caller must start a new session. Rate limits (429), server faults (5xx) and network failures are temporary.
|
|
21
|
+
*/
|
|
22
|
+
get IsRefused() {
|
|
23
|
+
return this.Status === 401 || this.Status === 403;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
9
26
|
/** How early (ms before expiry) to proactively refresh the guest token. */
|
|
10
27
|
const REFRESH_LEAD_MS = 60_000;
|
|
28
|
+
/**
|
|
29
|
+
* The shortest wait before a refresh. A token already inside the lead (the client's clock ahead of the server's)
|
|
30
|
+
* would otherwise be refreshed in a tight loop that trips the rate limiter's 429 instead of reaching the server's 403
|
|
31
|
+
* that starts a new session.
|
|
32
|
+
*/
|
|
33
|
+
const MIN_REFRESH_DELAY_MS = 5_000;
|
|
11
34
|
/**
|
|
12
35
|
* Talks to the widget guest-session endpoints. One instance per mounted widget.
|
|
13
36
|
*/
|
|
@@ -15,6 +38,21 @@ export class WidgetSessionClient {
|
|
|
15
38
|
constructor(apiUrl, widgetKey, fetchImpl) {
|
|
16
39
|
this.apiUrl = apiUrl;
|
|
17
40
|
this.widgetKey = widgetKey;
|
|
41
|
+
/**
|
|
42
|
+
* The key the current session is bound to: created at each mint, held only in memory, and never
|
|
43
|
+
* exportable. The server signs its thumbprint into the token, and refresh must be signed with it, so a
|
|
44
|
+
* token copied off this page cannot be renewed elsewhere.
|
|
45
|
+
*/
|
|
46
|
+
this.proofKey = null;
|
|
47
|
+
/**
|
|
48
|
+
* How far the server's clock is ahead of this browser's (ms), learned from the `iat` of each token the server
|
|
49
|
+
* issues. A visitor's device clock can be minutes off, and the server refuses a refresh proof more than 60 s
|
|
50
|
+
* from its own time, so the proof's `iat` and the refresh timer both run on server time. The token's `iat`
|
|
51
|
+
* rather than the HTTP `Date` header, because a cross-origin embed cannot read `Date` (not CORS-safelisted).
|
|
52
|
+
* `WidgetKeyClient` (`@memberjunction/ng-realtime-widget`) does the same; the two packages share no code, so
|
|
53
|
+
* the duplication is deliberate.
|
|
54
|
+
*/
|
|
55
|
+
this.serverOffsetMs = 0;
|
|
18
56
|
// happy fallback to the platform fetch; explicit in tests.
|
|
19
57
|
this.fetchImpl = fetchImpl ?? ((input, init) => fetch(input, init));
|
|
20
58
|
}
|
|
@@ -25,12 +63,19 @@ export class WidgetSessionClient {
|
|
|
25
63
|
* RememberReturningVisitors toggle). Omit on a first visit; the server mints one when remembering is on.
|
|
26
64
|
*/
|
|
27
65
|
async Mint(visitorKey) {
|
|
28
|
-
|
|
66
|
+
const key = await CreateProofOfPossessionKey();
|
|
67
|
+
const session = await this.call('/widget/session', visitorKey, undefined, key);
|
|
68
|
+
this.proofKey = key;
|
|
69
|
+
return session;
|
|
29
70
|
}
|
|
30
|
-
/** Refreshes the guest session (server re-mints by the same key
|
|
31
|
-
* refreshed session keeps the same
|
|
32
|
-
|
|
33
|
-
|
|
71
|
+
/** Refreshes the guest session (server re-mints by the same key while verifying the current token to
|
|
72
|
+
* preserve `mj_sid`). Carries the visitor anchor so the refreshed session keeps the same
|
|
73
|
+
* returning-visitor identity. */
|
|
74
|
+
async Refresh(currentToken, visitorKey) {
|
|
75
|
+
if (!this.proofKey) {
|
|
76
|
+
throw new Error('Widget session refresh needs the key registered at mint; call Mint first.');
|
|
77
|
+
}
|
|
78
|
+
return this.call('/widget/session/refresh', visitorKey, currentToken, this.proofKey);
|
|
34
79
|
}
|
|
35
80
|
/**
|
|
36
81
|
* W5 magic-link upgrade ("Verify it's you"): asks the server to email a verification link scoped to
|
|
@@ -101,23 +146,57 @@ export class WidgetSessionClient {
|
|
|
101
146
|
return { success: false, error: err instanceof Error ? err.message : 'Could not resolve identity.' };
|
|
102
147
|
}
|
|
103
148
|
}
|
|
104
|
-
/** Milliseconds until the given session should be refreshed (
|
|
149
|
+
/** Milliseconds until the given session should be refreshed (at least {@link MIN_REFRESH_DELAY_MS}). */
|
|
105
150
|
static MsUntilRefresh(session, nowMs) {
|
|
106
|
-
return Math.max(
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
151
|
+
return Math.max(MIN_REFRESH_DELAY_MS, session.expiresAtMs - nowMs - REFRESH_LEAD_MS);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* POSTs to a session endpoint. A mint (no `bearerToken`) registers `key`'s public half; a refresh sends the
|
|
155
|
+
* token and a proof signed by `key` for this URL and token.
|
|
156
|
+
*/
|
|
157
|
+
async call(path, visitorKey, bearerToken, key) {
|
|
158
|
+
const url = `${this.trimmedApiUrl()}${path}`;
|
|
159
|
+
const headers = { 'content-type': 'application/json' };
|
|
160
|
+
const request = { widgetKey: this.widgetKey };
|
|
161
|
+
if (visitorKey) {
|
|
162
|
+
request.visitorKey = visitorKey;
|
|
163
|
+
}
|
|
164
|
+
if (bearerToken) {
|
|
165
|
+
headers['authorization'] = `Bearer ${bearerToken}`;
|
|
166
|
+
headers['dpop'] = await CreateProofOfPossessionJwt(key, {
|
|
167
|
+
Method: 'POST',
|
|
168
|
+
Url: url,
|
|
169
|
+
AccessToken: bearerToken,
|
|
170
|
+
NowSeconds: Math.floor((Date.now() + this.serverOffsetMs) / 1000),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
request.proofKey = key.PublicJwk;
|
|
175
|
+
}
|
|
176
|
+
const res = await this.fetchImpl(url, { method: 'POST', headers, body: JSON.stringify(request) });
|
|
114
177
|
const body = (await res.json());
|
|
115
178
|
if (!res.ok || !body?.success || !body.token) {
|
|
116
|
-
throw new
|
|
179
|
+
throw new WidgetSessionError(`Widget session mint failed (${res.status}): ${body?.errorCode ?? body?.error ?? 'unknown'}`, res.status, body?.errorCode ?? null);
|
|
117
180
|
}
|
|
181
|
+
this.learnServerOffset(body.token);
|
|
118
182
|
return this.toSession(body);
|
|
119
183
|
}
|
|
120
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Records the server's clock offset from a token it just issued (`iat` is its "now"). The offset is off by the
|
|
186
|
+
* response's one-way latency, far inside the server's 60 s window. A token without a readable `iat` keeps the
|
|
187
|
+
* previous offset: the server stamps `iat` on every token it signs, so this is never a guess about server time.
|
|
188
|
+
*/
|
|
189
|
+
learnServerOffset(token) {
|
|
190
|
+
const iat = ReadTokenIssuedAtSeconds(token);
|
|
191
|
+
if (iat !== null) {
|
|
192
|
+
this.serverOffsetMs = iat * 1000 - Date.now();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Maps the API response to the in-memory session, validating required fields. `expiresAtMs` is put on this
|
|
197
|
+
* browser's clock (the server's expiry less the learned offset), so `expiresAtMs - Date.now()` is the time the
|
|
198
|
+
* token really has left even on a device whose clock is off.
|
|
199
|
+
*/
|
|
121
200
|
toSession(body) {
|
|
122
201
|
if (!body.widgetId || !body.applicationId || !body.pinnedAgentId) {
|
|
123
202
|
throw new Error('Widget session response missing required fields (widgetId/applicationId/pinnedAgentId).');
|
|
@@ -125,7 +204,7 @@ export class WidgetSessionClient {
|
|
|
125
204
|
const expiresAtMs = body.expiresAt ? Date.parse(body.expiresAt) : Number.NaN;
|
|
126
205
|
return {
|
|
127
206
|
token: body.token,
|
|
128
|
-
expiresAtMs: Number.isFinite(expiresAtMs) ? expiresAtMs : Date.now() + 15 * 60_000,
|
|
207
|
+
expiresAtMs: Number.isFinite(expiresAtMs) ? expiresAtMs - this.serverOffsetMs : Date.now() + 15 * 60_000,
|
|
129
208
|
widgetId: body.widgetId,
|
|
130
209
|
applicationId: body.applicationId,
|
|
131
210
|
pinnedAgentId: body.pinnedAgentId,
|
|
@@ -144,4 +223,26 @@ export class WidgetSessionClient {
|
|
|
144
223
|
return this.apiUrl.replace(/\/+$/, '');
|
|
145
224
|
}
|
|
146
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* The `iat` (epoch seconds) of a JWT, read WITHOUT verifying it: the widget only needs the server's clock reading,
|
|
228
|
+
* and the server verifies the token itself. Null when the token is unreadable or carries no numeric `iat`.
|
|
229
|
+
*/
|
|
230
|
+
function ReadTokenIssuedAtSeconds(token) {
|
|
231
|
+
const part = token.split('.')[1];
|
|
232
|
+
if (!part) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const base64 = part.replace(/-/g, '+').replace(/_/g, '/');
|
|
237
|
+
const payload = JSON.parse(atob(base64 + '='.repeat((4 - (base64.length % 4)) % 4)));
|
|
238
|
+
if (typeof payload !== 'object' || payload === null || !('iat' in payload)) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
return typeof payload.iat === 'number' && Number.isFinite(payload.iat) ? payload.iat : null;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Not base64 or not JSON: an unreadable token says nothing about the server's clock (see learnServerOffset).
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
147
248
|
//# sourceMappingURL=widget-session-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-session-client.js","sourceRoot":"","sources":["../../src/session/widget-session-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"widget-session-client.js","sourceRoot":"","sources":["../../src/session/widget-session-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,12 +42,6 @@ export declare class RuntimeWidgetTransport implements IWidgetTransport {
|
|
|
42
42
|
private createConversation;
|
|
43
43
|
/** Saves the visitor's message as a Conversation Detail and returns the entity. */
|
|
44
44
|
private saveUserMessage;
|
|
45
|
-
/**
|
|
46
|
-
* Creates the agent's response detail placeholder (Role='AI', In-Progress) the agent run writes
|
|
47
|
-
* into. Mirrors how the chat UI / AgentRunner pre-create the response row; its id is passed as
|
|
48
|
-
* `conversationDetailId` so the reply lands as an agent turn the widget can read back.
|
|
49
|
-
*/
|
|
50
|
-
private createAgentResponseDetail;
|
|
51
45
|
/** Reads the newest AI Conversation Detail in Main (the agent's reply). */
|
|
52
46
|
private readLatestAgentReply;
|
|
53
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-widget-transport.d.ts","sourceRoot":"","sources":["../../src/transport/runtime-widget-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAKxG,6FAA6F;AAC7F,qBAAa,sBAAuB,YAAW,gBAAgB;IAO/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,QAAQ,CAAkC;gBAErB,MAAM,EAAE,MAAM;IAE3C,qGAAqG;IACxF,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAa9D,8FAA8F;IACvF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIvC,6EAA6E;IAChE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-widget-transport.d.ts","sourceRoot":"","sources":["../../src/transport/runtime-widget-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAKxG,6FAA6F;AAC7F,qBAAa,sBAAuB,YAAW,gBAAgB;IAO/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IANnC,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,QAAQ,CAAkC;gBAErB,MAAM,EAAE,MAAM;IAE3C,qGAAqG;IACxF,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAa9D,8FAA8F;IACvF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIvC,6EAA6E;IAChE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4BzF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,WAAW;IAMnB,gEAAgE;YAClD,kBAAkB;IA+ChC,mFAAmF;YACrE,eAAe;IAc7B,2EAA2E;YAC7D,oBAAoB;CAuBrC"}
|
|
@@ -55,18 +55,11 @@ export class RuntimeWidgetTransport {
|
|
|
55
55
|
if (!userDetail) {
|
|
56
56
|
return { reply: '', success: false, error: 'Could not record your message.' };
|
|
57
57
|
}
|
|
58
|
-
// The
|
|
59
|
-
//
|
|
60
|
-
// IS the agent response detail). Create it as Role='AI' so the reply is an agent turn, not a
|
|
61
|
-
// second user turn; `message`/`latestMessageId` stays the user's triggering message.
|
|
62
|
-
const agentDetail = await this.createAgentResponseDetail();
|
|
63
|
-
if (!agentDetail) {
|
|
64
|
-
return { reply: '', success: false, error: 'Could not start the agent response.' };
|
|
65
|
-
}
|
|
58
|
+
// The server creates the agent's reply row for the visitor's message (only the server writes agent
|
|
59
|
+
// replies) and runs the agent into it; the reply is read back below.
|
|
66
60
|
const result = await ConversationsRuntime.Instance.AgentRunner.processMessage({
|
|
67
61
|
conversationId: this.conversationId,
|
|
68
62
|
message: userDetail,
|
|
69
|
-
conversationDetailId: agentDetail.ID,
|
|
70
63
|
applicationId: this.session.applicationId,
|
|
71
64
|
// D5: ALWAYS pin the support agent — never the unfiltered fallback.
|
|
72
65
|
explicitAgentId: this.session.pinnedAgentId,
|
|
@@ -164,28 +157,6 @@ export class RuntimeWidgetTransport {
|
|
|
164
157
|
}
|
|
165
158
|
return detail;
|
|
166
159
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Creates the agent's response detail placeholder (Role='AI', In-Progress) the agent run writes
|
|
169
|
-
* into. Mirrors how the chat UI / AgentRunner pre-create the response row; its id is passed as
|
|
170
|
-
* `conversationDetailId` so the reply lands as an agent turn the widget can read back.
|
|
171
|
-
*/
|
|
172
|
-
async createAgentResponseDetail() {
|
|
173
|
-
const md = this.requireProvider();
|
|
174
|
-
const detail = await md.GetEntityObject(CONVERSATION_DETAILS_ENTITY, this.contextUser ?? undefined);
|
|
175
|
-
detail.NewRecord();
|
|
176
|
-
detail.ConversationID = this.conversationId;
|
|
177
|
-
detail.Role = 'AI';
|
|
178
|
-
detail.Message = '⏳ Starting…';
|
|
179
|
-
detail.Status = 'In-Progress';
|
|
180
|
-
if (this.session?.pinnedAgentId) {
|
|
181
|
-
detail.AgentID = this.session.pinnedAgentId;
|
|
182
|
-
}
|
|
183
|
-
const saved = await detail.Save();
|
|
184
|
-
if (!saved) {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
return detail;
|
|
188
|
-
}
|
|
189
160
|
/** Reads the newest AI Conversation Detail in Main (the agent's reply). */
|
|
190
161
|
async readLatestAgentReply() {
|
|
191
162
|
const conversationId = this.conversationId;
|