@ada-support/embed2 1.13.5 → 1.14.3
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 +2 -2
- package/dist/npm-entry/client/components/Container/host-facing-meta-fields.d.ts +5 -0
- package/dist/npm-entry/client/embed.d.ts +1 -0
- package/dist/npm-entry/common/constants/events.d.ts +2 -0
- package/dist/npm-entry/common/helpers/host-telemetry.d.ts +8 -0
- package/dist/npm-entry/common/helpers/programmatic-control.d.ts +5 -0
- package/dist/npm-entry/common/helpers/with-timeout.d.ts +10 -0
- package/dist/npm-entry/common/lib/channel.d.ts +43 -0
- package/dist/npm-entry/common/types/extended-api.d.ts +191 -0
- package/dist/npm-entry/common/types/index.d.ts +2 -2
- package/dist/npm-entry/common/types/store-state.d.ts +4 -0
- package/dist/npm-entry/index-npm.d.ts +1 -1
- package/dist/npm-entry/index.js +500 -82
- package/dist/npm-entry/interface.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Embed 2
|
|
2
2
|
|
|
3
|
-
Embed 2 allows clients to setup Ada Web Chat in their web application. For further information on how to use Embed, check out our [documentation](https://
|
|
3
|
+
Embed 2 allows clients to setup Ada Web Chat in their web application. For further information on how to use Embed, check out our [documentation](https://docs.ada.cx/chat/web/getting-started).
|
|
4
4
|
|
|
5
5
|
## 1. Installation
|
|
6
6
|
|
|
@@ -34,4 +34,4 @@ adaEmbed.start({
|
|
|
34
34
|
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
In the example above the `handle` key is a part of `AdaSettings`. To learn more about other settings, consult the [API reference](https://
|
|
37
|
+
In the example above the `handle` key is a part of `AdaSettings`. To learn more about other settings, consult the [API reference](https://docs.ada.cx/chat/web/sdk-api-reference).
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PayloadByEvent } from "common/lib/channel";
|
|
2
|
+
/** Strips the internal `proactive_conversation` tracker for getMetaFields(). */
|
|
3
|
+
export declare function toHostFacingMetaFields(metaFields: Record<string, unknown> | undefined): PayloadByEvent["GET_META_FIELDS_RESPONSE"];
|
|
4
|
+
/** Merges a proactive_conversation key onto existing metaFields. */
|
|
5
|
+
export declare function withProactiveKey(metaFields: Record<string, unknown> | undefined, key: string): Record<string, unknown>;
|
|
@@ -10,6 +10,7 @@ export declare function createEmbed(adaSettings: StartOptions): {
|
|
|
10
10
|
readonly adaSettings: StartOptions;
|
|
11
11
|
readonly getInfo: () => Promise<WindowInfo>;
|
|
12
12
|
readonly setMetaFields: (options: MetaFieldPayload) => Promise<void>;
|
|
13
|
+
readonly getMetaFields: () => Promise<MetaFieldPayload>;
|
|
13
14
|
readonly setSensitiveMetaFields: (options: MetaFieldPayload) => Promise<void>;
|
|
14
15
|
readonly stop: () => Promise<void>;
|
|
15
16
|
readonly deleteHistory: () => Promise<void>;
|
|
@@ -59,6 +59,8 @@ export declare const GET_INFO = "GET_INFO";
|
|
|
59
59
|
export declare const GET_INFO_RESPONSE = "GET_INFO_RESPONSE";
|
|
60
60
|
export declare const SET_META_FIELDS = "SET_META_FIELDS";
|
|
61
61
|
export declare const SET_META_FIELDS_RESPONSE = "SET_META_FIELDS_RESPONSE";
|
|
62
|
+
export declare const GET_META_FIELDS = "GET_META_FIELDS";
|
|
63
|
+
export declare const GET_META_FIELDS_RESPONSE = "GET_META_FIELDS_RESPONSE";
|
|
62
64
|
export declare const STOP = "STOP";
|
|
63
65
|
export declare const STOP_RESPONSE = "STOP_RESPONSE";
|
|
64
66
|
export declare const DELETE_HISTORY = "DELETE_HISTORY";
|
|
@@ -3,6 +3,7 @@ export type HostTelemetrySurface = "mobile" | "browser";
|
|
|
3
3
|
export type HostTelemetryPlatform = "ios" | "android" | "react-native" | "web" | "unknown";
|
|
4
4
|
export type HostTelemetryWebSdkOrigin = "legacy" | "messaging";
|
|
5
5
|
export type HostTelemetryMobileShell = "messaging-sdk" | "legacy-sdk";
|
|
6
|
+
export type HostTelemetryMode = "headless" | "visible";
|
|
6
7
|
export interface HostTelemetryContext {
|
|
7
8
|
surface: HostTelemetrySurface;
|
|
8
9
|
hostPlatform: HostTelemetryPlatform;
|
|
@@ -10,6 +11,13 @@ export interface HostTelemetryContext {
|
|
|
10
11
|
mobileShell?: HostTelemetryMobileShell;
|
|
11
12
|
mobilePackage?: string;
|
|
12
13
|
mobileVersion?: string;
|
|
14
|
+
/**
|
|
15
|
+
* MES-981 P1 #10: distinguishes SDK-driven headless sessions from
|
|
16
|
+
* sessions with a visible chat surface. Tagged on every log/RUM line
|
|
17
|
+
* emitted through `setGlobalLogContext(toMonitoringContext(...))` so
|
|
18
|
+
* dashboards can filter by mode without a separate event.
|
|
19
|
+
*/
|
|
20
|
+
mode?: HostTelemetryMode;
|
|
13
21
|
}
|
|
14
22
|
export declare const HOST_TELEMETRY_QUERY_PARAM = "ada_host_telemetry";
|
|
15
23
|
type StartOptionsWithHostTelemetry = StartOptions & {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AdaEmbedError } from "common/helpers/errors";
|
|
2
|
+
export declare const PROGRAMMATIC_CONTROL_DISABLED_ERROR: AdaEmbedError;
|
|
3
|
+
export declare function isProgrammaticControlEnabled(adaSettings: object | undefined | null): boolean;
|
|
4
|
+
export declare function requireProgrammaticControl(adaSettings: object | undefined | null): void;
|
|
5
|
+
export declare function shouldDeliverTranscriptEvent(eventKey: string, adaSettings: object | undefined | null): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Race `promise` against a timeout. If the timeout fires first, reject
|
|
3
|
+
* with an AdaEmbedError carrying `errorMessage`. If the promise settles
|
|
4
|
+
* first (resolve or reject), clear the pending timer so it doesn't
|
|
5
|
+
* keep the event loop alive past resolution.
|
|
6
|
+
*
|
|
7
|
+
* MES-981 P1 #7: used to cap host-supplied beforeSend hooks so a
|
|
8
|
+
* never-resolving delegate can't hang sendMessage forever.
|
|
9
|
+
*/
|
|
10
|
+
export declare function withTimeout<T>(promise: PromiseLike<T> | T, ms: number, errorMessage: string): Promise<T>;
|
|
@@ -15,7 +15,10 @@ export interface EmbedRequestPayloadByEvent {
|
|
|
15
15
|
DISPATCH: StoreDispatchPayload;
|
|
16
16
|
EVAL_CAMPAIGN_CONDITIONS: CampaignParams;
|
|
17
17
|
GET: StoreGetPayload;
|
|
18
|
+
GET_CONVERSATION: unknown;
|
|
18
19
|
GET_INFO: unknown;
|
|
20
|
+
GET_MESSAGES: unknown;
|
|
21
|
+
GET_META_FIELDS: unknown;
|
|
19
22
|
GET_STATE: unknown;
|
|
20
23
|
RESET: ResetParams;
|
|
21
24
|
SET_META_FIELDS: MetaFieldPayload;
|
|
@@ -34,6 +37,12 @@ export interface EmbedRequestPayloadByEvent {
|
|
|
34
37
|
SET_LANGUAGE: {
|
|
35
38
|
language: string;
|
|
36
39
|
};
|
|
40
|
+
SET_COMPOSER_TEXT: {
|
|
41
|
+
text: string;
|
|
42
|
+
};
|
|
43
|
+
SEND_MESSAGE: {
|
|
44
|
+
text: string;
|
|
45
|
+
};
|
|
37
46
|
TRIGGER_PROACTIVE: TriggerProactiveParams;
|
|
38
47
|
INJECT_PROACTIVE_CONVERSATION: {
|
|
39
48
|
key: string;
|
|
@@ -51,8 +60,42 @@ export interface EmbedResponsePayloadByEvent {
|
|
|
51
60
|
"DISPATCH_RESPONSE": StoreState;
|
|
52
61
|
"EVAL_CAMPAIGN_CONDITIONS_RESPONSE": unknown;
|
|
53
62
|
"GET_RESPONSE": StoreState[keyof StoreState];
|
|
63
|
+
"GET_CONVERSATION_RESPONSE": {
|
|
64
|
+
id: string | null;
|
|
65
|
+
handoff: {
|
|
66
|
+
inLiveChat: boolean;
|
|
67
|
+
agent?: {
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
avatarUrl?: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
54
74
|
"GET_INFO_RESPONSE": unknown;
|
|
75
|
+
"GET_MESSAGES_RESPONSE": Array<{
|
|
76
|
+
id: string;
|
|
77
|
+
role: "user" | "bot" | "agent";
|
|
78
|
+
type: string;
|
|
79
|
+
body?: string;
|
|
80
|
+
createdAt: number;
|
|
81
|
+
agent?: {
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
avatarUrl?: string;
|
|
85
|
+
};
|
|
86
|
+
}>;
|
|
87
|
+
"GET_META_FIELDS_RESPONSE": MetaFieldPayload;
|
|
55
88
|
"GET_STATE_RESPONSE": StoreState;
|
|
89
|
+
"SEND_MESSAGE_RESPONSE": {
|
|
90
|
+
id: string;
|
|
91
|
+
} | {
|
|
92
|
+
error: string;
|
|
93
|
+
};
|
|
94
|
+
"SET_COMPOSER_TEXT_RESPONSE": {
|
|
95
|
+
ok: true;
|
|
96
|
+
} | {
|
|
97
|
+
error: string;
|
|
98
|
+
};
|
|
56
99
|
"GREETING": unknown;
|
|
57
100
|
"JWT_AUTH_RESPONSE": unknown;
|
|
58
101
|
"RESET_RESPONSE": unknown;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { AdaEmbedAPI, AdaEventContext, AdaEventKey, AdaEventSubscriptionCallback, StartOptions } from "@ada-support/embed-types";
|
|
2
|
+
import type { MetaFieldPayload } from "common/types/store";
|
|
3
|
+
/**
|
|
4
|
+
* MES-981: new ada:* event keys + their payload shapes, added alongside
|
|
5
|
+
* the existing `@ada-support/embed-types` `AdaEventDataKeyedByEvent` union.
|
|
6
|
+
* Once the upstream package is updated these are folded back in and this
|
|
7
|
+
* file goes away.
|
|
8
|
+
*/
|
|
9
|
+
export interface ExtendedAdaEventDataKeyedByEvent {
|
|
10
|
+
/**
|
|
11
|
+
* MES-981 P1 #10: tagged with `mode` so downstream consumers can
|
|
12
|
+
* distinguish between visible-drawer sessions and SDK-driven headless
|
|
13
|
+
* sessions.
|
|
14
|
+
*/
|
|
15
|
+
"ada:ready": {
|
|
16
|
+
mode: "headless" | "visible";
|
|
17
|
+
};
|
|
18
|
+
"ada:message:sent": {
|
|
19
|
+
message: Message;
|
|
20
|
+
};
|
|
21
|
+
"ada:message:received": {
|
|
22
|
+
message: Message;
|
|
23
|
+
};
|
|
24
|
+
"ada:typing:start": {
|
|
25
|
+
agentId: string;
|
|
26
|
+
};
|
|
27
|
+
"ada:typing:stop": {
|
|
28
|
+
agentId: string;
|
|
29
|
+
};
|
|
30
|
+
"ada:connection:change": {
|
|
31
|
+
state: "connected" | "reconnecting" | "disconnected";
|
|
32
|
+
};
|
|
33
|
+
"ada:conversation:change": {
|
|
34
|
+
id: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export type ExtendedAdaEventKey = AdaEventKey | keyof ExtendedAdaEventDataKeyedByEvent;
|
|
38
|
+
/**
|
|
39
|
+
* MES-981: forward-compatible start options that include the new
|
|
40
|
+
* MES-981 flags. The flags are consumed at runtime by `embed-2`; the
|
|
41
|
+
* type augmentation here lets host pages set them without a type error
|
|
42
|
+
* while the upstream `@ada-support/embed-types` package is being updated.
|
|
43
|
+
*/
|
|
44
|
+
export type ExtendedStartOptions = StartOptions & {
|
|
45
|
+
/** Loads chat without rendering the default button/drawer. */
|
|
46
|
+
headless?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Opt-in to the programmatic transcript-bearing surface introduced by
|
|
49
|
+
* MES-981: `sendMessage`, `setComposerText`, `getMessages`, `setDelegate`,
|
|
50
|
+
* and the `ada:message:sent` / `ada:message:received` events.
|
|
51
|
+
*
|
|
52
|
+
* Defaults to `false`. While the flag is off the methods reject with an
|
|
53
|
+
* explicit error and the events are not delivered to host subscribers,
|
|
54
|
+
* because every script that lives in the host page (analytics, GTM, ad
|
|
55
|
+
* pixels, session replay tools, supply-chain XSS) inherits the host's
|
|
56
|
+
* trust — and the host site's product/security team should explicitly
|
|
57
|
+
* accept the transcript-exposure risk before that capability is reachable.
|
|
58
|
+
*/
|
|
59
|
+
enableProgrammaticControl?: boolean;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Local augmentation of the public AdaEmbedAPI surface for methods that are
|
|
63
|
+
* being rolled out via MES-981 ahead of a matching release of
|
|
64
|
+
* @ada-support/embed-types. Once those types are published, the methods below
|
|
65
|
+
* should be moved into the upstream interface and this file can be removed.
|
|
66
|
+
*/
|
|
67
|
+
export interface ExtendedAdaEmbedAPI extends AdaEmbedAPI {
|
|
68
|
+
/**
|
|
69
|
+
* MES-981: widened start() overload that accepts the new ExtendedStartOptions
|
|
70
|
+
* (`headless`, `enableProgrammaticControl`) without requiring an `as`
|
|
71
|
+
* cast at the call site. Returns void to match the upstream signature.
|
|
72
|
+
*/
|
|
73
|
+
start(adaSettings: ExtendedStartOptions): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Convenience accessor for whether the chat drawer is currently open.
|
|
76
|
+
* Equivalent to `(await getInfo()).isChatOpen`.
|
|
77
|
+
*
|
|
78
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* if (await adaEmbed.isOpen()) {
|
|
82
|
+
* // chat is visible
|
|
83
|
+
* }
|
|
84
|
+
*/
|
|
85
|
+
isOpen(): Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* Returns the metaFields currently held in embed-2's state. Reflects the
|
|
88
|
+
* value initially passed to `start({ metaFields })` plus any subsequent
|
|
89
|
+
* `setMetaFields` updates. Sensitive metaFields are deliberately not
|
|
90
|
+
* exposed.
|
|
91
|
+
*
|
|
92
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`.
|
|
93
|
+
*/
|
|
94
|
+
getMetaFields(): Promise<MetaFieldPayload>;
|
|
95
|
+
/**
|
|
96
|
+
* Pre-fills the chat composer input with `text` without sending it.
|
|
97
|
+
* The value can still be edited or cleared by the end user.
|
|
98
|
+
*
|
|
99
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`,
|
|
100
|
+
* or with an `AdaEmbedError` if the chat frame is not yet ready.
|
|
101
|
+
*/
|
|
102
|
+
setComposerText(text: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Returns metadata about the current conversation: its id (or `null`
|
|
105
|
+
* if there is no active conversation), and the handoff state — whether
|
|
106
|
+
* the conversation is in live chat and, if so, basic info about the
|
|
107
|
+
* connected agent.
|
|
108
|
+
*
|
|
109
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`,
|
|
110
|
+
* or with an `AdaEmbedError` if the chat frame is not yet ready.
|
|
111
|
+
*/
|
|
112
|
+
getConversation(): Promise<ConversationInfo>;
|
|
113
|
+
/**
|
|
114
|
+
* Returns the full in-memory message list for the current session.
|
|
115
|
+
* Generative has no server-side history endpoint, so this returns
|
|
116
|
+
* what the client has rendered (user, bot, and any handoff messages).
|
|
117
|
+
* Returns an empty array if no messages have been exchanged yet.
|
|
118
|
+
*
|
|
119
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`,
|
|
120
|
+
* or with an `AdaEmbedError` if the chat frame is not yet ready.
|
|
121
|
+
*/
|
|
122
|
+
getMessages(): Promise<Message[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Sends a free-text user message through the same path as the visible
|
|
125
|
+
* composer (POSTs to `/message/chat/`). Resolves with the generated
|
|
126
|
+
* message id so the caller can correlate it with later `getMessages()`
|
|
127
|
+
* reads.
|
|
128
|
+
*
|
|
129
|
+
* Generative does not support per-message metadata; user-level metadata
|
|
130
|
+
* is set via `setMetaFields`.
|
|
131
|
+
*
|
|
132
|
+
* Rejects with `EMBED_NOT_INITIALIZED_ERROR` if called before `start()`,
|
|
133
|
+
* an `AdaEmbedError` if the chat frame is not yet ready, or an
|
|
134
|
+
* `AdaEmbedError` if `text` is empty.
|
|
135
|
+
*/
|
|
136
|
+
sendMessage(text: string): Promise<{
|
|
137
|
+
id: string;
|
|
138
|
+
}>;
|
|
139
|
+
/**
|
|
140
|
+
* Registers a host-side interceptor that runs in embed-2 before
|
|
141
|
+
* outgoing messages are forwarded to chat. Use `beforeSend` to
|
|
142
|
+
* modify, cancel, or pass through the user message. Set `beforeSend`
|
|
143
|
+
* to `undefined` to clear an existing delegate.
|
|
144
|
+
*
|
|
145
|
+
* The delegate may be synchronous or async. Returning `false` (or a
|
|
146
|
+
* Promise of `false`) cancels the send and causes `sendMessage` to
|
|
147
|
+
* reject with `DelegateRejected`.
|
|
148
|
+
*/
|
|
149
|
+
setDelegate(delegate: Delegate): void;
|
|
150
|
+
/**
|
|
151
|
+
* MES-981: widened subscribeEvent overload to accept the new ada:* event
|
|
152
|
+
* keys until @ada-support/embed-types is republished. The upstream signature
|
|
153
|
+
* is preserved for the original key set via the union return type.
|
|
154
|
+
*/
|
|
155
|
+
subscribeEvent<K extends ExtendedAdaEventKey>(eventKey: K, callback: K extends AdaEventKey ? AdaEventSubscriptionCallback<K> : K extends keyof ExtendedAdaEventDataKeyedByEvent ? (data: ExtendedAdaEventDataKeyedByEvent[K], context: AdaEventContext) => void : never): Promise<number>;
|
|
156
|
+
}
|
|
157
|
+
export type BeforeSend = (message: {
|
|
158
|
+
text: string;
|
|
159
|
+
}) => {
|
|
160
|
+
text: string;
|
|
161
|
+
} | false | Promise<{
|
|
162
|
+
text: string;
|
|
163
|
+
} | false>;
|
|
164
|
+
export interface Delegate {
|
|
165
|
+
beforeSend?: BeforeSend;
|
|
166
|
+
}
|
|
167
|
+
export interface ConversationInfo {
|
|
168
|
+
id: string | null;
|
|
169
|
+
handoff: {
|
|
170
|
+
inLiveChat: boolean;
|
|
171
|
+
agent?: {
|
|
172
|
+
id: string;
|
|
173
|
+
name: string;
|
|
174
|
+
avatarUrl?: string;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
export type MessageRole = "user" | "bot" | "agent";
|
|
179
|
+
export interface Message {
|
|
180
|
+
id: string;
|
|
181
|
+
role: MessageRole;
|
|
182
|
+
type: string;
|
|
183
|
+
body?: string;
|
|
184
|
+
/** Unix epoch seconds (subsecond precision), as stored by the chat session. */
|
|
185
|
+
createdAt: number;
|
|
186
|
+
agent?: {
|
|
187
|
+
id: string;
|
|
188
|
+
name: string;
|
|
189
|
+
avatarUrl?: string;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AdaEmbedAPI } from "@ada-support/embed-types";
|
|
2
1
|
import type { ActionTypes } from "common/constants/actions";
|
|
2
|
+
import type { ExtendedAdaEmbedAPI } from "./extended-api";
|
|
3
3
|
import type { StoreState } from "./store-state";
|
|
4
4
|
export * from "./interface";
|
|
5
5
|
export interface StoreAction {
|
|
@@ -30,7 +30,7 @@ export interface TriggerCampaignParams {
|
|
|
30
30
|
ignoreFrequency?: boolean;
|
|
31
31
|
}
|
|
32
32
|
export interface CustomWindow extends Window {
|
|
33
|
-
adaEmbed:
|
|
33
|
+
adaEmbed: ExtendedAdaEmbedAPI;
|
|
34
34
|
navigator: Navigator;
|
|
35
35
|
adaEmbedLoadedCallback?: () => void;
|
|
36
36
|
}
|
|
@@ -65,4 +65,8 @@ export interface StartOptionsNoFunction {
|
|
|
65
65
|
testMode?: boolean;
|
|
66
66
|
preload?: boolean;
|
|
67
67
|
showFallbackOnTimeout?: boolean;
|
|
68
|
+
/** MES-981: programmatic-only mode — entry UI is hidden, host renders its own surface */
|
|
69
|
+
headless?: boolean;
|
|
70
|
+
/** MES-981 P0 #4: opt-in for the transcript-bearing programmatic surface. */
|
|
71
|
+
enableProgrammaticControl?: boolean;
|
|
68
72
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("./common/types/extended-api").ExtendedAdaEmbedAPI;
|
|
2
2
|
export default _default;
|
package/dist/npm-entry/index.js
CHANGED
|
@@ -15919,7 +15919,7 @@ const client = new BrowserClient({
|
|
|
15919
15919
|
return event;
|
|
15920
15920
|
},
|
|
15921
15921
|
environment: "production",
|
|
15922
|
-
release: "1.
|
|
15922
|
+
release: "1.14.3-00422f5",
|
|
15923
15923
|
sampleRate: 0.25,
|
|
15924
15924
|
autoSessionTracking: false,
|
|
15925
15925
|
// Integrations don't seem to work with Sentry: https://github.com/getsentry/sentry-javascript/issues/2541
|
|
@@ -16019,6 +16019,8 @@ const GET_INFO = "GET_INFO";
|
|
|
16019
16019
|
const GET_INFO_RESPONSE = "GET_INFO_RESPONSE";
|
|
16020
16020
|
const SET_META_FIELDS = "SET_META_FIELDS";
|
|
16021
16021
|
const SET_META_FIELDS_RESPONSE = "SET_META_FIELDS_RESPONSE";
|
|
16022
|
+
const GET_META_FIELDS = "GET_META_FIELDS";
|
|
16023
|
+
const GET_META_FIELDS_RESPONSE = "GET_META_FIELDS_RESPONSE";
|
|
16022
16024
|
const STOP = "STOP";
|
|
16023
16025
|
const STOP_RESPONSE = "STOP_RESPONSE";
|
|
16024
16026
|
const DELETE_HISTORY = "DELETE_HISTORY";
|
|
@@ -16058,6 +16060,12 @@ let FetchEventStatus = /*#__PURE__*/function (FetchEventStatus) {
|
|
|
16058
16060
|
|
|
16059
16061
|
|
|
16060
16062
|
|
|
16063
|
+
// MES-981 P1 #6 follow-up: request events whose responses are surfaced
|
|
16064
|
+
// directly to host-page callers. For these, channel.fetch() differentiates
|
|
16065
|
+
// timeouts (resolves to undefined) from other failures (re-throws with a
|
|
16066
|
+
// descriptive message) so the caller's "response === undefined" check
|
|
16067
|
+
// always means "timeout" specifically, not "something else went wrong".
|
|
16068
|
+
const PRIVILEGED_FETCH_EVENTS = new Set(["SEND_MESSAGE", "SET_COMPOSER_TEXT", "GET_MESSAGES", "GET_CONVERSATION"]);
|
|
16061
16069
|
class Channel {
|
|
16062
16070
|
constructor() {
|
|
16063
16071
|
_defineProperty(this, "trackedListeners", void 0);
|
|
@@ -16111,6 +16119,21 @@ class Channel {
|
|
|
16111
16119
|
throw new AdaEmbedError(`Failed to respond to "GET_STATE" request. Reason: "${e.message}".`);
|
|
16112
16120
|
}
|
|
16113
16121
|
|
|
16122
|
+
// MES-981 P1 #6 follow-up: privileged transcript-bearing request/
|
|
16123
|
+
// response pairs must distinguish timeouts from other failures.
|
|
16124
|
+
// Without this, the "if (response === undefined)" check in
|
|
16125
|
+
// interface.ts throws a misleading "… timed out" error even when
|
|
16126
|
+
// the real failure was a payload-shape rejection or a handler
|
|
16127
|
+
// exception. Re-throw on any non-timeout error so the caller sees
|
|
16128
|
+
// the actual reason.
|
|
16129
|
+
if (PRIVILEGED_FETCH_EVENTS.has(requestEvent)) {
|
|
16130
|
+
if (e instanceof Error && e.message === "Could not connect frame channel.") {
|
|
16131
|
+
// genuine timeout — fall through, resolves to undefined
|
|
16132
|
+
} else {
|
|
16133
|
+
throw new AdaEmbedError(`"${requestEvent}" failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
16134
|
+
}
|
|
16135
|
+
}
|
|
16136
|
+
|
|
16114
16137
|
// handling promise
|
|
16115
16138
|
if (e.message !== "Could not connect frame channel.") {
|
|
16116
16139
|
error_tracker.trackException(e);
|
|
@@ -16395,14 +16418,25 @@ function subscribeEvent(eventKey, callback) {
|
|
|
16395
16418
|
});
|
|
16396
16419
|
return id;
|
|
16397
16420
|
}
|
|
16421
|
+
|
|
16422
|
+
// MES-981 P2 #11: events that carry transcript bodies (or other
|
|
16423
|
+
// sensitive payloads) must match exactly, never via prefix. Prefix
|
|
16424
|
+
// subscriptions to `ada:` would otherwise leak `ada:message:sent` and
|
|
16425
|
+
// `ada:message:received` to anyone broadly subscribed to the `ada:`
|
|
16426
|
+
// namespace.
|
|
16427
|
+
const EXACT_MATCH_EVENT_KEYS = new Set(["ada:message:sent", "ada:message:received"]);
|
|
16398
16428
|
function publishEvent(eventKey, data) {
|
|
16399
16429
|
subscriptions.forEach(subscription => {
|
|
16400
|
-
|
|
16401
|
-
//
|
|
16402
|
-
//
|
|
16403
|
-
//
|
|
16404
|
-
|
|
16405
|
-
|
|
16430
|
+
const matches = EXACT_MATCH_EVENT_KEYS.has(eventKey) ?
|
|
16431
|
+
// Sensitive events require an exact subscription key match —
|
|
16432
|
+
// never deliver via a prefix subscription to e.g. "ada:" or
|
|
16433
|
+
// "ada:message".
|
|
16434
|
+
subscription.eventKey === eventKey :
|
|
16435
|
+
// Prefix match remains the default so subscribers can listen to
|
|
16436
|
+
// a namespace like `ada:campaigns` and catch
|
|
16437
|
+
// `ada:campaigns:opened` / `:engaged` / `:shown`.
|
|
16438
|
+
eventKey.startsWith(subscription.eventKey);
|
|
16439
|
+
if (matches) {
|
|
16406
16440
|
try {
|
|
16407
16441
|
subscription.callback(data, {
|
|
16408
16442
|
eventKey
|
|
@@ -16509,7 +16543,7 @@ function getEmbedURL(_ref) {
|
|
|
16509
16543
|
} else {
|
|
16510
16544
|
host = `http://${handle}.localhost:${ports.localhost.default}`;
|
|
16511
16545
|
}
|
|
16512
|
-
return `${host}/embed/${frameName}/${"
|
|
16546
|
+
return `${host}/embed/${frameName}/${"00422f5"}/index.html`;
|
|
16513
16547
|
}
|
|
16514
16548
|
function constructQueryString(query) {
|
|
16515
16549
|
return Object.keys(query).map(key => {
|
|
@@ -16720,6 +16754,15 @@ const mutations = (state, action) => {
|
|
|
16720
16754
|
switch (action.type) {
|
|
16721
16755
|
case ActionTypes.TOGGLE_CHAT_TYPE:
|
|
16722
16756
|
{
|
|
16757
|
+
// MES-981 P1 #9 follow-up: defensive guard against future accidental
|
|
16758
|
+
// TOGGLE_CHAT_ACTION dispatches in headless mode. The host page has
|
|
16759
|
+
// no drawer to toggle, so flipping isDrawerOpen / drawerHasBeenOpened
|
|
16760
|
+
// and persisting `ada-embed_is-drawer-open: true` to localStorage
|
|
16761
|
+
// would leak across reloads with no visible effect. start() doesn't
|
|
16762
|
+
// dispatch this in headless any more, but the mutation stays robust.
|
|
16763
|
+
if (state.adaSettings.headless) {
|
|
16764
|
+
return state;
|
|
16765
|
+
}
|
|
16723
16766
|
let {
|
|
16724
16767
|
hasChatOpenedAfterProactiveMessagesShown
|
|
16725
16768
|
} = state;
|
|
@@ -17011,6 +17054,8 @@ const getInitialState = adaSettings => ({
|
|
|
17011
17054
|
language: undefined,
|
|
17012
17055
|
greeting: undefined,
|
|
17013
17056
|
crossWindowPersistence: true,
|
|
17057
|
+
headless: false,
|
|
17058
|
+
enableProgrammaticControl: false,
|
|
17014
17059
|
hideMask: true,
|
|
17015
17060
|
metaFields: {},
|
|
17016
17061
|
sensitiveMetaFields: {},
|
|
@@ -17052,6 +17097,58 @@ const getInitialState = adaSettings => ({
|
|
|
17052
17097
|
deviceToken: null,
|
|
17053
17098
|
showFallbackOnTimeout: true
|
|
17054
17099
|
});
|
|
17100
|
+
// EXTERNAL MODULE: ./node_modules/lodash.memoize/index.js
|
|
17101
|
+
var lodash_memoize = __webpack_require__(7654);
|
|
17102
|
+
var lodash_memoize_default = /*#__PURE__*/__webpack_require__.n(lodash_memoize);
|
|
17103
|
+
;// CONCATENATED MODULE: ./src/services/logger/index.ts
|
|
17104
|
+
|
|
17105
|
+
function logger_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
17106
|
+
function logger_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? logger_ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : logger_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17107
|
+
|
|
17108
|
+
|
|
17109
|
+
const DEFAULT_LOG_SAMPLE_RATE = 0.01;
|
|
17110
|
+
const DD_BASE_URL = "https://browser-http-intake.logs.datadoghq.com/v1/input/";
|
|
17111
|
+
const DD_TOKEN = "pubfe23baedd2ea322bebb5ed2020fa2fa1";
|
|
17112
|
+
let globalLogContext = {};
|
|
17113
|
+
function setGlobalLogContext(context) {
|
|
17114
|
+
globalLogContext = logger_objectSpread({}, context);
|
|
17115
|
+
}
|
|
17116
|
+
function clearGlobalLogContext() {
|
|
17117
|
+
globalLogContext = {};
|
|
17118
|
+
}
|
|
17119
|
+
|
|
17120
|
+
// We need memoization to ensure consistency of logs
|
|
17121
|
+
const shouldLog = lodash_memoize_default()(sampleRate => {
|
|
17122
|
+
if (!DD_TOKEN || sampleRate === 0) {
|
|
17123
|
+
return false;
|
|
17124
|
+
}
|
|
17125
|
+
return Math.random() < (sampleRate || DEFAULT_LOG_SAMPLE_RATE);
|
|
17126
|
+
});
|
|
17127
|
+
|
|
17128
|
+
/**
|
|
17129
|
+
* Sends log to Datadog
|
|
17130
|
+
*/
|
|
17131
|
+
async function log(message, extra, options) {
|
|
17132
|
+
if (!shouldLog(options === null || options === void 0 ? void 0 : options.sampleRate)) {
|
|
17133
|
+
return;
|
|
17134
|
+
}
|
|
17135
|
+
await httpRequest({
|
|
17136
|
+
url: `${DD_BASE_URL}${DD_TOKEN}?ddsource=browser&ddtags=version:1.5.0,env:${"production"}`,
|
|
17137
|
+
method: "POST",
|
|
17138
|
+
body: JSON.stringify(logger_objectSpread(logger_objectSpread(logger_objectSpread({
|
|
17139
|
+
message
|
|
17140
|
+
}, extra), globalLogContext), {}, {
|
|
17141
|
+
level: (options === null || options === void 0 ? void 0 : options.level) || "info",
|
|
17142
|
+
sampleRate: (options === null || options === void 0 ? void 0 : options.sampleRate) || DEFAULT_LOG_SAMPLE_RATE,
|
|
17143
|
+
service: "embed",
|
|
17144
|
+
env: "production",
|
|
17145
|
+
embedVersion: 2,
|
|
17146
|
+
version: "1.14.3",
|
|
17147
|
+
isNpm: true,
|
|
17148
|
+
commitHash: "00422f5"
|
|
17149
|
+
}))
|
|
17150
|
+
});
|
|
17151
|
+
}
|
|
17055
17152
|
;// CONCATENATED MODULE: ./src/common/helpers/get-intro-for-url.ts
|
|
17056
17153
|
function getProcessedPath(path) {
|
|
17057
17154
|
const regex = /^http(s)?:\/\/(www.)?/;
|
|
@@ -17651,58 +17748,6 @@ function getButtonText(client) {
|
|
|
17651
17748
|
}
|
|
17652
17749
|
return buttonTextMap[languageKey];
|
|
17653
17750
|
}
|
|
17654
|
-
// EXTERNAL MODULE: ./node_modules/lodash.memoize/index.js
|
|
17655
|
-
var lodash_memoize = __webpack_require__(7654);
|
|
17656
|
-
var lodash_memoize_default = /*#__PURE__*/__webpack_require__.n(lodash_memoize);
|
|
17657
|
-
;// CONCATENATED MODULE: ./src/services/logger/index.ts
|
|
17658
|
-
|
|
17659
|
-
function logger_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
17660
|
-
function logger_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? logger_ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : logger_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
const DEFAULT_LOG_SAMPLE_RATE = 0.01;
|
|
17664
|
-
const DD_BASE_URL = "https://browser-http-intake.logs.datadoghq.com/v1/input/";
|
|
17665
|
-
const DD_TOKEN = "pubfe23baedd2ea322bebb5ed2020fa2fa1";
|
|
17666
|
-
let globalLogContext = {};
|
|
17667
|
-
function setGlobalLogContext(context) {
|
|
17668
|
-
globalLogContext = logger_objectSpread({}, context);
|
|
17669
|
-
}
|
|
17670
|
-
function clearGlobalLogContext() {
|
|
17671
|
-
globalLogContext = {};
|
|
17672
|
-
}
|
|
17673
|
-
|
|
17674
|
-
// We need memoization to ensure consistency of logs
|
|
17675
|
-
const shouldLog = lodash_memoize_default()(sampleRate => {
|
|
17676
|
-
if (!DD_TOKEN || sampleRate === 0) {
|
|
17677
|
-
return false;
|
|
17678
|
-
}
|
|
17679
|
-
return Math.random() < (sampleRate || DEFAULT_LOG_SAMPLE_RATE);
|
|
17680
|
-
});
|
|
17681
|
-
|
|
17682
|
-
/**
|
|
17683
|
-
* Sends log to Datadog
|
|
17684
|
-
*/
|
|
17685
|
-
async function log(message, extra, options) {
|
|
17686
|
-
if (!shouldLog(options === null || options === void 0 ? void 0 : options.sampleRate)) {
|
|
17687
|
-
return;
|
|
17688
|
-
}
|
|
17689
|
-
await httpRequest({
|
|
17690
|
-
url: `${DD_BASE_URL}${DD_TOKEN}?ddsource=browser&ddtags=version:1.5.0,env:${"production"}`,
|
|
17691
|
-
method: "POST",
|
|
17692
|
-
body: JSON.stringify(logger_objectSpread(logger_objectSpread(logger_objectSpread({
|
|
17693
|
-
message
|
|
17694
|
-
}, extra), globalLogContext), {}, {
|
|
17695
|
-
level: (options === null || options === void 0 ? void 0 : options.level) || "info",
|
|
17696
|
-
sampleRate: (options === null || options === void 0 ? void 0 : options.sampleRate) || DEFAULT_LOG_SAMPLE_RATE,
|
|
17697
|
-
service: "embed",
|
|
17698
|
-
env: "production",
|
|
17699
|
-
embedVersion: 2,
|
|
17700
|
-
version: "1.13.5",
|
|
17701
|
-
isNpm: true,
|
|
17702
|
-
commitHash: "7576a55"
|
|
17703
|
-
}))
|
|
17704
|
-
});
|
|
17705
|
-
}
|
|
17706
17751
|
;// CONCATENATED MODULE: ./src/client/helpers/alternative-bot-rollout/index.ts
|
|
17707
17752
|
|
|
17708
17753
|
function alternative_bot_rollout_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -19263,6 +19308,12 @@ function deriveMessagingMobileShell(mobilePackage) {
|
|
|
19263
19308
|
function deriveLegacyMobileShell(surface, hostPlatform) {
|
|
19264
19309
|
return surface === "mobile" && hostPlatform !== "web" ? "legacy-sdk" : undefined;
|
|
19265
19310
|
}
|
|
19311
|
+
|
|
19312
|
+
// MES-981 P1 #10: extracted to keep resolveHostTelemetryFromStartOptions
|
|
19313
|
+
// under the sonarjs cognitive-complexity threshold.
|
|
19314
|
+
function deriveMode(adaSettings) {
|
|
19315
|
+
return adaSettings.headless ? "headless" : undefined;
|
|
19316
|
+
}
|
|
19266
19317
|
function normalizeHostTelemetry(value) {
|
|
19267
19318
|
const record = asRecord(value);
|
|
19268
19319
|
if (!record) {
|
|
@@ -19345,11 +19396,14 @@ function resolveHostTelemetryFromStartOptions(adaSettings) {
|
|
|
19345
19396
|
const mobilePackage = explicit === null || explicit === void 0 ? void 0 : explicit.mobilePackage;
|
|
19346
19397
|
const mobileVersion = explicit === null || explicit === void 0 ? void 0 : explicit.mobileVersion;
|
|
19347
19398
|
const mobileShell = deriveMessagingMobileShell(mobilePackage) ?? (explicit === null || explicit === void 0 ? void 0 : explicit.mobileShell) ?? (legacyFingerprint === null || legacyFingerprint === void 0 ? void 0 : legacyFingerprint.mobileShell) ?? (!hasExplicitHostTelemetry ? deriveLegacyMobileShell(surface, hostPlatform) : undefined);
|
|
19348
|
-
|
|
19399
|
+
const mode = deriveMode(adaSettings);
|
|
19400
|
+
return host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread({
|
|
19349
19401
|
surface,
|
|
19350
19402
|
hostPlatform,
|
|
19351
19403
|
webSdkOrigin
|
|
19352
|
-
},
|
|
19404
|
+
}, mode ? {
|
|
19405
|
+
mode
|
|
19406
|
+
} : {}), mobileShell ? {
|
|
19353
19407
|
mobileShell
|
|
19354
19408
|
} : {}), mobilePackage ? {
|
|
19355
19409
|
mobilePackage
|
|
@@ -19367,7 +19421,11 @@ function toMonitoringContext(hostTelemetry) {
|
|
|
19367
19421
|
return host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread({
|
|
19368
19422
|
surface: hostTelemetry.surface,
|
|
19369
19423
|
host_platform: hostTelemetry.hostPlatform,
|
|
19370
|
-
web_sdk_origin: hostTelemetry.webSdkOrigin
|
|
19424
|
+
web_sdk_origin: hostTelemetry.webSdkOrigin,
|
|
19425
|
+
// MES-981 P1 #10: every log/RUM line carries `mode`; default to
|
|
19426
|
+
// "visible" when not set on the context so dashboards can filter
|
|
19427
|
+
// by mode without a separate query.
|
|
19428
|
+
mode: hostTelemetry.mode ?? "visible"
|
|
19371
19429
|
}, hostTelemetry.mobileShell ? {
|
|
19372
19430
|
mobile_shell: hostTelemetry.mobileShell
|
|
19373
19431
|
} : {}), hostTelemetry.mobilePackage ? {
|
|
@@ -19378,6 +19436,32 @@ function toMonitoringContext(hostTelemetry) {
|
|
|
19378
19436
|
}
|
|
19379
19437
|
;// CONCATENATED MODULE: ./src/common/helpers/is-mobile.ts
|
|
19380
19438
|
const isMobile = /(iPhone)|(iPod)|(android)|(webOS)/i.exec(navigator.userAgent) !== null;
|
|
19439
|
+
;// CONCATENATED MODULE: ./src/common/helpers/programmatic-control.ts
|
|
19440
|
+
|
|
19441
|
+
|
|
19442
|
+
// MES-981: privileged transcript-bearing surface is opt-in. Host pages
|
|
19443
|
+
// must explicitly accept the exposure risk via
|
|
19444
|
+
// `start({ enableProgrammaticControl: true })`, because every third-party
|
|
19445
|
+
// script in the host page (analytics, GTM, ad pixels, session replay,
|
|
19446
|
+
// supply-chain XSS) inherits the host's trust.
|
|
19447
|
+
const PROGRAMMATIC_CONTROL_DISABLED_ERROR = new AdaEmbedError("ProgrammaticControlNotEnabled: this API requires `start({ enableProgrammaticControl: true })`.");
|
|
19448
|
+
function isProgrammaticControlEnabled(adaSettings) {
|
|
19449
|
+
return Boolean(adaSettings === null || adaSettings === void 0 ? void 0 : adaSettings.enableProgrammaticControl);
|
|
19450
|
+
}
|
|
19451
|
+
function requireProgrammaticControl(adaSettings) {
|
|
19452
|
+
if (!isProgrammaticControlEnabled(adaSettings)) {
|
|
19453
|
+
throw PROGRAMMATIC_CONTROL_DISABLED_ERROR;
|
|
19454
|
+
}
|
|
19455
|
+
}
|
|
19456
|
+
|
|
19457
|
+
// ada:message:sent and ada:message:received carry user/agent transcript
|
|
19458
|
+
// bodies. Other ada:* events (ready, connection, conversation, typing)
|
|
19459
|
+
// only carry id/state/timing data and are not subject to this gate.
|
|
19460
|
+
const TRANSCRIPT_EVENT_KEYS = new Set(["ada:message:sent", "ada:message:received"]);
|
|
19461
|
+
function shouldDeliverTranscriptEvent(eventKey, adaSettings) {
|
|
19462
|
+
if (!TRANSCRIPT_EVENT_KEYS.has(eventKey)) return true;
|
|
19463
|
+
return isProgrammaticControlEnabled(adaSettings);
|
|
19464
|
+
}
|
|
19381
19465
|
;// CONCATENATED MODULE: ./src/client/components/ChatFrame/chatFrameEvents/chatterEvent/index.ts
|
|
19382
19466
|
|
|
19383
19467
|
|
|
@@ -19548,6 +19632,31 @@ function getFallbackDataURI() {
|
|
|
19548
19632
|
|
|
19549
19633
|
|
|
19550
19634
|
|
|
19635
|
+
|
|
19636
|
+
// MES-981: route an inbound PUBLISH_EVENT from the chat iframe to the host's
|
|
19637
|
+
// event-subscription registry. Pulled out of handleChatEvent so its switch
|
|
19638
|
+
// stays under the sonarjs cognitive-complexity threshold.
|
|
19639
|
+
//
|
|
19640
|
+
// Two host-facing transforms happen here:
|
|
19641
|
+
// - shouldDeliverTranscriptEvent drops ada:message:* unless the host
|
|
19642
|
+
// opted in via enableProgrammaticControl (P0 #4).
|
|
19643
|
+
// - ada:ready is re-emitted with `{ mode: "headless" | "visible" }` so
|
|
19644
|
+
// subscribers can branch without inspecting adaSettings (P1 #10).
|
|
19645
|
+
function forwardPublishEvent(publishPayload, adaSettings) {
|
|
19646
|
+
const {
|
|
19647
|
+
eventKey,
|
|
19648
|
+
data
|
|
19649
|
+
} = publishPayload;
|
|
19650
|
+
if (!shouldDeliverTranscriptEvent(eventKey, adaSettings)) return;
|
|
19651
|
+
if (eventKey === "ada:ready") {
|
|
19652
|
+
const mode = adaSettings.headless ? "headless" : "visible";
|
|
19653
|
+
publishEvent(eventKey, {
|
|
19654
|
+
mode
|
|
19655
|
+
});
|
|
19656
|
+
return;
|
|
19657
|
+
}
|
|
19658
|
+
publishEvent(eventKey, data);
|
|
19659
|
+
}
|
|
19551
19660
|
class ChatFrame extends preact_module_d {
|
|
19552
19661
|
constructor() {
|
|
19553
19662
|
super(...arguments);
|
|
@@ -19597,7 +19706,7 @@ class ChatFrame extends preact_module_d {
|
|
|
19597
19706
|
log("Chat frame mount", {
|
|
19598
19707
|
handle,
|
|
19599
19708
|
chatUrl: this.url,
|
|
19600
|
-
embedVersion: "
|
|
19709
|
+
embedVersion: "00422f5".slice(0, 7),
|
|
19601
19710
|
embedSettings: adaSettings
|
|
19602
19711
|
});
|
|
19603
19712
|
|
|
@@ -19685,7 +19794,7 @@ class ChatFrame extends preact_module_d {
|
|
|
19685
19794
|
const hostPageUrlParams = new URL(window.location.href).searchParams;
|
|
19686
19795
|
const smsToken = hostPageUrlParams.get("adaSMSToken");
|
|
19687
19796
|
const queryParams = {
|
|
19688
|
-
embedVersion: "
|
|
19797
|
+
embedVersion: "00422f5".slice(0, 7),
|
|
19689
19798
|
greeting,
|
|
19690
19799
|
language,
|
|
19691
19800
|
skipGreeting,
|
|
@@ -20004,11 +20113,7 @@ class ChatFrame extends preact_module_d {
|
|
|
20004
20113
|
}
|
|
20005
20114
|
case PUBLISH_EVENT:
|
|
20006
20115
|
{
|
|
20007
|
-
|
|
20008
|
-
eventKey,
|
|
20009
|
-
data
|
|
20010
|
-
} = payload;
|
|
20011
|
-
publishEvent(eventKey, data);
|
|
20116
|
+
forwardPublishEvent(payload, adaSettings);
|
|
20012
20117
|
break;
|
|
20013
20118
|
}
|
|
20014
20119
|
case ANALYTICS_EVENT:
|
|
@@ -20658,10 +20763,36 @@ class XStorageFrame extends preact_module_d {
|
|
|
20658
20763
|
}
|
|
20659
20764
|
}
|
|
20660
20765
|
/* harmony default export */ var components_XStorageFrame = (connect()(XStorageFrame));
|
|
20766
|
+
;// CONCATENATED MODULE: ./src/client/components/Container/host-facing-meta-fields.ts
|
|
20767
|
+
|
|
20768
|
+
function host_facing_meta_fields_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
20769
|
+
function host_facing_meta_fields_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? host_facing_meta_fields_ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : host_facing_meta_fields_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
20770
|
+
// MES-981 metaFields helpers. Extracted from Container/index.tsx so the
|
|
20771
|
+
// transforms don't push that already-large module over its max-lines budget.
|
|
20772
|
+
|
|
20773
|
+
/** Strips the internal `proactive_conversation` tracker for getMetaFields(). */
|
|
20774
|
+
function toHostFacingMetaFields(metaFields) {
|
|
20775
|
+
const hostFacing = host_facing_meta_fields_objectSpread({}, metaFields);
|
|
20776
|
+
delete hostFacing.proactive_conversation;
|
|
20777
|
+
return hostFacing;
|
|
20778
|
+
}
|
|
20779
|
+
|
|
20780
|
+
/** Merges a proactive_conversation key onto existing metaFields. */
|
|
20781
|
+
function withProactiveKey(metaFields, key) {
|
|
20782
|
+
return host_facing_meta_fields_objectSpread(host_facing_meta_fields_objectSpread({}, metaFields), {}, {
|
|
20783
|
+
proactive_conversation: key
|
|
20784
|
+
});
|
|
20785
|
+
}
|
|
20661
20786
|
;// CONCATENATED MODULE: ./src/client/components/Container/index.tsx
|
|
20662
20787
|
|
|
20663
20788
|
function Container_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
20664
20789
|
function Container_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? Container_ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : Container_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
20790
|
+
/* eslint-disable max-lines -- MES-981: file was already at the 1000-line
|
|
20791
|
+
max-lines cap on main; the additive programmatic-control work pushes it
|
|
20792
|
+
just over. A targeted refactor of this Container is being tracked
|
|
20793
|
+
separately and is out of scope for this PR. */
|
|
20794
|
+
|
|
20795
|
+
|
|
20665
20796
|
|
|
20666
20797
|
|
|
20667
20798
|
|
|
@@ -20740,11 +20871,11 @@ class Container extends preact_module_d {
|
|
|
20740
20871
|
adaSettings
|
|
20741
20872
|
});
|
|
20742
20873
|
|
|
20743
|
-
//
|
|
20874
|
+
// MES-981: seed state.metaFields with host-supplied values + reset tracker.
|
|
20744
20875
|
setGlobalState({
|
|
20745
|
-
metaFields: {
|
|
20876
|
+
metaFields: Container_objectSpread(Container_objectSpread({}, adaSettings.metaFields ?? {}), {}, {
|
|
20746
20877
|
proactive_conversation: null
|
|
20747
|
-
}
|
|
20878
|
+
})
|
|
20748
20879
|
});
|
|
20749
20880
|
|
|
20750
20881
|
// We want to make sure this happens before any publishEvent calls
|
|
@@ -20853,7 +20984,9 @@ class Container extends preact_module_d {
|
|
|
20853
20984
|
// campaigns, we don't need this for engage (response_id) campaigns
|
|
20854
20985
|
campaignToTrigger.response_id || appConnectionState === ConnectionState.Done) && !isDrawerOpen && !chatterInLiveChat) {
|
|
20855
20986
|
triggerCampaignImpl({
|
|
20856
|
-
adaSettings,
|
|
20987
|
+
adaSettings: Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
|
|
20988
|
+
handle: (client === null || client === void 0 ? void 0 : client.handle) || adaSettings.handle
|
|
20989
|
+
}),
|
|
20857
20990
|
chatterToken,
|
|
20858
20991
|
campaign: campaignToTrigger,
|
|
20859
20992
|
ignoreStatus: Boolean(campaignTriggerOptions.ignoreStatus),
|
|
@@ -20901,12 +21034,11 @@ class Container extends preact_module_d {
|
|
|
20901
21034
|
if (isChatWebsocketConnected && isDrawerOpen && recentProactiveConversationConfig) {
|
|
20902
21035
|
const chatChannel = messageService.getChannel(CHAT_IFRAME);
|
|
20903
21036
|
if (chatChannel) {
|
|
20904
|
-
|
|
20905
|
-
|
|
21037
|
+
const {
|
|
21038
|
+
metaFields
|
|
21039
|
+
} = this.props;
|
|
20906
21040
|
setGlobalState({
|
|
20907
|
-
metaFields:
|
|
20908
|
-
proactive_conversation: recentProactiveConversationConfig.key
|
|
20909
|
-
}
|
|
21041
|
+
metaFields: withProactiveKey(metaFields, recentProactiveConversationConfig.key)
|
|
20910
21042
|
});
|
|
20911
21043
|
chatChannel.postMessage(INJECT_PROACTIVE_CONVERSATION, {
|
|
20912
21044
|
key: recentProactiveConversationConfig.key,
|
|
@@ -20961,6 +21093,13 @@ class Container extends preact_module_d {
|
|
|
20961
21093
|
if (hideChatOverride) {
|
|
20962
21094
|
return false;
|
|
20963
21095
|
}
|
|
21096
|
+
|
|
21097
|
+
// MES-981: in headless mode the host page never opens the drawer, so
|
|
21098
|
+
// treat headless as an implicit preload to ensure the chat iframe loads
|
|
21099
|
+
// and registers its frame-channel handler.
|
|
21100
|
+
if (adaSettings.headless) {
|
|
21101
|
+
return true;
|
|
21102
|
+
}
|
|
20964
21103
|
if (preload) {
|
|
20965
21104
|
return true;
|
|
20966
21105
|
}
|
|
@@ -21101,7 +21240,9 @@ class Container extends preact_module_d {
|
|
|
21101
21240
|
if (!client) {
|
|
21102
21241
|
throw new AdaEmbedError("`client` is not defined");
|
|
21103
21242
|
}
|
|
21104
|
-
const campaignToTrigger = getCampaignToTrigger(
|
|
21243
|
+
const campaignToTrigger = getCampaignToTrigger(Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
|
|
21244
|
+
handle: client.handle
|
|
21245
|
+
}), client.marketing_campaigns, params, !client.features.afm_proactive_messaging);
|
|
21105
21246
|
if (campaignToTrigger) {
|
|
21106
21247
|
if (useDelay) {
|
|
21107
21248
|
setTimeout(() => {
|
|
@@ -21238,9 +21379,13 @@ class Container extends preact_module_d {
|
|
|
21238
21379
|
drawerHasBeenOpened,
|
|
21239
21380
|
chatterToken
|
|
21240
21381
|
} = this.props;
|
|
21382
|
+
// MES-981 P1 #9: in headless mode the UI is intentionally hidden,
|
|
21383
|
+
// so `isChatOpen` always returns false regardless of any drawer
|
|
21384
|
+
// state. Matches the contract that isOpen() returns in headless.
|
|
21385
|
+
const isHeadless = Boolean(adaSettings.headless);
|
|
21241
21386
|
const contentToReturn = {
|
|
21242
|
-
isDrawerOpen,
|
|
21243
|
-
isChatOpen: isDrawerOpen || Boolean(parentElement),
|
|
21387
|
+
isDrawerOpen: isHeadless ? false : isDrawerOpen,
|
|
21388
|
+
isChatOpen: isHeadless ? false : isDrawerOpen || Boolean(parentElement),
|
|
21244
21389
|
hasActiveChatter: Boolean(chatterToken),
|
|
21245
21390
|
hasClosedChat: drawerHasBeenOpened && !isDrawerOpen
|
|
21246
21391
|
};
|
|
@@ -21261,6 +21406,14 @@ class Container extends preact_module_d {
|
|
|
21261
21406
|
localChannel.postMessage(SET_META_FIELDS_RESPONSE, null, id);
|
|
21262
21407
|
break;
|
|
21263
21408
|
}
|
|
21409
|
+
case GET_META_FIELDS:
|
|
21410
|
+
{
|
|
21411
|
+
const {
|
|
21412
|
+
metaFields
|
|
21413
|
+
} = this.props;
|
|
21414
|
+
localChannel.postMessage(GET_META_FIELDS_RESPONSE, toHostFacingMetaFields(metaFields), id);
|
|
21415
|
+
break;
|
|
21416
|
+
}
|
|
21264
21417
|
case "SET_SENSITIVE_META_FIELDS":
|
|
21265
21418
|
{
|
|
21266
21419
|
const {
|
|
@@ -21826,6 +21979,7 @@ function embed_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { va
|
|
|
21826
21979
|
|
|
21827
21980
|
|
|
21828
21981
|
|
|
21982
|
+
|
|
21829
21983
|
function renderApp(_ref) {
|
|
21830
21984
|
let {
|
|
21831
21985
|
adaSettings,
|
|
@@ -21850,6 +22004,25 @@ function renderApp(_ref) {
|
|
|
21850
22004
|
if (!parentContainer) {
|
|
21851
22005
|
throw new AdaEmbedError("`parentContainer` is null");
|
|
21852
22006
|
}
|
|
22007
|
+
|
|
22008
|
+
// MES-981: in headless mode the React tree still mounts (so the websocket,
|
|
22009
|
+
// Redux, and FC handlers run) but the entry container is moved off-screen
|
|
22010
|
+
// — the host page controls its own UI on top of the programmatic surface.
|
|
22011
|
+
// We use absolute positioning + 0x0 + clip instead of `display: none`
|
|
22012
|
+
// because Chrome (and Safari) defer iframe loads for elements that are
|
|
22013
|
+
// display:none, which would block the chat iframe from ever registering
|
|
22014
|
+
// its frame-channel handlers.
|
|
22015
|
+
if (adaSettings.headless) {
|
|
22016
|
+
entryContainer.style.position = "absolute";
|
|
22017
|
+
entryContainer.style.left = "0";
|
|
22018
|
+
entryContainer.style.top = "0";
|
|
22019
|
+
entryContainer.style.width = "0";
|
|
22020
|
+
entryContainer.style.height = "0";
|
|
22021
|
+
entryContainer.style.overflow = "hidden";
|
|
22022
|
+
entryContainer.style.clip = "rect(0, 0, 0, 0)";
|
|
22023
|
+
entryContainer.style.pointerEvents = "none";
|
|
22024
|
+
entryContainer.setAttribute("aria-hidden", "true");
|
|
22025
|
+
}
|
|
21853
22026
|
parentContainer.appendChild(entryContainer);
|
|
21854
22027
|
M(v(StoreContext.Provider, {
|
|
21855
22028
|
value: store
|
|
@@ -21899,6 +22072,31 @@ function createEmbed(adaSettings) {
|
|
|
21899
22072
|
initializationReject: reject
|
|
21900
22073
|
});
|
|
21901
22074
|
});
|
|
22075
|
+
|
|
22076
|
+
// MES-981 P1 #10: emit a high-priority log entry on every headless
|
|
22077
|
+
// session start so ops can spot abuse patterns (compromised host site
|
|
22078
|
+
// silently running chatter sessions under the visiting user's token).
|
|
22079
|
+
// Sampled at 1.0 so we never miss one; the volume is bounded by the
|
|
22080
|
+
// host explicitly opting in.
|
|
22081
|
+
if (adaSettings.headless) {
|
|
22082
|
+
log("headless_session_initialized", {
|
|
22083
|
+
handle: adaSettings.handle,
|
|
22084
|
+
parent_origin: window.location.origin
|
|
22085
|
+
}, {
|
|
22086
|
+
sampleRate: 1,
|
|
22087
|
+
level: "info"
|
|
22088
|
+
});
|
|
22089
|
+
}
|
|
22090
|
+
|
|
22091
|
+
// MES-981 P1 #9: headless boot no longer reuses TOGGLE_CHAT_ACTION.
|
|
22092
|
+
// The old dispatch persisted drawer-open state to localStorage and set
|
|
22093
|
+
// `drawerHasBeenOpened` / `focusIsOnAda` even though there is no
|
|
22094
|
+
// visible drawer — which then leaked across reloads. The chat iframe
|
|
22095
|
+
// mounts directly via `shouldRenderChatFrame` returning true for
|
|
22096
|
+
// headless (Container/index.tsx), and the iframe's own init drives
|
|
22097
|
+
// chatter creation, pusher subscription, and greeting fire. No drawer
|
|
22098
|
+
// state needs to flip.
|
|
22099
|
+
|
|
21902
22100
|
const debounceCampaignTrigger = lodash_debounce_default()(async function (campaignKey) {
|
|
21903
22101
|
let triggerCampaignParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
21904
22102
|
await initialized;
|
|
@@ -21921,6 +22119,10 @@ function createEmbed(adaSettings) {
|
|
|
21921
22119
|
await initialized;
|
|
21922
22120
|
await localChannel.fetch(SET_META_FIELDS, SET_META_FIELDS_RESPONSE, options);
|
|
21923
22121
|
},
|
|
22122
|
+
async getMetaFields() {
|
|
22123
|
+
await initialized;
|
|
22124
|
+
return await localChannel.fetch(GET_META_FIELDS, GET_META_FIELDS_RESPONSE);
|
|
22125
|
+
},
|
|
21924
22126
|
async setSensitiveMetaFields(options) {
|
|
21925
22127
|
await initialized;
|
|
21926
22128
|
await localChannel.fetch("SET_SENSITIVE_META_FIELDS", "SET_SENSITIVE_META_FIELDS_RESPONSE", options);
|
|
@@ -21990,6 +22192,30 @@ function createEmbed(adaSettings) {
|
|
|
21990
22192
|
}
|
|
21991
22193
|
};
|
|
21992
22194
|
}
|
|
22195
|
+
;// CONCATENATED MODULE: ./src/common/helpers/with-timeout.ts
|
|
22196
|
+
|
|
22197
|
+
|
|
22198
|
+
/**
|
|
22199
|
+
* Race `promise` against a timeout. If the timeout fires first, reject
|
|
22200
|
+
* with an AdaEmbedError carrying `errorMessage`. If the promise settles
|
|
22201
|
+
* first (resolve or reject), clear the pending timer so it doesn't
|
|
22202
|
+
* keep the event loop alive past resolution.
|
|
22203
|
+
*
|
|
22204
|
+
* MES-981 P1 #7: used to cap host-supplied beforeSend hooks so a
|
|
22205
|
+
* never-resolving delegate can't hang sendMessage forever.
|
|
22206
|
+
*/
|
|
22207
|
+
function withTimeout(promise, ms, errorMessage) {
|
|
22208
|
+
return new Promise((resolve, reject) => {
|
|
22209
|
+
const handle = setTimeout(() => reject(new AdaEmbedError(errorMessage)), ms);
|
|
22210
|
+
Promise.resolve(promise).then(value => {
|
|
22211
|
+
clearTimeout(handle);
|
|
22212
|
+
resolve(value);
|
|
22213
|
+
}, err => {
|
|
22214
|
+
clearTimeout(handle);
|
|
22215
|
+
reject(err);
|
|
22216
|
+
});
|
|
22217
|
+
});
|
|
22218
|
+
}
|
|
21993
22219
|
;// CONCATENATED MODULE: ./src/interface.ts
|
|
21994
22220
|
|
|
21995
22221
|
|
|
@@ -21998,13 +22224,56 @@ function createEmbed(adaSettings) {
|
|
|
21998
22224
|
|
|
21999
22225
|
|
|
22000
22226
|
|
|
22227
|
+
|
|
22228
|
+
|
|
22001
22229
|
const EMBED_NOT_INITIALIZED_ERROR = new AdaEmbedError("Actions cannot be called until Embed has been instantiated. Try running `adaEmbed.start({...})`.");
|
|
22002
22230
|
|
|
22231
|
+
// MES-981 P1 #7: run the host's beforeSend hook with a 5s timeout, validate
|
|
22232
|
+
// its return value, and surface DelegateRejected / DelegateTimeout / shape
|
|
22233
|
+
// errors with the same wording as before. Extracted from sendMessage to
|
|
22234
|
+
// keep that method below the sonarjs cognitive-complexity threshold.
|
|
22235
|
+
async function applyBeforeSend(beforeSend, originalText) {
|
|
22236
|
+
let result;
|
|
22237
|
+
try {
|
|
22238
|
+
result = await withTimeout(beforeSend({
|
|
22239
|
+
text: originalText
|
|
22240
|
+
}), 5000, "DelegateTimeout");
|
|
22241
|
+
} catch (err) {
|
|
22242
|
+
if (err instanceof AdaEmbedError && err.message === "DelegateTimeout") {
|
|
22243
|
+
log("Delegate beforeSend timed out", {
|
|
22244
|
+
timeoutMs: 5000
|
|
22245
|
+
});
|
|
22246
|
+
} else {
|
|
22247
|
+
log("Delegate beforeSend threw", {
|
|
22248
|
+
error: err instanceof Error ? err.message : String(err)
|
|
22249
|
+
});
|
|
22250
|
+
}
|
|
22251
|
+
throw err;
|
|
22252
|
+
}
|
|
22253
|
+
if (result === false) {
|
|
22254
|
+
log("Delegate beforeSend canceled the send", {});
|
|
22255
|
+
throw new AdaEmbedError("DelegateRejected");
|
|
22256
|
+
}
|
|
22257
|
+
const candidate = result;
|
|
22258
|
+
if (!candidate || typeof candidate !== "object" || typeof candidate.text !== "string") {
|
|
22259
|
+
throw new AdaEmbedError("Delegate beforeSend must return `{ text: string }`, `false`, or a Promise resolving to one of these.");
|
|
22260
|
+
}
|
|
22261
|
+
const transformed = candidate.text;
|
|
22262
|
+
if (transformed.trim().length === 0) {
|
|
22263
|
+
throw new AdaEmbedError("sendMessage requires non-empty text after delegate transform");
|
|
22264
|
+
}
|
|
22265
|
+
log("Delegate beforeSend completed", {
|
|
22266
|
+
transformed: transformed !== originalText
|
|
22267
|
+
});
|
|
22268
|
+
return transformed;
|
|
22269
|
+
}
|
|
22270
|
+
|
|
22003
22271
|
/**
|
|
22004
22272
|
* Returns the public Embed methods to be bound to the window object.
|
|
22005
22273
|
*/
|
|
22006
22274
|
function createEmbedInterface() {
|
|
22007
22275
|
let embed = null;
|
|
22276
|
+
let delegate = {};
|
|
22008
22277
|
const toggle = async () => {
|
|
22009
22278
|
if (!embed) {
|
|
22010
22279
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22048,6 +22317,9 @@ function createEmbedInterface() {
|
|
|
22048
22317
|
}
|
|
22049
22318
|
const stopPromise = embed.stop();
|
|
22050
22319
|
embed = null;
|
|
22320
|
+
// MES-981: clear the registered delegate so a subsequent start() begins
|
|
22321
|
+
// with a clean interception state.
|
|
22322
|
+
delegate = {};
|
|
22051
22323
|
try {
|
|
22052
22324
|
await stopPromise;
|
|
22053
22325
|
} finally {
|
|
@@ -22067,6 +22339,12 @@ function createEmbedInterface() {
|
|
|
22067
22339
|
}
|
|
22068
22340
|
return embed.setMetaFields(options);
|
|
22069
22341
|
},
|
|
22342
|
+
getMetaFields: async () => {
|
|
22343
|
+
if (!embed) {
|
|
22344
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22345
|
+
}
|
|
22346
|
+
return embed.getMetaFields();
|
|
22347
|
+
},
|
|
22070
22348
|
setSensitiveMetaFields: async options => {
|
|
22071
22349
|
if (!embed) {
|
|
22072
22350
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22079,6 +22357,20 @@ function createEmbedInterface() {
|
|
|
22079
22357
|
}
|
|
22080
22358
|
return embed.getInfo();
|
|
22081
22359
|
},
|
|
22360
|
+
isOpen: async () => {
|
|
22361
|
+
if (!embed) {
|
|
22362
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22363
|
+
}
|
|
22364
|
+
|
|
22365
|
+
// MES-981: in headless mode the entry container is display:none, so
|
|
22366
|
+
// even a parentElement-mounted embed isn't visible to the user. Treat
|
|
22367
|
+
// it as "not open" regardless of the underlying isDrawerOpen flag.
|
|
22368
|
+
if (embed.adaSettings.headless) {
|
|
22369
|
+
return false;
|
|
22370
|
+
}
|
|
22371
|
+
const info = await embed.getInfo();
|
|
22372
|
+
return info.isChatOpen;
|
|
22373
|
+
},
|
|
22082
22374
|
reset: async resetParams => {
|
|
22083
22375
|
if (!embed) {
|
|
22084
22376
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22120,6 +22412,12 @@ function createEmbedInterface() {
|
|
|
22120
22412
|
}
|
|
22121
22413
|
return embed.evaluateCampaignConditions(options);
|
|
22122
22414
|
},
|
|
22415
|
+
// MES-981: the public surface accepts both the upstream AdaEventKey set
|
|
22416
|
+
// and the new ada:* keys (ExtendedAdaEventKey). The underlying event
|
|
22417
|
+
// subscription registry is a string-keyed map at runtime, so casting
|
|
22418
|
+
// through any is safe and lets the implementation reuse the existing
|
|
22419
|
+
// subscribeEvent helper.
|
|
22420
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22123
22421
|
subscribeEvent: async (eventKey, callback) => subscribeEvent(eventKey, callback),
|
|
22124
22422
|
unsubscribeEvent: async id => unsubscribeEvent(id),
|
|
22125
22423
|
closeCampaign: async () => {
|
|
@@ -22146,6 +22444,126 @@ function createEmbedInterface() {
|
|
|
22146
22444
|
language
|
|
22147
22445
|
});
|
|
22148
22446
|
},
|
|
22447
|
+
setComposerText: async text => {
|
|
22448
|
+
if (!embed) {
|
|
22449
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22450
|
+
}
|
|
22451
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22452
|
+
if (embed.adaSettings.headless) {
|
|
22453
|
+
throw new AdaEmbedError("HeadlessModeError: setComposerText is not available in headless mode");
|
|
22454
|
+
}
|
|
22455
|
+
|
|
22456
|
+
// MES-981: wait for chat to finish init before forwarding the
|
|
22457
|
+
// postMessage, matching the existing behaviour of setMetaFields etc.
|
|
22458
|
+
await embed.initialized;
|
|
22459
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22460
|
+
if (!channel) {
|
|
22461
|
+
throw new AdaEmbedError("Chat is not ready yet to have composer text set.");
|
|
22462
|
+
}
|
|
22463
|
+
|
|
22464
|
+
// MES-981 P0 #3: SET_COMPOSER_TEXT is request/response so chat-side
|
|
22465
|
+
// validation failures (INVALID_PAYLOAD, TOO_LONG) reach the caller.
|
|
22466
|
+
const response = await channel.fetch("SET_COMPOSER_TEXT", "SET_COMPOSER_TEXT_RESPONSE", {
|
|
22467
|
+
text
|
|
22468
|
+
});
|
|
22469
|
+
if (!response) {
|
|
22470
|
+
throw new AdaEmbedError("setComposerText timed out — chat frame did not respond in time.");
|
|
22471
|
+
}
|
|
22472
|
+
if ("error" in response) {
|
|
22473
|
+
throw new AdaEmbedError(`setComposerText rejected by chat: ${response.error}`);
|
|
22474
|
+
}
|
|
22475
|
+
},
|
|
22476
|
+
getConversation: async () => {
|
|
22477
|
+
if (!embed) {
|
|
22478
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22479
|
+
}
|
|
22480
|
+
|
|
22481
|
+
// MES-981 P0 #4: getConversation returns the live-agent handoff
|
|
22482
|
+
// identity (id / name / avatarUrl) alongside the conversation id.
|
|
22483
|
+
// Same host-page exposure surface as ada:message:* and getMessages,
|
|
22484
|
+
// so the same opt-in gate applies.
|
|
22485
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22486
|
+
await embed.initialized;
|
|
22487
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22488
|
+
if (!channel) {
|
|
22489
|
+
throw new AdaEmbedError("Chat is not ready yet to read conversation.");
|
|
22490
|
+
}
|
|
22491
|
+
const response = await channel.fetch("GET_CONVERSATION", "GET_CONVERSATION_RESPONSE");
|
|
22492
|
+
if (!response) {
|
|
22493
|
+
throw new AdaEmbedError("getConversation timed out — chat frame did not respond in time.");
|
|
22494
|
+
}
|
|
22495
|
+
return response;
|
|
22496
|
+
},
|
|
22497
|
+
getMessages: async () => {
|
|
22498
|
+
if (!embed) {
|
|
22499
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22500
|
+
}
|
|
22501
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22502
|
+
await embed.initialized;
|
|
22503
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22504
|
+
if (!channel) {
|
|
22505
|
+
throw new AdaEmbedError("Chat is not ready yet to read messages.");
|
|
22506
|
+
}
|
|
22507
|
+
const response = await channel.fetch("GET_MESSAGES", "GET_MESSAGES_RESPONSE");
|
|
22508
|
+
|
|
22509
|
+
// MES-981 P1 #6: channel.fetch resolves to undefined on timeout.
|
|
22510
|
+
// The previous behavior normalized that to [], which made a real
|
|
22511
|
+
// chat-frame failure indistinguishable from an empty transcript.
|
|
22512
|
+
// Fail loudly instead so hosts can branch on the error.
|
|
22513
|
+
if (response === undefined) {
|
|
22514
|
+
throw new AdaEmbedError("getMessages timed out — chat frame did not respond in time.");
|
|
22515
|
+
}
|
|
22516
|
+
return response;
|
|
22517
|
+
},
|
|
22518
|
+
sendMessage: async text => {
|
|
22519
|
+
if (!embed) {
|
|
22520
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22521
|
+
}
|
|
22522
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22523
|
+
|
|
22524
|
+
// MES-981: reject empty AND whitespace-only text so we never POST a
|
|
22525
|
+
// meaningless body to /message/chat/.
|
|
22526
|
+
if (typeof text !== "string" || text.trim().length === 0) {
|
|
22527
|
+
throw new AdaEmbedError("sendMessage requires non-empty text");
|
|
22528
|
+
}
|
|
22529
|
+
|
|
22530
|
+
// MES-981: gate on init BEFORE running the host's beforeSend hook.
|
|
22531
|
+
// Otherwise an init failure (or a missing chat channel) leaves the
|
|
22532
|
+
// host with delegate side-effects — analytics logs, UI optimism — for
|
|
22533
|
+
// a message that can never be sent. Match the gating order used by
|
|
22534
|
+
// every other public method on this surface.
|
|
22535
|
+
await embed.initialized;
|
|
22536
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22537
|
+
if (!channel) {
|
|
22538
|
+
throw new AdaEmbedError("Chat is not ready yet to send a message.");
|
|
22539
|
+
}
|
|
22540
|
+
const {
|
|
22541
|
+
beforeSend
|
|
22542
|
+
} = delegate;
|
|
22543
|
+
const finalText = beforeSend ? await applyBeforeSend(beforeSend, text) : text;
|
|
22544
|
+
const response = await channel.fetch("SEND_MESSAGE", "SEND_MESSAGE_RESPONSE", {
|
|
22545
|
+
text: finalText
|
|
22546
|
+
});
|
|
22547
|
+
if (!response) {
|
|
22548
|
+
throw new AdaEmbedError("sendMessage timed out — chat frame did not respond in time.");
|
|
22549
|
+
}
|
|
22550
|
+
|
|
22551
|
+
// MES-981 P0 #2: chat-side validation/rate-limit/dispatch failures
|
|
22552
|
+
// come back as `{ error: <code> }`. Surface the code to the caller
|
|
22553
|
+
// so they can branch on machine-readable reasons (TOO_LONG,
|
|
22554
|
+
// RATE_LIMITED, EMPTY_TEXT, INVALID_PAYLOAD, DISPATCH_FAILED).
|
|
22555
|
+
if ("error" in response) {
|
|
22556
|
+
throw new AdaEmbedError(`sendMessage rejected by chat: ${response.error}`);
|
|
22557
|
+
}
|
|
22558
|
+
return response;
|
|
22559
|
+
},
|
|
22560
|
+
setDelegate: newDelegate => {
|
|
22561
|
+
if (!embed) {
|
|
22562
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22563
|
+
}
|
|
22564
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22565
|
+
delegate = newDelegate ?? {};
|
|
22566
|
+
},
|
|
22149
22567
|
handleNotification: async () => {
|
|
22150
22568
|
if (!embed) {
|
|
22151
22569
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AdaEmbedAPI } from "@ada-support/embed-types";
|
|
2
1
|
import { AdaEmbedError } from "common/helpers/errors";
|
|
2
|
+
import type { ExtendedAdaEmbedAPI } from "common/types/extended-api";
|
|
3
3
|
export declare const EMBED_NOT_INITIALIZED_ERROR: AdaEmbedError;
|
|
4
4
|
/**
|
|
5
5
|
* Returns the public Embed methods to be bound to the window object.
|
|
6
6
|
*/
|
|
7
|
-
export declare function createEmbedInterface():
|
|
7
|
+
export declare function createEmbedInterface(): ExtendedAdaEmbedAPI;
|