@opencx/widget-core 4.0.60 → 5.0.0-beta.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/index.cjs +13 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4422 -772
- package/dist/index.js.map +1 -1
- package/dist/src/__tests__/api/agent-stream-parts.spec.d.ts +2 -0
- package/dist/src/__tests__/api/agent-stream-parts.spec.d.ts.map +1 -0
- package/dist/src/__tests__/api/dictation-mint-cache.spec.d.ts +2 -0
- package/dist/src/__tests__/api/dictation-mint-cache.spec.d.ts.map +1 -0
- package/dist/src/__tests__/api/widget-api-wire.spec.d.ts +2 -0
- package/dist/src/__tests__/api/widget-api-wire.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/contact-ctx.create-failure.spec.d.ts +2 -0
- package/dist/src/__tests__/context/contact-ctx.create-failure.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/dictation-ctx.spec.d.ts +1 -0
- package/dist/src/__tests__/context/dictation-ctx.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message/merge-send-context.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message/merge-send-context.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message/pending-user-messages.spec.d.ts +1 -0
- package/dist/src/__tests__/context/message/pending-user-messages.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message/sent-text-history.spec.d.ts +1 -0
- package/dist/src/__tests__/context/message/sent-text-history.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.agent-handlers.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.agent-handlers.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.client-context.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.client-context.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.mentions.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.mentions.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.page-mark-chips.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.page-mark-chips.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.send-acceptance.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.send-acceptance.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/message-ctx.send-features.spec.d.ts +2 -0
- package/dist/src/__tests__/context/message-ctx.send-features.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/reconcile-after-stream.spec.d.ts +1 -0
- package/dist/src/__tests__/context/reconcile-after-stream.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/restore-last-session.spec.d.ts +2 -0
- package/dist/src/__tests__/context/restore-last-session.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/session-ctx.stale-token-retry.spec.d.ts +2 -0
- package/dist/src/__tests__/context/session-ctx.stale-token-retry.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/storage-ctx.spec.d.ts +2 -0
- package/dist/src/__tests__/context/storage-ctx.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/streaming-engine.spec.d.ts +1 -0
- package/dist/src/__tests__/context/streaming-engine.spec.d.ts.map +1 -0
- package/dist/src/__tests__/context/widget-ctx.features.spec.d.ts +1 -0
- package/dist/src/__tests__/context/widget-ctx.features.spec.d.ts.map +1 -0
- package/dist/src/__tests__/dictation/dictation-commands.utils.spec.d.ts +2 -0
- package/dist/src/__tests__/dictation/dictation-commands.utils.spec.d.ts.map +1 -0
- package/dist/src/__tests__/test-utils.d.ts +28 -0
- package/dist/src/__tests__/test-utils.d.ts.map +1 -1
- package/dist/src/__tests__/translation.spec.d.ts +2 -0
- package/dist/src/__tests__/translation.spec.d.ts.map +1 -0
- package/dist/src/__tests__/utils/companion-layout.spec.d.ts +2 -0
- package/dist/src/__tests__/utils/companion-layout.spec.d.ts.map +1 -0
- package/dist/src/api/agent-stream-parts.d.ts +24 -0
- package/dist/src/api/agent-stream-parts.d.ts.map +1 -0
- package/dist/src/api/api-caller.d.ts +50 -1
- package/dist/src/api/api-caller.d.ts.map +1 -1
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/schema.d.ts +355 -78
- package/dist/src/api/schema.d.ts.map +1 -1
- package/dist/src/context/active-session-polling.ctx.d.ts +10 -0
- package/dist/src/context/active-session-polling.ctx.d.ts.map +1 -1
- package/dist/src/context/contact.ctx.d.ts +9 -0
- package/dist/src/context/contact.ctx.d.ts.map +1 -1
- package/dist/src/context/csat.ctx.d.ts +2 -5
- package/dist/src/context/csat.ctx.d.ts.map +1 -1
- package/dist/src/context/dictation.ctx.d.ts +67 -0
- package/dist/src/context/dictation.ctx.d.ts.map +1 -0
- package/dist/src/context/message.ctx.d.ts +209 -9
- package/dist/src/context/message.ctx.d.ts.map +1 -1
- package/dist/src/context/router.ctx.d.ts +22 -0
- package/dist/src/context/router.ctx.d.ts.map +1 -1
- package/dist/src/context/session.ctx.d.ts +22 -32
- package/dist/src/context/session.ctx.d.ts.map +1 -1
- package/dist/src/context/storage.ctx.d.ts +40 -1
- package/dist/src/context/storage.ctx.d.ts.map +1 -1
- package/dist/src/context/widget-agent.d.ts +60 -0
- package/dist/src/context/widget-agent.d.ts.map +1 -0
- package/dist/src/context/widget.ctx.d.ts +33 -0
- package/dist/src/context/widget.ctx.d.ts.map +1 -1
- package/dist/src/dictation/dictation-commands.utils.d.ts +76 -0
- package/dist/src/dictation/dictation-commands.utils.d.ts.map +1 -0
- package/dist/src/dictation/dictation-drip.utils.d.ts +21 -0
- package/dist/src/dictation/dictation-drip.utils.d.ts.map +1 -0
- package/dist/src/dictation/dictation-level-smoother.d.ts +18 -0
- package/dist/src/dictation/dictation-level-smoother.d.ts.map +1 -0
- package/dist/src/dictation/dictation-mint-cache.d.ts +25 -0
- package/dist/src/dictation/dictation-mint-cache.d.ts.map +1 -0
- package/dist/src/dictation/dictation-session.d.ts +55 -0
- package/dist/src/dictation/dictation-session.d.ts.map +1 -0
- package/dist/src/index.d.ts +17 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/translation/ar.d.ts.map +1 -1
- package/dist/src/translation/bg.d.ts.map +1 -1
- package/dist/src/translation/bn.d.ts.map +1 -1
- package/dist/src/translation/cs.d.ts.map +1 -1
- package/dist/src/translation/da.d.ts.map +1 -1
- package/dist/src/translation/de.d.ts.map +1 -1
- package/dist/src/translation/el.d.ts.map +1 -1
- package/dist/src/translation/en.d.ts.map +1 -1
- package/dist/src/translation/es.d.ts.map +1 -1
- package/dist/src/translation/et.d.ts.map +1 -1
- package/dist/src/translation/fi.d.ts.map +1 -1
- package/dist/src/translation/fil.d.ts.map +1 -1
- package/dist/src/translation/fr.d.ts.map +1 -1
- package/dist/src/translation/hi.d.ts.map +1 -1
- package/dist/src/translation/hr.d.ts.map +1 -1
- package/dist/src/translation/hu.d.ts.map +1 -1
- package/dist/src/translation/index.d.ts +87 -1
- package/dist/src/translation/index.d.ts.map +1 -1
- package/dist/src/translation/is.d.ts.map +1 -1
- package/dist/src/translation/it.d.ts.map +1 -1
- package/dist/src/translation/ja.d.ts.map +1 -1
- package/dist/src/translation/ko.d.ts.map +1 -1
- package/dist/src/translation/lb.d.ts.map +1 -1
- package/dist/src/translation/lt.d.ts.map +1 -1
- package/dist/src/translation/lv.d.ts.map +1 -1
- package/dist/src/translation/mt.d.ts.map +1 -1
- package/dist/src/translation/nb.d.ts.map +1 -1
- package/dist/src/translation/nl.d.ts.map +1 -1
- package/dist/src/translation/no.d.ts.map +1 -1
- package/dist/src/translation/pl.d.ts.map +1 -1
- package/dist/src/translation/pt.d.ts.map +1 -1
- package/dist/src/translation/ro.d.ts.map +1 -1
- package/dist/src/translation/ru.d.ts.map +1 -1
- package/dist/src/translation/sk.d.ts.map +1 -1
- package/dist/src/translation/sv.d.ts.map +1 -1
- package/dist/src/translation/th.d.ts.map +1 -1
- package/dist/src/translation/tr.d.ts.map +1 -1
- package/dist/src/translation/ur.d.ts.map +1 -1
- package/dist/src/translation/vi.d.ts.map +1 -1
- package/dist/src/translation/zh-cn.d.ts.map +1 -1
- package/dist/src/types/component-name.d.ts +1 -1
- package/dist/src/types/component-name.d.ts.map +1 -1
- package/dist/src/types/dtos.d.ts +2 -0
- package/dist/src/types/dtos.d.ts.map +1 -1
- package/dist/src/types/icons.d.ts +1 -1
- package/dist/src/types/icons.d.ts.map +1 -1
- package/dist/src/types/messages.d.ts +36 -2
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/widget-config.d.ts +402 -4
- package/dist/src/types/widget-config.d.ts.map +1 -1
- package/dist/src/utils/Poller.d.ts.map +1 -1
- package/dist/src/utils/PrimitiveState.d.ts.map +1 -1
- package/dist/src/utils/companion-layout.d.ts +23 -0
- package/dist/src/utils/companion-layout.d.ts.map +1 -0
- package/dist/src/utils/is-exhaustive.d.ts.map +1 -1
- package/dist/src/utils/is-record.d.ts +3 -0
- package/dist/src/utils/is-record.d.ts.map +1 -0
- package/dist/src/utils/log.d.ts +5 -0
- package/dist/src/utils/log.d.ts.map +1 -0
- package/package.json +2 -1
|
@@ -25,6 +25,15 @@ export declare class ContactCtx {
|
|
|
25
25
|
shouldCollectData: () => boolean;
|
|
26
26
|
private autoCreateUnverifiedUserIfNotExists;
|
|
27
27
|
createUnverifiedContact: (payload: Dto["CreateUnverifiedContactDto"], extraCollectedData?: Record<string, string>) => Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* A persisted contact token can go stale — it no longer resolves to a
|
|
30
|
+
* contact and the backend answers 401 "Invalid token". Drop the dead token,
|
|
31
|
+
* clear auth, and mint a fresh anonymous contact so the widget self-heals
|
|
32
|
+
* instead of getting stuck on create-session. No-op for a config-provided
|
|
33
|
+
* verified token (authoritative — re-minting it is not ours to do).
|
|
34
|
+
* Returns true if a fresh contact token was obtained.
|
|
35
|
+
*/
|
|
36
|
+
recoverFromStaleToken: () => Promise<boolean>;
|
|
28
37
|
setUnverifiedContact: (token: string) => Promise<void>;
|
|
29
38
|
}
|
|
30
39
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contact.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/contact.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"contact.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/contact.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIhD,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;KAChC,GAAG,IAAI,CAAC;IACT,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACvD,2BAA2B,EAAE,OAAO,CAAC;IACrC,gCAAgC,EAAE,OAAO,CAAC;CAC3C,CAAC;AAEF,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,GAAG,CAAY;IACvB,KAAK,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;gBAExB,EACV,MAAM,EACN,GAAG,EACH,UAAU,GACX,EAAE;QACD,GAAG,EAAE,SAAS,CAAC;QACf,MAAM,EAAE,YAAY,CAAC;QACrB,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;IAqBD,iBAAiB,QAAO,OAAO,CAK7B;IAEF,OAAO,CAAC,mCAAmC,CAqDzC;IAEF,uBAAuB,GACrB,SAAS,GAAG,CAAC,4BAA4B,CAAC,EAC1C,qBAAqB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC1C,OAAO,CAAC,IAAI,CAAC,CA6Bd;IAEF;;;;;;;OAOG;IACH,qBAAqB,QAAa,OAAO,CAAC,OAAO,CAAC,CAyBhD;IAEF,oBAAoB,GAAU,OAAO,MAAM,mBAUzC;CACH"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { ApiCaller } from '../api/api-caller';
|
|
2
2
|
import { Dto } from '../api/client';
|
|
3
|
-
import { WidgetConfig } from '../types/widget-config';
|
|
4
3
|
import { MessageCtx } from './message.ctx';
|
|
5
4
|
import { SessionCtx } from './session.ctx';
|
|
6
5
|
export declare class CsatCtx {
|
|
7
|
-
private config;
|
|
8
6
|
private api;
|
|
9
7
|
private sessionCtx;
|
|
10
8
|
private messageCtx;
|
|
11
|
-
constructor({
|
|
12
|
-
config: WidgetConfig;
|
|
9
|
+
constructor({ api, sessionCtx, messageCtx, }: {
|
|
13
10
|
api: ApiCaller;
|
|
14
11
|
sessionCtx: SessionCtx;
|
|
15
12
|
messageCtx: MessageCtx;
|
|
@@ -20,7 +17,7 @@ export declare class CsatCtx {
|
|
|
20
17
|
} | {
|
|
21
18
|
data: {
|
|
22
19
|
success: boolean;
|
|
23
|
-
reason?: "rescore_locked";
|
|
20
|
+
reason?: "rescore_locked" | "request_cancelled";
|
|
24
21
|
} | undefined;
|
|
25
22
|
error: {
|
|
26
23
|
statusCode?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csat.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/csat.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"csat.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/csat.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAa;gBAEnB,EACV,GAAG,EACH,UAAU,EACV,UAAU,GACX,EAAE;QACD,GAAG,EAAE,SAAS,CAAC;QACf,UAAU,EAAE,UAAU,CAAC;QACvB,UAAU,EAAE,UAAU,CAAC;KACxB;IAMD,UAAU,GACR,MAAM,IAAI,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;;;;;;;;;;;;;OAgCjE;CACH"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ApiCaller } from '../api/api-caller';
|
|
2
|
+
import { DictationErrorCode } from '../dictation/dictation-session';
|
|
3
|
+
import { WidgetConfig } from '../types/widget-config';
|
|
4
|
+
import { PrimitiveState } from '../utils/PrimitiveState';
|
|
5
|
+
export type DictationStatus = 'idle' | 'connecting' | 'listening';
|
|
6
|
+
export type DictationCtxState = {
|
|
7
|
+
status: DictationStatus;
|
|
8
|
+
/** Last failure, cleared on the next start. */
|
|
9
|
+
error: DictationErrorCode | null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Where dictated text lands. The widget composer is a plain textarea whose
|
|
13
|
+
* value is React state, so the target is just "what is there now" and "set
|
|
14
|
+
* it". Text is appended after whatever the visitor already typed; a manual
|
|
15
|
+
* edit inside the dictated region ends the session (their edit wins).
|
|
16
|
+
*/
|
|
17
|
+
export interface DictationTarget {
|
|
18
|
+
getValue: () => string;
|
|
19
|
+
setValue: (value: string) => void;
|
|
20
|
+
/** Fired for the spoken "send message" command, after the text is final. */
|
|
21
|
+
onSend?: (() => void) | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Voice dictation for the composer: mic → realtime transcription → the
|
|
25
|
+
* textarea, with the spoken-command grammar ("new line",
|
|
26
|
+
* "scratch that", "send it") and paced word reveal. One session per widget;
|
|
27
|
+
* `start` on a live session restarts it against the new target.
|
|
28
|
+
*/
|
|
29
|
+
export declare class DictationCtx {
|
|
30
|
+
state: PrimitiveState<DictationCtxState>;
|
|
31
|
+
/** 0..1 mic level — read inside a rAF loop, never during render. */
|
|
32
|
+
readonly levelRef: {
|
|
33
|
+
current: number;
|
|
34
|
+
};
|
|
35
|
+
private readonly api;
|
|
36
|
+
private readonly config;
|
|
37
|
+
private readonly mintCache;
|
|
38
|
+
private session;
|
|
39
|
+
private target;
|
|
40
|
+
private language;
|
|
41
|
+
/** Composer content when dictation started — dictated text follows it. */
|
|
42
|
+
private prefix;
|
|
43
|
+
private raw;
|
|
44
|
+
private processed;
|
|
45
|
+
private displayed;
|
|
46
|
+
private dripTimer;
|
|
47
|
+
private silenceTimer;
|
|
48
|
+
constructor({ api, config }: {
|
|
49
|
+
api: ApiCaller;
|
|
50
|
+
config: WidgetConfig;
|
|
51
|
+
});
|
|
52
|
+
isActive: () => boolean;
|
|
53
|
+
/** Fire-and-forget token pre-mint (mic hover) so the click starts instantly. */
|
|
54
|
+
prewarm: () => void;
|
|
55
|
+
start: (target: DictationTarget) => void;
|
|
56
|
+
stop: () => void;
|
|
57
|
+
private mintToken;
|
|
58
|
+
/** Applied text = prefix + dictated. A mismatch means the visitor edited. */
|
|
59
|
+
private isConsistent;
|
|
60
|
+
private applyDisplayed;
|
|
61
|
+
/** Process the transcript and apply the outcome. Shared by the delta path,
|
|
62
|
+
* the silence timer, and (with `final`) teardown. Returns the control. */
|
|
63
|
+
private ingest;
|
|
64
|
+
private stopSilenceTimer;
|
|
65
|
+
private teardown;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=dictation.ctx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictation.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/dictation.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAOnD,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGzD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,eAAe,CAAC;IACxB,+CAA+C;IAC/C,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACnC;AAQD;;;;;GAKG;AACH,qBAAa,YAAY;IAChB,KAAK,oCAA+C;IAC3D,oEAAoE;IACpE,SAAgB,QAAQ;;MAAkB;IAE1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IAEtD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAqB;IACrC,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,YAAY,CAA8C;gBAEtD,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;QAAE,GAAG,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE;IAKrE,QAAQ,QAAO,OAAO,CAA0B;IAEhD,gFAAgF;IAChF,OAAO,aAOL;IAEF,KAAK,GAAI,QAAQ,eAAe,UA2F9B;IAEF,IAAI,aAEF;IAEF,OAAO,CAAC,SAAS,CAGb;IAEJ,6EAA6E;IAC7E,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,cAAc;IAMtB;8EAC0E;IAC1E,OAAO,CAAC,MAAM;IAcd,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,QAAQ;CAmCjB"}
|
|
@@ -1,10 +1,101 @@
|
|
|
1
1
|
import { ApiCaller } from '../api/api-caller';
|
|
2
|
-
import { WidgetConfig } from '../types/widget-config';
|
|
3
|
-
import { WidgetMessageU } from '../types/messages';
|
|
2
|
+
import { WidgetConfig, WidgetMention } from '../types/widget-config';
|
|
3
|
+
import { WidgetAiMessage, WidgetMessageU, WidgetUserMessage } from '../types/messages';
|
|
4
4
|
import { SendMessageDto } from '../types/dtos';
|
|
5
5
|
import { PrimitiveState } from '../utils/PrimitiveState';
|
|
6
6
|
import { SessionCtx } from './session.ctx';
|
|
7
7
|
import { ContactCtx } from './contact.ctx';
|
|
8
|
+
/** The shape a caller passes to `sendMessage` (and `stageUserTurn`). */
|
|
9
|
+
export type SendMessageInput = {
|
|
10
|
+
content: SendMessageDto['content'];
|
|
11
|
+
attachments?: SendMessageDto['attachments'];
|
|
12
|
+
customData?: SendMessageDto['custom_data'];
|
|
13
|
+
/**
|
|
14
|
+
* Per-message AI-visible context (e.g. the composer's picked page elements),
|
|
15
|
+
* merged over the config-level `context` on the wire.
|
|
16
|
+
*/
|
|
17
|
+
clientContext?: Record<string, unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* What the visitor @-mentioned (host items picked from `config.mentions`).
|
|
20
|
+
* Sent as `clientContext.mentions`.
|
|
21
|
+
*/
|
|
22
|
+
mentions?: WidgetMention[];
|
|
23
|
+
/**
|
|
24
|
+
* False when the visitor dismissed the page's entity pill for this message:
|
|
25
|
+
* the send goes out without `context.entity`, everything else intact.
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
withPageEntity?: boolean;
|
|
29
|
+
exitModePrompt?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Signals that the send has passed validation, has a session, and is owned
|
|
32
|
+
* by a send engine. This lets composers clear immediately without changing
|
|
33
|
+
* the existing blocking `sendMessage` promise (which still waits for a bot
|
|
34
|
+
* reply). It is lifecycle-only and is never sent over the wire.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
onAccepted?: () => void;
|
|
39
|
+
};
|
|
40
|
+
/** What `stageUserTurn` hands the engine that finishes the send. */
|
|
41
|
+
export type StagedUserTurn = {
|
|
42
|
+
sessionId: string;
|
|
43
|
+
userMessage: WidgetUserMessage;
|
|
44
|
+
/** Persistent greetings riding a fresh conversation's first turn. */
|
|
45
|
+
initialMessages: WidgetAiMessage[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The seam the headless agent-chat provider registers so the shared
|
|
49
|
+
* `sendMessage` entry point routes to its `useChat` streaming engine. Core
|
|
50
|
+
* stays framework-neutral and owns only the blocking bot-chat path plus the
|
|
51
|
+
* shared persisted message list.
|
|
52
|
+
*/
|
|
53
|
+
export type AgentChatHandlers = {
|
|
54
|
+
send: (input: SendMessageInput) => Promise<void> | void;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The per-message wire context shared by both send engines: the host's
|
|
58
|
+
* config-level `context` (resolved fresh when it is a function) with the
|
|
59
|
+
* widget's own per-send page context merged over it.
|
|
60
|
+
*
|
|
61
|
+
* `sendsPageContext` is `WidgetCtx.features.pageContext` — the org's
|
|
62
|
+
* page-context feature narrowed by the embed. Off → the widget adds nothing
|
|
63
|
+
* of its own (no page marks, no picked elements) but the host's `context`
|
|
64
|
+
* still rides along exactly as it did in v4; `custom_data` is unaffected.
|
|
65
|
+
*/
|
|
66
|
+
export declare const mergeSendContext: (config: WidgetConfig, input: SendMessageInput, { sendsPageContext }: {
|
|
67
|
+
sendsPageContext: boolean;
|
|
68
|
+
}) => {
|
|
69
|
+
clientContext: Record<string, unknown> | undefined;
|
|
70
|
+
custom_data: Record<string, unknown>;
|
|
71
|
+
};
|
|
72
|
+
export declare const resolveConfigContext: (config: WidgetConfig) => Record<string, unknown> | undefined;
|
|
73
|
+
/** Wire shape of the per-embed feature toggles (`config.features`). */
|
|
74
|
+
type SendFeaturesBody = NonNullable<SendMessageDto['features']>;
|
|
75
|
+
/**
|
|
76
|
+
* `config.features` (camelCase) → the snake_cased `features` field both send
|
|
77
|
+
* engines carry. Undefined when the embedder set nothing, so the body stays
|
|
78
|
+
* byte-identical to before for embeds that never touch the option.
|
|
79
|
+
*/
|
|
80
|
+
export declare const resolveSendFeatures: (config: WidgetConfig) => SendFeaturesBody | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Everything one send carries on the wire — the SAME body for the blocking
|
|
83
|
+
* send and the streaming turn (both endpoints take `WidgetSendMessageInputDto`).
|
|
84
|
+
* Config is read at call time so function-form `context` and a refreshed
|
|
85
|
+
* embedder config are reflected on every request.
|
|
86
|
+
*/
|
|
87
|
+
export declare const buildSendMessageBody: ({ config, input, uuid, sessionId, content, initialMessages, sendsPageContext, }: {
|
|
88
|
+
config: WidgetConfig;
|
|
89
|
+
input: SendMessageInput;
|
|
90
|
+
/** The user message's wire id (a retry sends a fresh one). */
|
|
91
|
+
uuid: string;
|
|
92
|
+
sessionId: string;
|
|
93
|
+
/** The rendered user message text (extra collected data already prepended). */
|
|
94
|
+
content: string;
|
|
95
|
+
/** Persistent greetings riding a fresh conversation's first turn. */
|
|
96
|
+
initialMessages: readonly WidgetAiMessage[];
|
|
97
|
+
sendsPageContext: boolean;
|
|
98
|
+
}) => SendMessageDto;
|
|
8
99
|
type MessageCtxState = {
|
|
9
100
|
messages: WidgetMessageU[];
|
|
10
101
|
/** Regardless of assignee */
|
|
@@ -19,15 +110,62 @@ export declare class MessageCtx {
|
|
|
19
110
|
private contactCtx;
|
|
20
111
|
private sessionCtx;
|
|
21
112
|
state: PrimitiveState<MessageCtxState>;
|
|
113
|
+
/**
|
|
114
|
+
* The org's web channel runs the streaming engine — turns stream over the
|
|
115
|
+
* AI SDK `useChat` surface instead of the blocking send. Decided by the
|
|
116
|
+
* server at init and constant for the widget's whole lifetime.
|
|
117
|
+
*/
|
|
118
|
+
readonly streaming: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* `WidgetCtx.features.pageContext`: whether the widget's own page context
|
|
121
|
+
* (page marks, picked elements) rides along with each message. Off → the
|
|
122
|
+
* user bubble shows no page-mark chips either.
|
|
123
|
+
*/
|
|
124
|
+
readonly sendsPageContext: boolean;
|
|
125
|
+
/** Registered by the headless agent engine for the WidgetProvider lifetime. */
|
|
126
|
+
private agentHandlers;
|
|
127
|
+
/** Sends issued before the agent-chat surface mounts, oldest first. */
|
|
128
|
+
private bufferedAgentSends;
|
|
22
129
|
private sendMessageAbortController;
|
|
23
130
|
private messageIdsDispatchedToOnMessageReceivedHook;
|
|
24
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Text of messages sent in THIS conversation, oldest first, for the
|
|
133
|
+
* composer's ↑/↓ recall. Lives here rather than in the composer because the
|
|
134
|
+
* quick-ask bar and the full chat composer are different mounts of the same
|
|
135
|
+
* component and recall must survive the morph between them — while staying
|
|
136
|
+
* scoped to one widget instance and one conversation (`reset` clears it, so
|
|
137
|
+
* a new chat never recalls the previous visitor's or session's text).
|
|
138
|
+
* Deliberately NOT part of `state`: nothing renders it, so it must not
|
|
139
|
+
* re-render the transcript on every send.
|
|
140
|
+
*/
|
|
141
|
+
private sentTextHistory;
|
|
142
|
+
private static readonly SENT_TEXT_HISTORY_MAX;
|
|
143
|
+
constructor({ config, api, sessionCtx, contactCtx, streaming, sendsPageContext, }: {
|
|
25
144
|
config: WidgetConfig;
|
|
26
145
|
api: ApiCaller;
|
|
27
146
|
sessionCtx: SessionCtx;
|
|
28
147
|
contactCtx: ContactCtx;
|
|
148
|
+
streaming: boolean;
|
|
149
|
+
sendsPageContext: boolean;
|
|
29
150
|
});
|
|
30
151
|
reset: () => void;
|
|
152
|
+
/**
|
|
153
|
+
* Record sent text for ↑/↓ recall. Consecutive duplicates collapse — the
|
|
154
|
+
* common case is re-sending the same line after a failure.
|
|
155
|
+
*/
|
|
156
|
+
rememberSentText: (text: string) => void;
|
|
157
|
+
/** Sent text for this conversation, oldest first. */
|
|
158
|
+
getSentTextHistory: () => readonly string[];
|
|
159
|
+
/**
|
|
160
|
+
* Wiring for the headless agent engine: WidgetProvider registers its useChat
|
|
161
|
+
* `send` here and clears it on unmount, so every streaming headless or
|
|
162
|
+
* styled consumer shares the same lifecycle. Imperative sends can arrive in
|
|
163
|
+
* the render gap before registration; drain those in FIFO order once ready.
|
|
164
|
+
*/
|
|
165
|
+
registerAgentHandlers: (handlers: AgentChatHandlers) => void;
|
|
166
|
+
/** Hand a send to the streaming engine; its failure can never propagate. */
|
|
167
|
+
private static dispatchToEngine;
|
|
168
|
+
unregisterAgentHandlers: (handlers: AgentChatHandlers) => void;
|
|
31
169
|
/**
|
|
32
170
|
* Fires `config.hooks.onMessageReceived` for AI or human-agent messages exactly
|
|
33
171
|
* once per id. Safe to call from any path that ingests messages from the server
|
|
@@ -41,12 +179,74 @@ export declare class MessageCtx {
|
|
|
41
179
|
* receiving new messages. Subsequent polls still dedupe against these ids.
|
|
42
180
|
*/
|
|
43
181
|
markAsDispatchedToOnMessageReceivedHook: (messageIds: string[]) => void;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
182
|
+
/**
|
|
183
|
+
* On the very first turn of a fresh conversation, the configured persistent
|
|
184
|
+
* initial messages are inserted into the transcript above the user's first
|
|
185
|
+
* message (and posted to the backend so they persist in history). Any later
|
|
186
|
+
* turn returns an empty array.
|
|
187
|
+
*/
|
|
188
|
+
private buildPersistentInitialMessages;
|
|
189
|
+
/**
|
|
190
|
+
* Create the session on the conversation's first send; refreshes the
|
|
191
|
+
* sessions list so the new session shows up immediately. Returns `null`
|
|
192
|
+
* when creation fails.
|
|
193
|
+
*/
|
|
194
|
+
private ensureSessionId;
|
|
195
|
+
/** Remove only this failed attempt's optimistic rows, preserving poll merges. */
|
|
196
|
+
private rollbackOptimisticMessages;
|
|
197
|
+
/**
|
|
198
|
+
* Fire the caller's `onAccepted` once a send is validated, has a session,
|
|
199
|
+
* and is owned by an engine. A consumer callback must never be able to
|
|
200
|
+
* break an accepted send.
|
|
201
|
+
*/
|
|
202
|
+
notifySendAccepted: (input: SendMessageInput) => void;
|
|
203
|
+
/**
|
|
204
|
+
* The front half every send shares, whichever engine finishes it: validate,
|
|
205
|
+
* build the user message (plus the persistent greetings on a fresh
|
|
206
|
+
* conversation's first turn), render it optimistically, and make sure a
|
|
207
|
+
* session exists — rolling the optimistic rows back if it cannot. Returns
|
|
208
|
+
* `null` when there is nothing to send or no session could be created.
|
|
209
|
+
*/
|
|
210
|
+
stageUserTurn: (input: SendMessageInput, { pending }: {
|
|
211
|
+
pending: boolean;
|
|
212
|
+
}) => Promise<StagedUserTurn | null>;
|
|
213
|
+
/**
|
|
214
|
+
* Build the user message for a QUEUED (multi-send) turn WITHOUT rendering
|
|
215
|
+
* it into the transcript. A queued message must not appear above the still-
|
|
216
|
+
* streaming response of the active turn — the surface renders it below the
|
|
217
|
+
* live overlay (dimmed via `pending`) and only `appendUserMessageIfAbsent`s
|
|
218
|
+
* it into `messages` when its own turn actually starts (see `useAgentChat`).
|
|
219
|
+
* A session already exists here (a turn is in flight), so this never creates
|
|
220
|
+
* one.
|
|
221
|
+
*/
|
|
222
|
+
buildQueuedUserMessage: (input: SendMessageInput) => {
|
|
223
|
+
sessionId: string;
|
|
224
|
+
userMessage: WidgetUserMessage;
|
|
225
|
+
} | null;
|
|
226
|
+
/** Validate the input and build its user message; `null` when empty. */
|
|
227
|
+
private buildUserMessage;
|
|
228
|
+
/**
|
|
229
|
+
* Defensive read of `clientContext.page_marks` → the user bubble's context
|
|
230
|
+
* chips: each mark contributes the element it was placed on, the note the
|
|
231
|
+
* visitor wrote, and a reference back to the mark itself (the UI renders
|
|
232
|
+
* the same presentation the composer showed, thumbnail included). Entries
|
|
233
|
+
* without a usable name are dropped.
|
|
234
|
+
*/
|
|
235
|
+
private static markedElementNames;
|
|
236
|
+
/** Append a user message to the transcript once, ignoring a duplicate id. */
|
|
237
|
+
appendUserMessageIfAbsent: (userMessage: WidgetUserMessage) => void;
|
|
238
|
+
/**
|
|
239
|
+
* Clear the `pending` flag for the user message owned by one streamed turn.
|
|
240
|
+
* Later queued bubbles must remain pending until their own turn reaches the
|
|
241
|
+
* server.
|
|
242
|
+
*/
|
|
243
|
+
markUserMessageDelivered: (messageId: string) => void;
|
|
244
|
+
/**
|
|
245
|
+
* The blocking engine refuses a send while the AI reply is pending unless
|
|
246
|
+
* the embed opted out. The streaming engine never blocks (it queues).
|
|
247
|
+
*/
|
|
248
|
+
get blocksSendWhileAwaitingReply(): boolean;
|
|
249
|
+
sendMessage: (input: SendMessageInput) => Promise<void>;
|
|
50
250
|
private toUserMessage;
|
|
51
251
|
private toBotMessage;
|
|
52
252
|
private toBotErrorMessage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/message.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"message.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/message.ctx.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,13 +17,35 @@ export declare class RouterCtx {
|
|
|
17
17
|
private contactCtx;
|
|
18
18
|
private sessionCtx;
|
|
19
19
|
private resetChat;
|
|
20
|
+
/**
|
|
21
|
+
* Whether a reload returns the visitor to the conversation they were in.
|
|
22
|
+
* Off by default: the home screen is the sessions list. Embedders whose
|
|
23
|
+
* widget is a continuous assistant (an empty panel beside a live
|
|
24
|
+
* conversation reads as data loss) opt in via `router.restoreLastSession`.
|
|
25
|
+
*/
|
|
26
|
+
private readonly shouldRestoreLastSession;
|
|
27
|
+
/** The stored pointer, until it is used or found unusable. */
|
|
28
|
+
private restorableSessionId;
|
|
29
|
+
/** Has the (async) storage read settled? Automatic routing waits for it. */
|
|
30
|
+
private didReadStoredSession;
|
|
20
31
|
constructor({ config, contactCtx, sessionCtx, resetChat, }: {
|
|
21
32
|
config: WidgetConfig;
|
|
22
33
|
contactCtx: ContactCtx;
|
|
23
34
|
sessionCtx: SessionCtx;
|
|
24
35
|
resetChat: WidgetCtx['resetChat'];
|
|
25
36
|
});
|
|
37
|
+
/**
|
|
38
|
+
* Read the remembered conversation before any automatic routing runs. The
|
|
39
|
+
* read is async (the storage adapter may be), and the sessions list can land
|
|
40
|
+
* first — so routing is re-run once the pointer is known.
|
|
41
|
+
*/
|
|
42
|
+
private readStoredSession;
|
|
26
43
|
private registerRoutingListener;
|
|
44
|
+
/**
|
|
45
|
+
* Every automatic route the sessions list can trigger, in one place so the
|
|
46
|
+
* restore can re-run it once the stored pointer is known.
|
|
47
|
+
*/
|
|
48
|
+
private routeFromSessions;
|
|
27
49
|
toSessionsScreen: () => void;
|
|
28
50
|
/**
|
|
29
51
|
* @param sessionId The ID of the session to open, or `undefined` if it is a new chat session
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/router.ctx.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,OAAO,GACf,yFAAyF,CAC3F,SAAS;AACT,kDAAkD;GAChD,UAAU;AACZ,uBAAuB;GACrB,MAAM,CAAC;AAEX,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,qBAAa,SAAS;IACpB,KAAK,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC;IAEnC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAyB;
|
|
1
|
+
{"version":3,"file":"router.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/router.ctx.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,OAAO,GACf,yFAAyF,CAC3F,SAAS;AACT,kDAAkD;GAChD,UAAU;AACZ,uBAAuB;GACrB,MAAM,CAAC;AAEX,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,qBAAa,SAAS;IACpB,KAAK,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC;IAEnC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAyB;IAC1C;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IACnD,8DAA8D;IAC9D,OAAO,CAAC,mBAAmB,CAAuB;IAClD,4EAA4E;IAC5E,OAAO,CAAC,oBAAoB,CAAS;gBAEzB,EACV,MAAM,EACN,UAAU,EACV,UAAU,EACV,SAAS,GACV,EAAE;QACD,MAAM,EAAE,YAAY,CAAC;QACrB,UAAU,EAAE,UAAU,CAAC;QACvB,UAAU,EAAE,UAAU,CAAC;QACvB,SAAS,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;KACnC;IAmBD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB,CAcvB;IAEF,OAAO,CAAC,uBAAuB,CAW7B;IAEF;;;OAGG;IACH,OAAO,CAAC,iBAAiB,CAkDvB;IAEF,gBAAgB,aAGd;IAEF;;OAEG;IACH,YAAY,GAAI,YAAY,MAAM,UAmBhC;CACH"}
|
|
@@ -4,6 +4,7 @@ import { SessionDto } from '../types/dtos';
|
|
|
4
4
|
import { WidgetConfig } from '../types/widget-config';
|
|
5
5
|
import { PrimitiveState } from '../utils/PrimitiveState';
|
|
6
6
|
import { ContactCtx } from './contact.ctx';
|
|
7
|
+
import { StorageCtx } from './storage.ctx';
|
|
7
8
|
type SessionState = {
|
|
8
9
|
/**
|
|
9
10
|
* The currently selected session.
|
|
@@ -28,52 +29,41 @@ export declare class SessionCtx {
|
|
|
28
29
|
private config;
|
|
29
30
|
private api;
|
|
30
31
|
private contactCtx;
|
|
32
|
+
private storageCtx?;
|
|
31
33
|
private sessionsPollingIntervalSeconds;
|
|
32
34
|
private sessionsRefresher;
|
|
35
|
+
/** The session id currently written to storage (null = none written). */
|
|
36
|
+
private persistedSessionId;
|
|
33
37
|
sessionState: PrimitiveState<SessionState>;
|
|
34
38
|
sessionsState: PrimitiveState<SessionsState>;
|
|
35
|
-
constructor({ config, api, contactCtx, sessionsPollingIntervalSeconds, }: {
|
|
39
|
+
constructor({ config, api, contactCtx, storageCtx, sessionsPollingIntervalSeconds, }: {
|
|
36
40
|
config: WidgetConfig;
|
|
37
41
|
api: ApiCaller;
|
|
38
42
|
contactCtx: ContactCtx;
|
|
43
|
+
storageCtx?: StorageCtx;
|
|
39
44
|
sessionsPollingIntervalSeconds: number;
|
|
40
45
|
});
|
|
46
|
+
/**
|
|
47
|
+
* Remember which conversation the visitor is in, so a page reload can put
|
|
48
|
+
* them back into it (`RouterCtx` does the restoring). Only OPEN sessions are
|
|
49
|
+
* remembered — a closed one would reopen as a dead transcript — and the
|
|
50
|
+
* pointer is dropped the moment the visitor leaves for a new chat.
|
|
51
|
+
*
|
|
52
|
+
* The boot value is deliberately NOT written: `subscribe` fires on changes
|
|
53
|
+
* only, and clearing on a null we never set would wipe the pointer the
|
|
54
|
+
* restore is about to read.
|
|
55
|
+
*/
|
|
56
|
+
private registerActiveSessionPersistence;
|
|
57
|
+
/** The conversation the visitor was last in, from a previous page load. */
|
|
58
|
+
getLastActiveSessionId: () => Promise<string | null>;
|
|
41
59
|
/** Clears the session and stops polling */
|
|
42
60
|
reset: () => Promise<void>;
|
|
43
61
|
private registerSessionsRefresherWrapper;
|
|
44
62
|
private registerSessionsRefresher;
|
|
45
63
|
private getParsedCustomData;
|
|
46
|
-
createSession: () => Promise<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
title: string | null;
|
|
50
|
-
createdAt: string;
|
|
51
|
-
updatedAt: string;
|
|
52
|
-
isHandedOff: boolean;
|
|
53
|
-
isOpened: boolean;
|
|
54
|
-
assignee: {
|
|
55
|
-
kind: import('../api/schema').components["schemas"]["AssigneeKindEnum"];
|
|
56
|
-
name: string | null;
|
|
57
|
-
avatarUrl: string | null;
|
|
58
|
-
};
|
|
59
|
-
channel: string;
|
|
60
|
-
isVerified: boolean;
|
|
61
|
-
lastMessage: string | null;
|
|
62
|
-
modeId: string | null;
|
|
63
|
-
latestStateCheckpointPayload: {
|
|
64
|
-
[key: string]: unknown;
|
|
65
|
-
} | null;
|
|
66
|
-
sessionAttributes: {
|
|
67
|
-
[key: string]: string | number | boolean;
|
|
68
|
-
};
|
|
69
|
-
customStatus: {
|
|
70
|
-
id: string;
|
|
71
|
-
name: string;
|
|
72
|
-
description: string | null;
|
|
73
|
-
color: string | null;
|
|
74
|
-
icon: string | null;
|
|
75
|
-
} | null;
|
|
76
|
-
} | null>;
|
|
64
|
+
createSession: () => Promise<SessionDto | null>;
|
|
65
|
+
/** One create-session request; on success the session is stored and the hook fires. */
|
|
66
|
+
private requestSession;
|
|
77
67
|
loadMoreSessions: () => Promise<void>;
|
|
78
68
|
private getSessions;
|
|
79
69
|
setSessions: (data: SessionDto[]) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/session.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAoB,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"session.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/session.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAoB,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,KAAK,YAAY,GAAG;IAClB;;;OAGG;IACH,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AACF,KAAK,aAAa,GAAG;IACnB,gCAAgC;IAChC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,gDAAgD;IAChD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,0CAA0C;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,mCAAmC;IACnC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,8BAA8B,CAAS;IAC/C,OAAO,CAAC,iBAAiB,CAAgB;IACzC,yEAAyE;IACzE,OAAO,CAAC,kBAAkB,CAAuB;IAE1C,YAAY,+BAIhB;IACI,aAAa,gCASjB;gBAES,EACV,MAAM,EACN,GAAG,EACH,UAAU,EACV,UAAU,EACV,8BAA8B,GAC/B,EAAE;QACD,MAAM,EAAE,YAAY,CAAC;QACrB,GAAG,EAAE,SAAS,CAAC;QACf,UAAU,EAAE,UAAU,CAAC;QACvB,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,8BAA8B,EAAE,MAAM,CAAC;KACxC;IAWD;;;;;;;;;OASG;IACH,OAAO,CAAC,gCAAgC,CAoBtC;IAEF,2EAA2E;IAC3E,sBAAsB,QAAa,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOvD;IAEF,2CAA2C;IAC3C,KAAK,sBAGH;IAEF,OAAO,CAAC,gCAAgC,CAetC;IAEF,OAAO,CAAC,yBAAyB,CAY/B;IAEF,OAAO,CAAC,mBAAmB,CAczB;IAEF,aAAa,QAAa,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA0BlD;IAEF,uFAAuF;IACvF,OAAO,CAAC,cAAc,CA0BpB;IAEF,gBAAgB,sBAoBd;IAEF,OAAO,CAAC,WAAW,CAYjB;IAEF,WAAW,GAAI,MAAM,UAAU,EAAE,UAK/B;IAEF,eAAe,sBAKb;IAEF,cAAc;;;;;;;;;;;;;;;sBAqCi5iB,6CAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAlBn7iB;IAEF,qBAAqB,GACnB,SAAS,GAAG,CAAC,qCAAqC,CAAC,CAAC,SAAS,CAAC;;;;mBAa9D;CACH"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExternalStorage } from '../types/external-storage';
|
|
2
|
-
import { WidgetConfig } from '../types/widget-config';
|
|
2
|
+
import { WidgetCompanionDefaultLayoutU, WidgetConfig, WidgetSidebarModeU } from '../types/widget-config';
|
|
3
|
+
import { WidgetSidebarSideResolvedU } from '../utils/companion-layout';
|
|
3
4
|
export declare class StorageCtx {
|
|
4
5
|
private storage;
|
|
5
6
|
private config;
|
|
@@ -10,7 +11,45 @@ export declare class StorageCtx {
|
|
|
10
11
|
});
|
|
11
12
|
setContactToken: (token: string) => Promise<void>;
|
|
12
13
|
getContactToken: () => Promise<string | null>;
|
|
14
|
+
clearContactToken: () => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* The conversation the visitor was last in. Only a POINTER lives here — the
|
|
17
|
+
* messages themselves are on the backend — but without it a page reload
|
|
18
|
+
* drops the visitor into an empty composer beside a conversation that is
|
|
19
|
+
* still very much alive.
|
|
20
|
+
*/
|
|
21
|
+
private activeSessionKey;
|
|
22
|
+
getActiveSessionId: () => Promise<string | null>;
|
|
23
|
+
setActiveSessionId: (sessionId: string) => Promise<void>;
|
|
24
|
+
clearActiveSessionId: () => Promise<void>;
|
|
13
25
|
setExternalContactId: (id: string) => Promise<void>;
|
|
14
26
|
getExternalContactId: () => Promise<string | null>;
|
|
27
|
+
private companionKey;
|
|
28
|
+
private getFiniteNumber;
|
|
29
|
+
getCompanionPillOffsetX: () => Promise<number | null>;
|
|
30
|
+
setCompanionPillOffsetX: (offset: number) => Promise<void>;
|
|
31
|
+
getCompanionSidebarWidth: () => Promise<number | null>;
|
|
32
|
+
setCompanionSidebarWidth: (width: number) => Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* The visitor's own sidebar side/mode, once they have picked one in the
|
|
35
|
+
* layout menu. Absent until then, so `companion.sidebar.*` config keeps
|
|
36
|
+
* deciding for a visitor who never touched the control. Unrecognized stored
|
|
37
|
+
* values read as absent rather than poisoning the layout.
|
|
38
|
+
*/
|
|
39
|
+
getCompanionSidebarSide: () => Promise<WidgetSidebarSideResolvedU | null>;
|
|
40
|
+
setCompanionSidebarSide: (side: WidgetSidebarSideResolvedU) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* The RESTING layout the visitor last picked in the layout menu. Absent
|
|
43
|
+
* until they pick one, so `companion.defaultLayout` keeps deciding for a
|
|
44
|
+
* visitor who never touched the control.
|
|
45
|
+
*
|
|
46
|
+
* `fullscreen` is deliberately unstorable: it is a mode the visitor enters
|
|
47
|
+
* on top of a resting layout (Escape drops back out of it), so persisting
|
|
48
|
+
* it would reopen every future visit full-screen over the host page.
|
|
49
|
+
*/
|
|
50
|
+
getCompanionLayout: () => Promise<WidgetCompanionDefaultLayoutU | null>;
|
|
51
|
+
setCompanionLayout: (layout: WidgetCompanionDefaultLayoutU) => Promise<void>;
|
|
52
|
+
getCompanionSidebarMode: () => Promise<WidgetSidebarModeU | null>;
|
|
53
|
+
setCompanionSidebarMode: (mode: WidgetSidebarModeU) => Promise<void>;
|
|
15
54
|
}
|
|
16
55
|
//# sourceMappingURL=storage.ctx.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/storage.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"storage.ctx.d.ts","sourceRoot":"","sources":["../../../src/context/storage.ctx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EACV,6BAA6B,EAC7B,YAAY,EACZ,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAU5E,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAe;IAE7B,OAAO,CAAC,IAAI,CASV;gBAEU,EACV,OAAO,EACP,MAAM,GACP,EAAE;QACD,OAAO,EAAE,eAAe,CAAC;QACzB,MAAM,EAAE,YAAY,CAAC;KACtB;IAKD,eAAe,GAAU,OAAO,MAAM,mBAEpC;IACF,eAAe,+BAEb;IACF,iBAAiB,sBAEf;IAEF;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CACqB;IAE7C,kBAAkB,QAAa,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEnD;IACF,kBAAkB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;IACF,oBAAoB,QAAa,OAAO,CAAC,IAAI,CAAC,CAE5C;IAEF,oBAAoB,GAAU,IAAI,MAAM,mBAEtC;IACF,oBAAoB,+BAElB;IAEF,OAAO,CAAC,YAAY,CAC2C;IAE/D,OAAO,CAAC,eAAe,CAKrB;IAEF,uBAAuB,QAAa,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CACC;IAE3D,uBAAuB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAG7D;IAEF,wBAAwB,QAAa,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CACA;IAE3D,wBAAwB,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAG7D;IAEF;;;;;OAKG;IACH,uBAAuB,QACX,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAGlD;IAEJ,uBAAuB,GACrB,MAAM,0BAA0B,KAC/B,OAAO,CAAC,IAAI,CAAC,CAEd;IAEF;;;;;;;;OAQG;IACH,kBAAkB,QACN,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAGrD;IAEJ,kBAAkB,GAChB,QAAQ,6BAA6B,KACpC,OAAO,CAAC,IAAI,CAAC,CAEd;IAEF,uBAAuB,QAAa,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAGpE;IAEF,uBAAuB,GAAU,MAAM,kBAAkB,KAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;CACH"}
|