@ada-support/embed2 1.13.6 → 1.14.4
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/ChatFrame/chatFrameEvents/chatterEvent/index.d.ts +6 -1
- 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/messaging-auth-state.d.ts +34 -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 +6 -0
- package/dist/npm-entry/index-npm.d.ts +1 -1
- package/dist/npm-entry/index.js +784 -92
- package/dist/npm-entry/interface.d.ts +2 -2
- package/package.json +2 -2
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.4-57d2690",
|
|
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}/${"57d2690"}/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;
|
|
@@ -16994,11 +17037,192 @@ const ZD_MESSAGING_CHATTER_CREATED_STORAGE_KEY = "ada-embed_zd-messaging-chatter
|
|
|
16994
17037
|
|
|
16995
17038
|
/** @deprecated - Use CHATTER_TOKEN_STORAGE_KEY */
|
|
16996
17039
|
const CHATTER_STORAGE_KEY = (/* unused pure expression or super */ null && (CHATTER_TOKEN_STORAGE_KEY));
|
|
17040
|
+
;// CONCATENATED MODULE: ./src/common/helpers/messaging-auth-state.ts
|
|
17041
|
+
|
|
17042
|
+
|
|
17043
|
+
// Single static key, shared verbatim with messaging + chat and disclosed by
|
|
17044
|
+
// @ada-support/web-storage. Per-bot scoping is implicit in the bot-subdomain
|
|
17045
|
+
// storage origin this runs on, so no apiOrigin/handle-scoped key is needed.
|
|
17046
|
+
const MESSAGING_AUTH_STATE_STORAGE_KEY = "messagingAuthState";
|
|
17047
|
+
function isRecord(value) {
|
|
17048
|
+
return typeof value === "object" && value !== null;
|
|
17049
|
+
}
|
|
17050
|
+
|
|
17051
|
+
// Typed @ada-support/web-storage wrapper for the chosen persistence provider, or
|
|
17052
|
+
// null when persistence is disabled / there is no window. The wrapper is what
|
|
17053
|
+
// puts `messagingAuthState` on the published web-storage disclosure list and
|
|
17054
|
+
// serializes the value, so callers pass/get a typed object rather than a string.
|
|
17055
|
+
function getMessagingAuthStorage(persistence) {
|
|
17056
|
+
if (persistence === "private" || typeof window === "undefined") {
|
|
17057
|
+
return null;
|
|
17058
|
+
}
|
|
17059
|
+
return persistence === "session" ? dist/* adaSessionStorage */.ad : dist/* adaLocalStorage */.BB;
|
|
17060
|
+
}
|
|
17061
|
+
function getApiOrigin(_ref) {
|
|
17062
|
+
let {
|
|
17063
|
+
handle,
|
|
17064
|
+
cluster,
|
|
17065
|
+
domain
|
|
17066
|
+
} = _ref;
|
|
17067
|
+
try {
|
|
17068
|
+
return new window.URL(getURL({
|
|
17069
|
+
name: "api",
|
|
17070
|
+
handle,
|
|
17071
|
+
cluster,
|
|
17072
|
+
domain
|
|
17073
|
+
}), window.location.origin).origin;
|
|
17074
|
+
} catch (error) {
|
|
17075
|
+
return null;
|
|
17076
|
+
}
|
|
17077
|
+
}
|
|
17078
|
+
function buildMessagingAuthStateStorageKey(_ref2) {
|
|
17079
|
+
let {
|
|
17080
|
+
handle,
|
|
17081
|
+
cluster,
|
|
17082
|
+
domain
|
|
17083
|
+
} = _ref2;
|
|
17084
|
+
// The key itself is static; the handle/origin now only gate whether there is a
|
|
17085
|
+
// resolvable session to read/write (preserving the previous no-op behavior
|
|
17086
|
+
// before a handle/origin is known) rather than scoping the key.
|
|
17087
|
+
if (!handle || !getApiOrigin({
|
|
17088
|
+
handle,
|
|
17089
|
+
cluster,
|
|
17090
|
+
domain
|
|
17091
|
+
})) {
|
|
17092
|
+
return null;
|
|
17093
|
+
}
|
|
17094
|
+
return MESSAGING_AUTH_STATE_STORAGE_KEY;
|
|
17095
|
+
}
|
|
17096
|
+
function parseMessagingAuthState(value) {
|
|
17097
|
+
let parsedValue = value;
|
|
17098
|
+
if (typeof value === "string") {
|
|
17099
|
+
try {
|
|
17100
|
+
parsedValue = JSON.parse(value);
|
|
17101
|
+
} catch (error) {
|
|
17102
|
+
return null;
|
|
17103
|
+
}
|
|
17104
|
+
}
|
|
17105
|
+
if (!isRecord(parsedValue)) {
|
|
17106
|
+
return null;
|
|
17107
|
+
}
|
|
17108
|
+
const {
|
|
17109
|
+
messagingToken,
|
|
17110
|
+
messagingTokenExpiresAt,
|
|
17111
|
+
sessionRefreshToken,
|
|
17112
|
+
refreshGeneration
|
|
17113
|
+
} = parsedValue;
|
|
17114
|
+
if (typeof messagingToken !== "string" || !messagingToken || typeof messagingTokenExpiresAt !== "number" || !Number.isFinite(messagingTokenExpiresAt) || messagingTokenExpiresAt <= 0 || typeof sessionRefreshToken !== "string" || !sessionRefreshToken || typeof refreshGeneration !== "number" || !Number.isFinite(refreshGeneration)) {
|
|
17115
|
+
return null;
|
|
17116
|
+
}
|
|
17117
|
+
return {
|
|
17118
|
+
messagingToken,
|
|
17119
|
+
messagingTokenExpiresAt,
|
|
17120
|
+
sessionRefreshToken,
|
|
17121
|
+
refreshGeneration
|
|
17122
|
+
};
|
|
17123
|
+
}
|
|
17124
|
+
|
|
17125
|
+
// Storage-blocked browsers can throw on the storage methods, so each access is
|
|
17126
|
+
// wrapped to fall back gracefully rather than throw into callers.
|
|
17127
|
+
function safeReadMessagingAuthState(persistence) {
|
|
17128
|
+
try {
|
|
17129
|
+
var _getMessagingAuthStor;
|
|
17130
|
+
return parseMessagingAuthState(((_getMessagingAuthStor = getMessagingAuthStorage(persistence)) === null || _getMessagingAuthStor === void 0 ? void 0 : _getMessagingAuthStor.getItem(MESSAGING_AUTH_STATE_STORAGE_KEY)) ?? null);
|
|
17131
|
+
} catch (error) {
|
|
17132
|
+
return null;
|
|
17133
|
+
}
|
|
17134
|
+
}
|
|
17135
|
+
function readMessagingAuthStateFromStorage(_ref3) {
|
|
17136
|
+
let {
|
|
17137
|
+
handle,
|
|
17138
|
+
cluster,
|
|
17139
|
+
domain
|
|
17140
|
+
} = _ref3;
|
|
17141
|
+
if (!buildMessagingAuthStateStorageKey({
|
|
17142
|
+
handle,
|
|
17143
|
+
cluster,
|
|
17144
|
+
domain
|
|
17145
|
+
})) {
|
|
17146
|
+
return undefined;
|
|
17147
|
+
}
|
|
17148
|
+
const persistedAuthStates = ["normal", "session"].map(persistence => safeReadMessagingAuthState(persistence)).filter(authState => authState !== null);
|
|
17149
|
+
return persistedAuthStates.reduce((highestState, authState) => !highestState || authState.refreshGeneration > highestState.refreshGeneration ? authState : highestState, undefined);
|
|
17150
|
+
}
|
|
17151
|
+
function writeMessagingAuthStateToStorage(_ref4) {
|
|
17152
|
+
let {
|
|
17153
|
+
handle,
|
|
17154
|
+
cluster,
|
|
17155
|
+
domain,
|
|
17156
|
+
persistence,
|
|
17157
|
+
state
|
|
17158
|
+
} = _ref4;
|
|
17159
|
+
const storageKey = buildMessagingAuthStateStorageKey({
|
|
17160
|
+
handle,
|
|
17161
|
+
cluster,
|
|
17162
|
+
domain
|
|
17163
|
+
});
|
|
17164
|
+
const storage = getMessagingAuthStorage(persistence);
|
|
17165
|
+
if (!storageKey || !storage || !state) {
|
|
17166
|
+
return false;
|
|
17167
|
+
}
|
|
17168
|
+
try {
|
|
17169
|
+
const existing = readMessagingAuthStateFromStorage({
|
|
17170
|
+
handle,
|
|
17171
|
+
cluster,
|
|
17172
|
+
domain
|
|
17173
|
+
});
|
|
17174
|
+
if (existing && existing.refreshGeneration >= state.refreshGeneration) {
|
|
17175
|
+
return false;
|
|
17176
|
+
}
|
|
17177
|
+
storage.setItem(storageKey, state);
|
|
17178
|
+
return true;
|
|
17179
|
+
} catch (error) {
|
|
17180
|
+
return false;
|
|
17181
|
+
}
|
|
17182
|
+
}
|
|
17183
|
+
function clearAllMessagingAuthStatesFromStorage() {
|
|
17184
|
+
["normal", "session"].forEach(persistence => {
|
|
17185
|
+
try {
|
|
17186
|
+
var _getMessagingAuthStor2;
|
|
17187
|
+
(_getMessagingAuthStor2 = getMessagingAuthStorage(persistence)) === null || _getMessagingAuthStor2 === void 0 ? void 0 : _getMessagingAuthStor2.removeItem(MESSAGING_AUTH_STATE_STORAGE_KEY);
|
|
17188
|
+
} catch (error) {
|
|
17189
|
+
// Storage blocked; nothing to clear.
|
|
17190
|
+
}
|
|
17191
|
+
});
|
|
17192
|
+
}
|
|
17193
|
+
|
|
17194
|
+
// Removes the messaging auth state (across both persistence providers). Used when
|
|
17195
|
+
// a bot rotates to a new chatter. With the bot-subdomain storage origin there is a
|
|
17196
|
+
// single auth state per origin, so this and `clearAllMessagingAuthStatesFromStorage`
|
|
17197
|
+
// now clear the same key.
|
|
17198
|
+
function clearMessagingAuthStateFromStorage(_ref5) {
|
|
17199
|
+
let {
|
|
17200
|
+
handle,
|
|
17201
|
+
cluster,
|
|
17202
|
+
domain
|
|
17203
|
+
} = _ref5;
|
|
17204
|
+
if (!buildMessagingAuthStateStorageKey({
|
|
17205
|
+
handle,
|
|
17206
|
+
cluster,
|
|
17207
|
+
domain
|
|
17208
|
+
})) {
|
|
17209
|
+
return;
|
|
17210
|
+
}
|
|
17211
|
+
["normal", "session"].forEach(persistence => {
|
|
17212
|
+
try {
|
|
17213
|
+
var _getMessagingAuthStor3;
|
|
17214
|
+
(_getMessagingAuthStor3 = getMessagingAuthStorage(persistence)) === null || _getMessagingAuthStor3 === void 0 ? void 0 : _getMessagingAuthStor3.removeItem(MESSAGING_AUTH_STATE_STORAGE_KEY);
|
|
17215
|
+
} catch (error) {
|
|
17216
|
+
// Storage blocked; nothing to clear.
|
|
17217
|
+
}
|
|
17218
|
+
});
|
|
17219
|
+
}
|
|
16997
17220
|
;// CONCATENATED MODULE: ./src/client/store/state.ts
|
|
16998
17221
|
|
|
16999
17222
|
|
|
17000
17223
|
|
|
17001
17224
|
|
|
17225
|
+
|
|
17002
17226
|
function getValueFromStorage(key) {
|
|
17003
17227
|
return dist/* adaLocalStorage */.BB.getItem(key) || dist/* adaSessionStorage */.ad.getItem(key);
|
|
17004
17228
|
}
|
|
@@ -17011,6 +17235,8 @@ const getInitialState = adaSettings => ({
|
|
|
17011
17235
|
language: undefined,
|
|
17012
17236
|
greeting: undefined,
|
|
17013
17237
|
crossWindowPersistence: true,
|
|
17238
|
+
headless: false,
|
|
17239
|
+
enableProgrammaticControl: false,
|
|
17014
17240
|
hideMask: true,
|
|
17015
17241
|
metaFields: {},
|
|
17016
17242
|
sensitiveMetaFields: {},
|
|
@@ -17031,6 +17257,11 @@ const getInitialState = adaSettings => ({
|
|
|
17031
17257
|
chatterToken: getValueFromStorage(CHATTER_TOKEN_STORAGE_KEY) || undefined,
|
|
17032
17258
|
chatterCreated: getValueFromStorage(CHATTER_CREATED_STORAGE_KEY) || undefined,
|
|
17033
17259
|
sessionToken: getValueFromStorage(SESSION_AUTH_TOKEN_STORAGE_KEY) || undefined,
|
|
17260
|
+
messagingAuthState: readMessagingAuthStateFromStorage({
|
|
17261
|
+
handle: adaSettings.handle,
|
|
17262
|
+
cluster: adaSettings.cluster,
|
|
17263
|
+
domain: adaSettings.domain
|
|
17264
|
+
}),
|
|
17034
17265
|
zdSessionId: getValueFromStorage(ZD_SESSION_STORAGE_KEY) || undefined,
|
|
17035
17266
|
zdPreviousTags: getValueFromStorage(ZD_PREVIOUS_TAGS_STORAGE_KEY) || undefined,
|
|
17036
17267
|
zdMessagingExternalUserId: getValueFromStorage(ZD_MESSAGING_EXTERNAL_USER_ID_STORAGE_KEY) || null,
|
|
@@ -17052,6 +17283,58 @@ const getInitialState = adaSettings => ({
|
|
|
17052
17283
|
deviceToken: null,
|
|
17053
17284
|
showFallbackOnTimeout: true
|
|
17054
17285
|
});
|
|
17286
|
+
// EXTERNAL MODULE: ./node_modules/lodash.memoize/index.js
|
|
17287
|
+
var lodash_memoize = __webpack_require__(7654);
|
|
17288
|
+
var lodash_memoize_default = /*#__PURE__*/__webpack_require__.n(lodash_memoize);
|
|
17289
|
+
;// CONCATENATED MODULE: ./src/services/logger/index.ts
|
|
17290
|
+
|
|
17291
|
+
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; }
|
|
17292
|
+
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; }
|
|
17293
|
+
|
|
17294
|
+
|
|
17295
|
+
const DEFAULT_LOG_SAMPLE_RATE = 0.01;
|
|
17296
|
+
const DD_BASE_URL = "https://browser-http-intake.logs.datadoghq.com/v1/input/";
|
|
17297
|
+
const DD_TOKEN = "pubfe23baedd2ea322bebb5ed2020fa2fa1";
|
|
17298
|
+
let globalLogContext = {};
|
|
17299
|
+
function setGlobalLogContext(context) {
|
|
17300
|
+
globalLogContext = logger_objectSpread({}, context);
|
|
17301
|
+
}
|
|
17302
|
+
function clearGlobalLogContext() {
|
|
17303
|
+
globalLogContext = {};
|
|
17304
|
+
}
|
|
17305
|
+
|
|
17306
|
+
// We need memoization to ensure consistency of logs
|
|
17307
|
+
const shouldLog = lodash_memoize_default()(sampleRate => {
|
|
17308
|
+
if (!DD_TOKEN || sampleRate === 0) {
|
|
17309
|
+
return false;
|
|
17310
|
+
}
|
|
17311
|
+
return Math.random() < (sampleRate || DEFAULT_LOG_SAMPLE_RATE);
|
|
17312
|
+
});
|
|
17313
|
+
|
|
17314
|
+
/**
|
|
17315
|
+
* Sends log to Datadog
|
|
17316
|
+
*/
|
|
17317
|
+
async function log(message, extra, options) {
|
|
17318
|
+
if (!shouldLog(options === null || options === void 0 ? void 0 : options.sampleRate)) {
|
|
17319
|
+
return;
|
|
17320
|
+
}
|
|
17321
|
+
await httpRequest({
|
|
17322
|
+
url: `${DD_BASE_URL}${DD_TOKEN}?ddsource=browser&ddtags=version:1.5.0,env:${"production"}`,
|
|
17323
|
+
method: "POST",
|
|
17324
|
+
body: JSON.stringify(logger_objectSpread(logger_objectSpread(logger_objectSpread({
|
|
17325
|
+
message
|
|
17326
|
+
}, extra), globalLogContext), {}, {
|
|
17327
|
+
level: (options === null || options === void 0 ? void 0 : options.level) || "info",
|
|
17328
|
+
sampleRate: (options === null || options === void 0 ? void 0 : options.sampleRate) || DEFAULT_LOG_SAMPLE_RATE,
|
|
17329
|
+
service: "embed",
|
|
17330
|
+
env: "production",
|
|
17331
|
+
embedVersion: 2,
|
|
17332
|
+
version: "1.14.4",
|
|
17333
|
+
isNpm: true,
|
|
17334
|
+
commitHash: "57d2690"
|
|
17335
|
+
}))
|
|
17336
|
+
});
|
|
17337
|
+
}
|
|
17055
17338
|
;// CONCATENATED MODULE: ./src/common/helpers/get-intro-for-url.ts
|
|
17056
17339
|
function getProcessedPath(path) {
|
|
17057
17340
|
const regex = /^http(s)?:\/\/(www.)?/;
|
|
@@ -17651,58 +17934,6 @@ function getButtonText(client) {
|
|
|
17651
17934
|
}
|
|
17652
17935
|
return buttonTextMap[languageKey];
|
|
17653
17936
|
}
|
|
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.6",
|
|
17701
|
-
isNpm: true,
|
|
17702
|
-
commitHash: "406ab08"
|
|
17703
|
-
}))
|
|
17704
|
-
});
|
|
17705
|
-
}
|
|
17706
17937
|
;// CONCATENATED MODULE: ./src/client/helpers/alternative-bot-rollout/index.ts
|
|
17707
17938
|
|
|
17708
17939
|
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 +19494,12 @@ function deriveMessagingMobileShell(mobilePackage) {
|
|
|
19263
19494
|
function deriveLegacyMobileShell(surface, hostPlatform) {
|
|
19264
19495
|
return surface === "mobile" && hostPlatform !== "web" ? "legacy-sdk" : undefined;
|
|
19265
19496
|
}
|
|
19497
|
+
|
|
19498
|
+
// MES-981 P1 #10: extracted to keep resolveHostTelemetryFromStartOptions
|
|
19499
|
+
// under the sonarjs cognitive-complexity threshold.
|
|
19500
|
+
function deriveMode(adaSettings) {
|
|
19501
|
+
return adaSettings.headless ? "headless" : undefined;
|
|
19502
|
+
}
|
|
19266
19503
|
function normalizeHostTelemetry(value) {
|
|
19267
19504
|
const record = asRecord(value);
|
|
19268
19505
|
if (!record) {
|
|
@@ -19345,11 +19582,14 @@ function resolveHostTelemetryFromStartOptions(adaSettings) {
|
|
|
19345
19582
|
const mobilePackage = explicit === null || explicit === void 0 ? void 0 : explicit.mobilePackage;
|
|
19346
19583
|
const mobileVersion = explicit === null || explicit === void 0 ? void 0 : explicit.mobileVersion;
|
|
19347
19584
|
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
|
-
|
|
19585
|
+
const mode = deriveMode(adaSettings);
|
|
19586
|
+
return host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread({
|
|
19349
19587
|
surface,
|
|
19350
19588
|
hostPlatform,
|
|
19351
19589
|
webSdkOrigin
|
|
19352
|
-
},
|
|
19590
|
+
}, mode ? {
|
|
19591
|
+
mode
|
|
19592
|
+
} : {}), mobileShell ? {
|
|
19353
19593
|
mobileShell
|
|
19354
19594
|
} : {}), mobilePackage ? {
|
|
19355
19595
|
mobilePackage
|
|
@@ -19367,7 +19607,11 @@ function toMonitoringContext(hostTelemetry) {
|
|
|
19367
19607
|
return host_telemetry_objectSpread(host_telemetry_objectSpread(host_telemetry_objectSpread({
|
|
19368
19608
|
surface: hostTelemetry.surface,
|
|
19369
19609
|
host_platform: hostTelemetry.hostPlatform,
|
|
19370
|
-
web_sdk_origin: hostTelemetry.webSdkOrigin
|
|
19610
|
+
web_sdk_origin: hostTelemetry.webSdkOrigin,
|
|
19611
|
+
// MES-981 P1 #10: every log/RUM line carries `mode`; default to
|
|
19612
|
+
// "visible" when not set on the context so dashboards can filter
|
|
19613
|
+
// by mode without a separate query.
|
|
19614
|
+
mode: hostTelemetry.mode ?? "visible"
|
|
19371
19615
|
}, hostTelemetry.mobileShell ? {
|
|
19372
19616
|
mobile_shell: hostTelemetry.mobileShell
|
|
19373
19617
|
} : {}), hostTelemetry.mobilePackage ? {
|
|
@@ -19378,23 +19622,101 @@ function toMonitoringContext(hostTelemetry) {
|
|
|
19378
19622
|
}
|
|
19379
19623
|
;// CONCATENATED MODULE: ./src/common/helpers/is-mobile.ts
|
|
19380
19624
|
const isMobile = /(iPhone)|(iPod)|(android)|(webOS)/i.exec(navigator.userAgent) !== null;
|
|
19625
|
+
;// CONCATENATED MODULE: ./src/common/helpers/programmatic-control.ts
|
|
19626
|
+
|
|
19627
|
+
|
|
19628
|
+
// MES-981: privileged transcript-bearing surface is opt-in. Host pages
|
|
19629
|
+
// must explicitly accept the exposure risk via
|
|
19630
|
+
// `start({ enableProgrammaticControl: true })`, because every third-party
|
|
19631
|
+
// script in the host page (analytics, GTM, ad pixels, session replay,
|
|
19632
|
+
// supply-chain XSS) inherits the host's trust.
|
|
19633
|
+
const PROGRAMMATIC_CONTROL_DISABLED_ERROR = new AdaEmbedError("ProgrammaticControlNotEnabled: this API requires `start({ enableProgrammaticControl: true })`.");
|
|
19634
|
+
function isProgrammaticControlEnabled(adaSettings) {
|
|
19635
|
+
return Boolean(adaSettings === null || adaSettings === void 0 ? void 0 : adaSettings.enableProgrammaticControl);
|
|
19636
|
+
}
|
|
19637
|
+
function requireProgrammaticControl(adaSettings) {
|
|
19638
|
+
if (!isProgrammaticControlEnabled(adaSettings)) {
|
|
19639
|
+
throw PROGRAMMATIC_CONTROL_DISABLED_ERROR;
|
|
19640
|
+
}
|
|
19641
|
+
}
|
|
19642
|
+
|
|
19643
|
+
// ada:message:sent and ada:message:received carry user/agent transcript
|
|
19644
|
+
// bodies. Other ada:* events (ready, connection, conversation, typing)
|
|
19645
|
+
// only carry id/state/timing data and are not subject to this gate.
|
|
19646
|
+
const TRANSCRIPT_EVENT_KEYS = new Set(["ada:message:sent", "ada:message:received"]);
|
|
19647
|
+
function shouldDeliverTranscriptEvent(eventKey, adaSettings) {
|
|
19648
|
+
if (!TRANSCRIPT_EVENT_KEYS.has(eventKey)) return true;
|
|
19649
|
+
return isProgrammaticControlEnabled(adaSettings);
|
|
19650
|
+
}
|
|
19381
19651
|
;// CONCATENATED MODULE: ./src/client/components/ChatFrame/chatFrameEvents/chatterEvent/index.ts
|
|
19382
19652
|
|
|
19383
19653
|
|
|
19654
|
+
|
|
19384
19655
|
function storeChatterEventDataInBrowser(client, payload) {
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19656
|
+
let {
|
|
19657
|
+
cluster,
|
|
19658
|
+
domain,
|
|
19659
|
+
privateMode
|
|
19660
|
+
} = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
19388
19661
|
const {
|
|
19389
19662
|
chatter,
|
|
19390
19663
|
created,
|
|
19391
|
-
sessionToken
|
|
19664
|
+
sessionToken,
|
|
19665
|
+
messagingAuthState
|
|
19392
19666
|
} = payload;
|
|
19667
|
+
if (privateMode) {
|
|
19668
|
+
return;
|
|
19669
|
+
}
|
|
19670
|
+
const {
|
|
19671
|
+
persistence
|
|
19672
|
+
} = client;
|
|
19673
|
+
|
|
19674
|
+
// A new chatter resets refreshGeneration back to 1, so the generation guard in
|
|
19675
|
+
// writeMessagingAuthStateToStorage would otherwise refuse to overwrite a previous
|
|
19676
|
+
// chatter's higher-generation (now-dead) auth state — leaving the host-page copy
|
|
19677
|
+
// stuck on a refresh token the backend has rotated away. Whenever the persisted
|
|
19678
|
+
// chatter token does not match the incoming one — including when it is absent or in
|
|
19679
|
+
// the other persistence provider, leaving the auth state orphaned — drop the stale
|
|
19680
|
+
// auth state first so the new chatter's credentials persist.
|
|
19681
|
+
const previousChatter = retrieveStorage(CHATTER_TOKEN_STORAGE_KEY, client, privateMode);
|
|
19682
|
+
if (previousChatter !== chatter) {
|
|
19683
|
+
clearMessagingAuthStateFromStorage({
|
|
19684
|
+
handle: client.handle,
|
|
19685
|
+
cluster,
|
|
19686
|
+
domain
|
|
19687
|
+
});
|
|
19688
|
+
}
|
|
19393
19689
|
setBrowserStorageItem(CHATTER_TOKEN_STORAGE_KEY, chatter, persistence);
|
|
19394
19690
|
setBrowserStorageItem(CHATTER_CREATED_STORAGE_KEY, created, persistence);
|
|
19395
19691
|
if (sessionToken) {
|
|
19396
19692
|
setBrowserStorageItem(SESSION_AUTH_TOKEN_STORAGE_KEY, sessionToken, persistence);
|
|
19397
19693
|
}
|
|
19694
|
+
|
|
19695
|
+
// embed-2 only PERSISTS / mirrors the chat auth state here; it is the relay that
|
|
19696
|
+
// lets the chat iframe restore the JWT (e.g. across reloads). embed-2 deliberately
|
|
19697
|
+
// never attaches `Authorization` to its own XHR requests — adding headers to
|
|
19698
|
+
// embed-2's cross-origin XHR trips CORS preflight (see common/helpers/http.ts) — so
|
|
19699
|
+
// the chat iframe, not embed-2, is what sends `Bearer <messagingToken>`.
|
|
19700
|
+
const parsedAuthState = parseMessagingAuthState(messagingAuthState);
|
|
19701
|
+
if (parsedAuthState) {
|
|
19702
|
+
writeMessagingAuthStateToStorage({
|
|
19703
|
+
handle: client.handle,
|
|
19704
|
+
cluster,
|
|
19705
|
+
domain,
|
|
19706
|
+
persistence,
|
|
19707
|
+
state: parsedAuthState
|
|
19708
|
+
});
|
|
19709
|
+
} else {
|
|
19710
|
+
// chat published no usable auth state for this chatter (e.g. it cleared a dead
|
|
19711
|
+
// refresh token on unrecoverable invalid_refresh_token). Drop the host-side copy so
|
|
19712
|
+
// a stale token can't be resurrected on reload — a null write would otherwise no-op
|
|
19713
|
+
// and leave it in place.
|
|
19714
|
+
clearMessagingAuthStateFromStorage({
|
|
19715
|
+
handle: client.handle,
|
|
19716
|
+
cluster,
|
|
19717
|
+
domain
|
|
19718
|
+
});
|
|
19719
|
+
}
|
|
19398
19720
|
}
|
|
19399
19721
|
;// CONCATENATED MODULE: ./src/client/components/ChatFrame/chatFrameEvents/index.ts
|
|
19400
19722
|
|
|
@@ -19548,6 +19870,31 @@ function getFallbackDataURI() {
|
|
|
19548
19870
|
|
|
19549
19871
|
|
|
19550
19872
|
|
|
19873
|
+
|
|
19874
|
+
// MES-981: route an inbound PUBLISH_EVENT from the chat iframe to the host's
|
|
19875
|
+
// event-subscription registry. Pulled out of handleChatEvent so its switch
|
|
19876
|
+
// stays under the sonarjs cognitive-complexity threshold.
|
|
19877
|
+
//
|
|
19878
|
+
// Two host-facing transforms happen here:
|
|
19879
|
+
// - shouldDeliverTranscriptEvent drops ada:message:* unless the host
|
|
19880
|
+
// opted in via enableProgrammaticControl (P0 #4).
|
|
19881
|
+
// - ada:ready is re-emitted with `{ mode: "headless" | "visible" }` so
|
|
19882
|
+
// subscribers can branch without inspecting adaSettings (P1 #10).
|
|
19883
|
+
function forwardPublishEvent(publishPayload, adaSettings) {
|
|
19884
|
+
const {
|
|
19885
|
+
eventKey,
|
|
19886
|
+
data
|
|
19887
|
+
} = publishPayload;
|
|
19888
|
+
if (!shouldDeliverTranscriptEvent(eventKey, adaSettings)) return;
|
|
19889
|
+
if (eventKey === "ada:ready") {
|
|
19890
|
+
const mode = adaSettings.headless ? "headless" : "visible";
|
|
19891
|
+
publishEvent(eventKey, {
|
|
19892
|
+
mode
|
|
19893
|
+
});
|
|
19894
|
+
return;
|
|
19895
|
+
}
|
|
19896
|
+
publishEvent(eventKey, data);
|
|
19897
|
+
}
|
|
19551
19898
|
class ChatFrame extends preact_module_d {
|
|
19552
19899
|
constructor() {
|
|
19553
19900
|
super(...arguments);
|
|
@@ -19597,7 +19944,7 @@ class ChatFrame extends preact_module_d {
|
|
|
19597
19944
|
log("Chat frame mount", {
|
|
19598
19945
|
handle,
|
|
19599
19946
|
chatUrl: this.url,
|
|
19600
|
-
embedVersion: "
|
|
19947
|
+
embedVersion: "57d2690".slice(0, 7),
|
|
19601
19948
|
embedSettings: adaSettings
|
|
19602
19949
|
});
|
|
19603
19950
|
|
|
@@ -19685,7 +20032,7 @@ class ChatFrame extends preact_module_d {
|
|
|
19685
20032
|
const hostPageUrlParams = new URL(window.location.href).searchParams;
|
|
19686
20033
|
const smsToken = hostPageUrlParams.get("adaSMSToken");
|
|
19687
20034
|
const queryParams = {
|
|
19688
|
-
embedVersion: "
|
|
20035
|
+
embedVersion: "57d2690".slice(0, 7),
|
|
19689
20036
|
greeting,
|
|
19690
20037
|
language,
|
|
19691
20038
|
skipGreeting,
|
|
@@ -20004,11 +20351,7 @@ class ChatFrame extends preact_module_d {
|
|
|
20004
20351
|
}
|
|
20005
20352
|
case PUBLISH_EVENT:
|
|
20006
20353
|
{
|
|
20007
|
-
|
|
20008
|
-
eventKey,
|
|
20009
|
-
data
|
|
20010
|
-
} = payload;
|
|
20011
|
-
publishEvent(eventKey, data);
|
|
20354
|
+
forwardPublishEvent(payload, adaSettings);
|
|
20012
20355
|
break;
|
|
20013
20356
|
}
|
|
20014
20357
|
case ANALYTICS_EVENT:
|
|
@@ -20027,12 +20370,16 @@ class ChatFrame extends preact_module_d {
|
|
|
20027
20370
|
case CHATTER_EVENT:
|
|
20028
20371
|
{
|
|
20029
20372
|
const {
|
|
20030
|
-
client
|
|
20373
|
+
client,
|
|
20374
|
+
cluster,
|
|
20375
|
+
domain,
|
|
20376
|
+
privateMode
|
|
20031
20377
|
} = this.props;
|
|
20032
20378
|
const {
|
|
20033
20379
|
chatter,
|
|
20034
20380
|
created,
|
|
20035
|
-
sessionToken
|
|
20381
|
+
sessionToken,
|
|
20382
|
+
messagingAuthState
|
|
20036
20383
|
} = payload;
|
|
20037
20384
|
const {
|
|
20038
20385
|
chatterTokenCallback
|
|
@@ -20040,14 +20387,19 @@ class ChatFrame extends preact_module_d {
|
|
|
20040
20387
|
if (!client) {
|
|
20041
20388
|
throw new AdaEmbedError("`client` is undefined");
|
|
20042
20389
|
}
|
|
20043
|
-
storeChatterEventDataInBrowser(client, payload
|
|
20390
|
+
storeChatterEventDataInBrowser(client, payload, {
|
|
20391
|
+
cluster,
|
|
20392
|
+
domain,
|
|
20393
|
+
privateMode
|
|
20394
|
+
});
|
|
20044
20395
|
if (chatterTokenCallback) {
|
|
20045
20396
|
chatterTokenCallback(chatter);
|
|
20046
20397
|
}
|
|
20047
20398
|
await setGlobalState({
|
|
20048
20399
|
chatterToken: chatter,
|
|
20049
20400
|
chatterCreated: created,
|
|
20050
|
-
sessionToken
|
|
20401
|
+
sessionToken,
|
|
20402
|
+
messagingAuthState
|
|
20051
20403
|
});
|
|
20052
20404
|
break;
|
|
20053
20405
|
}
|
|
@@ -20658,10 +21010,37 @@ class XStorageFrame extends preact_module_d {
|
|
|
20658
21010
|
}
|
|
20659
21011
|
}
|
|
20660
21012
|
/* harmony default export */ var components_XStorageFrame = (connect()(XStorageFrame));
|
|
21013
|
+
;// CONCATENATED MODULE: ./src/client/components/Container/host-facing-meta-fields.ts
|
|
21014
|
+
|
|
21015
|
+
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; }
|
|
21016
|
+
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; }
|
|
21017
|
+
// MES-981 metaFields helpers. Extracted from Container/index.tsx so the
|
|
21018
|
+
// transforms don't push that already-large module over its max-lines budget.
|
|
21019
|
+
|
|
21020
|
+
/** Strips the internal `proactive_conversation` tracker for getMetaFields(). */
|
|
21021
|
+
function toHostFacingMetaFields(metaFields) {
|
|
21022
|
+
const hostFacing = host_facing_meta_fields_objectSpread({}, metaFields);
|
|
21023
|
+
delete hostFacing.proactive_conversation;
|
|
21024
|
+
return hostFacing;
|
|
21025
|
+
}
|
|
21026
|
+
|
|
21027
|
+
/** Merges a proactive_conversation key onto existing metaFields. */
|
|
21028
|
+
function withProactiveKey(metaFields, key) {
|
|
21029
|
+
return host_facing_meta_fields_objectSpread(host_facing_meta_fields_objectSpread({}, metaFields), {}, {
|
|
21030
|
+
proactive_conversation: key
|
|
21031
|
+
});
|
|
21032
|
+
}
|
|
20661
21033
|
;// CONCATENATED MODULE: ./src/client/components/Container/index.tsx
|
|
20662
21034
|
|
|
20663
21035
|
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
21036
|
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; }
|
|
21037
|
+
/* eslint-disable max-lines -- MES-981: file was already at the 1000-line
|
|
21038
|
+
max-lines cap on main; the additive programmatic-control work pushes it
|
|
21039
|
+
just over. A targeted refactor of this Container is being tracked
|
|
21040
|
+
separately and is out of scope for this PR. */
|
|
21041
|
+
|
|
21042
|
+
|
|
21043
|
+
|
|
20665
21044
|
|
|
20666
21045
|
|
|
20667
21046
|
|
|
@@ -20740,11 +21119,11 @@ class Container extends preact_module_d {
|
|
|
20740
21119
|
adaSettings
|
|
20741
21120
|
});
|
|
20742
21121
|
|
|
20743
|
-
//
|
|
21122
|
+
// MES-981: seed state.metaFields with host-supplied values + reset tracker.
|
|
20744
21123
|
setGlobalState({
|
|
20745
|
-
metaFields: {
|
|
21124
|
+
metaFields: Container_objectSpread(Container_objectSpread({}, adaSettings.metaFields ?? {}), {}, {
|
|
20746
21125
|
proactive_conversation: null
|
|
20747
|
-
}
|
|
21126
|
+
})
|
|
20748
21127
|
});
|
|
20749
21128
|
|
|
20750
21129
|
// We want to make sure this happens before any publishEvent calls
|
|
@@ -20853,7 +21232,9 @@ class Container extends preact_module_d {
|
|
|
20853
21232
|
// campaigns, we don't need this for engage (response_id) campaigns
|
|
20854
21233
|
campaignToTrigger.response_id || appConnectionState === ConnectionState.Done) && !isDrawerOpen && !chatterInLiveChat) {
|
|
20855
21234
|
triggerCampaignImpl({
|
|
20856
|
-
adaSettings,
|
|
21235
|
+
adaSettings: Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
|
|
21236
|
+
handle: (client === null || client === void 0 ? void 0 : client.handle) || adaSettings.handle
|
|
21237
|
+
}),
|
|
20857
21238
|
chatterToken,
|
|
20858
21239
|
campaign: campaignToTrigger,
|
|
20859
21240
|
ignoreStatus: Boolean(campaignTriggerOptions.ignoreStatus),
|
|
@@ -20901,12 +21282,11 @@ class Container extends preact_module_d {
|
|
|
20901
21282
|
if (isChatWebsocketConnected && isDrawerOpen && recentProactiveConversationConfig) {
|
|
20902
21283
|
const chatChannel = messageService.getChannel(CHAT_IFRAME);
|
|
20903
21284
|
if (chatChannel) {
|
|
20904
|
-
|
|
20905
|
-
|
|
21285
|
+
const {
|
|
21286
|
+
metaFields
|
|
21287
|
+
} = this.props;
|
|
20906
21288
|
setGlobalState({
|
|
20907
|
-
metaFields:
|
|
20908
|
-
proactive_conversation: recentProactiveConversationConfig.key
|
|
20909
|
-
}
|
|
21289
|
+
metaFields: withProactiveKey(metaFields, recentProactiveConversationConfig.key)
|
|
20910
21290
|
});
|
|
20911
21291
|
chatChannel.postMessage(INJECT_PROACTIVE_CONVERSATION, {
|
|
20912
21292
|
key: recentProactiveConversationConfig.key,
|
|
@@ -20961,6 +21341,13 @@ class Container extends preact_module_d {
|
|
|
20961
21341
|
if (hideChatOverride) {
|
|
20962
21342
|
return false;
|
|
20963
21343
|
}
|
|
21344
|
+
|
|
21345
|
+
// MES-981: in headless mode the host page never opens the drawer, so
|
|
21346
|
+
// treat headless as an implicit preload to ensure the chat iframe loads
|
|
21347
|
+
// and registers its frame-channel handler.
|
|
21348
|
+
if (adaSettings.headless) {
|
|
21349
|
+
return true;
|
|
21350
|
+
}
|
|
20964
21351
|
if (preload) {
|
|
20965
21352
|
return true;
|
|
20966
21353
|
}
|
|
@@ -21101,7 +21488,9 @@ class Container extends preact_module_d {
|
|
|
21101
21488
|
if (!client) {
|
|
21102
21489
|
throw new AdaEmbedError("`client` is not defined");
|
|
21103
21490
|
}
|
|
21104
|
-
const campaignToTrigger = getCampaignToTrigger(
|
|
21491
|
+
const campaignToTrigger = getCampaignToTrigger(Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
|
|
21492
|
+
handle: client.handle
|
|
21493
|
+
}), client.marketing_campaigns, params, !client.features.afm_proactive_messaging);
|
|
21105
21494
|
if (campaignToTrigger) {
|
|
21106
21495
|
if (useDelay) {
|
|
21107
21496
|
setTimeout(() => {
|
|
@@ -21238,9 +21627,13 @@ class Container extends preact_module_d {
|
|
|
21238
21627
|
drawerHasBeenOpened,
|
|
21239
21628
|
chatterToken
|
|
21240
21629
|
} = this.props;
|
|
21630
|
+
// MES-981 P1 #9: in headless mode the UI is intentionally hidden,
|
|
21631
|
+
// so `isChatOpen` always returns false regardless of any drawer
|
|
21632
|
+
// state. Matches the contract that isOpen() returns in headless.
|
|
21633
|
+
const isHeadless = Boolean(adaSettings.headless);
|
|
21241
21634
|
const contentToReturn = {
|
|
21242
|
-
isDrawerOpen,
|
|
21243
|
-
isChatOpen: isDrawerOpen || Boolean(parentElement),
|
|
21635
|
+
isDrawerOpen: isHeadless ? false : isDrawerOpen,
|
|
21636
|
+
isChatOpen: isHeadless ? false : isDrawerOpen || Boolean(parentElement),
|
|
21244
21637
|
hasActiveChatter: Boolean(chatterToken),
|
|
21245
21638
|
hasClosedChat: drawerHasBeenOpened && !isDrawerOpen
|
|
21246
21639
|
};
|
|
@@ -21261,6 +21654,14 @@ class Container extends preact_module_d {
|
|
|
21261
21654
|
localChannel.postMessage(SET_META_FIELDS_RESPONSE, null, id);
|
|
21262
21655
|
break;
|
|
21263
21656
|
}
|
|
21657
|
+
case GET_META_FIELDS:
|
|
21658
|
+
{
|
|
21659
|
+
const {
|
|
21660
|
+
metaFields
|
|
21661
|
+
} = this.props;
|
|
21662
|
+
localChannel.postMessage(GET_META_FIELDS_RESPONSE, toHostFacingMetaFields(metaFields), id);
|
|
21663
|
+
break;
|
|
21664
|
+
}
|
|
21264
21665
|
case "SET_SENSITIVE_META_FIELDS":
|
|
21265
21666
|
{
|
|
21266
21667
|
const {
|
|
@@ -21325,11 +21726,20 @@ class Container extends preact_module_d {
|
|
|
21325
21726
|
dist/* adaSessionStorage */.ad.removeItem(CHATTER_TOKEN_STORAGE_KEY);
|
|
21326
21727
|
dist/* adaLocalStorage */.BB.removeItem(CHATTER_CREATED_STORAGE_KEY);
|
|
21327
21728
|
dist/* adaSessionStorage */.ad.removeItem(CHATTER_CREATED_STORAGE_KEY);
|
|
21729
|
+
// Scope the clear to this bot so a sibling Ada bot on the same origin keeps its
|
|
21730
|
+
// own messaging auth state. adaSettings.{handle,cluster,domain} matches the key
|
|
21731
|
+
// storeChatterEventDataInBrowser wrote under.
|
|
21732
|
+
clearMessagingAuthStateFromStorage({
|
|
21733
|
+
handle: adaSettings.handle,
|
|
21734
|
+
cluster: adaSettings.cluster,
|
|
21735
|
+
domain: adaSettings.domain
|
|
21736
|
+
});
|
|
21328
21737
|
|
|
21329
21738
|
// And from state
|
|
21330
21739
|
newState = Container_objectSpread(Container_objectSpread({}, newState), {}, {
|
|
21331
21740
|
chatterToken: undefined,
|
|
21332
|
-
chatterCreated: undefined
|
|
21741
|
+
chatterCreated: undefined,
|
|
21742
|
+
messagingAuthState: undefined
|
|
21333
21743
|
});
|
|
21334
21744
|
}
|
|
21335
21745
|
await setGlobalState(newState);
|
|
@@ -21359,11 +21769,19 @@ class Container extends preact_module_d {
|
|
|
21359
21769
|
dist/* adaSessionStorage */.ad.removeItem(CHATTER_TOKEN_STORAGE_KEY);
|
|
21360
21770
|
dist/* adaLocalStorage */.BB.removeItem(CHATTER_CREATED_STORAGE_KEY);
|
|
21361
21771
|
dist/* adaSessionStorage */.ad.removeItem(CHATTER_CREATED_STORAGE_KEY);
|
|
21772
|
+
// Scope the clear to this bot so a sibling Ada bot on the same origin keeps its
|
|
21773
|
+
// own messaging auth state (see RESET above).
|
|
21774
|
+
clearMessagingAuthStateFromStorage({
|
|
21775
|
+
handle: adaSettings.handle,
|
|
21776
|
+
cluster: adaSettings.cluster,
|
|
21777
|
+
domain: adaSettings.domain
|
|
21778
|
+
});
|
|
21362
21779
|
|
|
21363
21780
|
// And from state
|
|
21364
21781
|
await setGlobalState({
|
|
21365
21782
|
chatterToken: undefined,
|
|
21366
|
-
chatterCreated: undefined
|
|
21783
|
+
chatterCreated: undefined,
|
|
21784
|
+
messagingAuthState: undefined
|
|
21367
21785
|
});
|
|
21368
21786
|
xStorageChannel.postMessage(DELETE_HISTORY_EVENT, undefined);
|
|
21369
21787
|
localChannel.postMessage(DELETE_HISTORY_RESPONSE, null, id);
|
|
@@ -21594,6 +22012,15 @@ class Container extends preact_module_d {
|
|
|
21594
22012
|
adaSettings: Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
|
|
21595
22013
|
handle: assignedClient.handle
|
|
21596
22014
|
}),
|
|
22015
|
+
// Re-read the handle-scoped messaging auth blob under the assigned bot handle.
|
|
22016
|
+
// getInitialState read it under the original adaSettings.handle, which differs
|
|
22017
|
+
// from assignedClient.handle under alternative-bot rollout, so without this the
|
|
22018
|
+
// host-side JWT fallback would miss the assigned bot's persisted token on reload.
|
|
22019
|
+
messagingAuthState: readMessagingAuthStateFromStorage({
|
|
22020
|
+
handle: assignedClient.handle,
|
|
22021
|
+
cluster: cluster,
|
|
22022
|
+
domain
|
|
22023
|
+
}),
|
|
21597
22024
|
chatterInLiveChat
|
|
21598
22025
|
}));
|
|
21599
22026
|
} catch (e) {
|
|
@@ -21826,6 +22253,7 @@ function embed_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { va
|
|
|
21826
22253
|
|
|
21827
22254
|
|
|
21828
22255
|
|
|
22256
|
+
|
|
21829
22257
|
function renderApp(_ref) {
|
|
21830
22258
|
let {
|
|
21831
22259
|
adaSettings,
|
|
@@ -21850,6 +22278,25 @@ function renderApp(_ref) {
|
|
|
21850
22278
|
if (!parentContainer) {
|
|
21851
22279
|
throw new AdaEmbedError("`parentContainer` is null");
|
|
21852
22280
|
}
|
|
22281
|
+
|
|
22282
|
+
// MES-981: in headless mode the React tree still mounts (so the websocket,
|
|
22283
|
+
// Redux, and FC handlers run) but the entry container is moved off-screen
|
|
22284
|
+
// — the host page controls its own UI on top of the programmatic surface.
|
|
22285
|
+
// We use absolute positioning + 0x0 + clip instead of `display: none`
|
|
22286
|
+
// because Chrome (and Safari) defer iframe loads for elements that are
|
|
22287
|
+
// display:none, which would block the chat iframe from ever registering
|
|
22288
|
+
// its frame-channel handlers.
|
|
22289
|
+
if (adaSettings.headless) {
|
|
22290
|
+
entryContainer.style.position = "absolute";
|
|
22291
|
+
entryContainer.style.left = "0";
|
|
22292
|
+
entryContainer.style.top = "0";
|
|
22293
|
+
entryContainer.style.width = "0";
|
|
22294
|
+
entryContainer.style.height = "0";
|
|
22295
|
+
entryContainer.style.overflow = "hidden";
|
|
22296
|
+
entryContainer.style.clip = "rect(0, 0, 0, 0)";
|
|
22297
|
+
entryContainer.style.pointerEvents = "none";
|
|
22298
|
+
entryContainer.setAttribute("aria-hidden", "true");
|
|
22299
|
+
}
|
|
21853
22300
|
parentContainer.appendChild(entryContainer);
|
|
21854
22301
|
M(v(StoreContext.Provider, {
|
|
21855
22302
|
value: store
|
|
@@ -21899,6 +22346,31 @@ function createEmbed(adaSettings) {
|
|
|
21899
22346
|
initializationReject: reject
|
|
21900
22347
|
});
|
|
21901
22348
|
});
|
|
22349
|
+
|
|
22350
|
+
// MES-981 P1 #10: emit a high-priority log entry on every headless
|
|
22351
|
+
// session start so ops can spot abuse patterns (compromised host site
|
|
22352
|
+
// silently running chatter sessions under the visiting user's token).
|
|
22353
|
+
// Sampled at 1.0 so we never miss one; the volume is bounded by the
|
|
22354
|
+
// host explicitly opting in.
|
|
22355
|
+
if (adaSettings.headless) {
|
|
22356
|
+
log("headless_session_initialized", {
|
|
22357
|
+
handle: adaSettings.handle,
|
|
22358
|
+
parent_origin: window.location.origin
|
|
22359
|
+
}, {
|
|
22360
|
+
sampleRate: 1,
|
|
22361
|
+
level: "info"
|
|
22362
|
+
});
|
|
22363
|
+
}
|
|
22364
|
+
|
|
22365
|
+
// MES-981 P1 #9: headless boot no longer reuses TOGGLE_CHAT_ACTION.
|
|
22366
|
+
// The old dispatch persisted drawer-open state to localStorage and set
|
|
22367
|
+
// `drawerHasBeenOpened` / `focusIsOnAda` even though there is no
|
|
22368
|
+
// visible drawer — which then leaked across reloads. The chat iframe
|
|
22369
|
+
// mounts directly via `shouldRenderChatFrame` returning true for
|
|
22370
|
+
// headless (Container/index.tsx), and the iframe's own init drives
|
|
22371
|
+
// chatter creation, pusher subscription, and greeting fire. No drawer
|
|
22372
|
+
// state needs to flip.
|
|
22373
|
+
|
|
21902
22374
|
const debounceCampaignTrigger = lodash_debounce_default()(async function (campaignKey) {
|
|
21903
22375
|
let triggerCampaignParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
21904
22376
|
await initialized;
|
|
@@ -21921,6 +22393,10 @@ function createEmbed(adaSettings) {
|
|
|
21921
22393
|
await initialized;
|
|
21922
22394
|
await localChannel.fetch(SET_META_FIELDS, SET_META_FIELDS_RESPONSE, options);
|
|
21923
22395
|
},
|
|
22396
|
+
async getMetaFields() {
|
|
22397
|
+
await initialized;
|
|
22398
|
+
return await localChannel.fetch(GET_META_FIELDS, GET_META_FIELDS_RESPONSE);
|
|
22399
|
+
},
|
|
21924
22400
|
async setSensitiveMetaFields(options) {
|
|
21925
22401
|
await initialized;
|
|
21926
22402
|
await localChannel.fetch("SET_SENSITIVE_META_FIELDS", "SET_SENSITIVE_META_FIELDS_RESPONSE", options);
|
|
@@ -21990,6 +22466,30 @@ function createEmbed(adaSettings) {
|
|
|
21990
22466
|
}
|
|
21991
22467
|
};
|
|
21992
22468
|
}
|
|
22469
|
+
;// CONCATENATED MODULE: ./src/common/helpers/with-timeout.ts
|
|
22470
|
+
|
|
22471
|
+
|
|
22472
|
+
/**
|
|
22473
|
+
* Race `promise` against a timeout. If the timeout fires first, reject
|
|
22474
|
+
* with an AdaEmbedError carrying `errorMessage`. If the promise settles
|
|
22475
|
+
* first (resolve or reject), clear the pending timer so it doesn't
|
|
22476
|
+
* keep the event loop alive past resolution.
|
|
22477
|
+
*
|
|
22478
|
+
* MES-981 P1 #7: used to cap host-supplied beforeSend hooks so a
|
|
22479
|
+
* never-resolving delegate can't hang sendMessage forever.
|
|
22480
|
+
*/
|
|
22481
|
+
function withTimeout(promise, ms, errorMessage) {
|
|
22482
|
+
return new Promise((resolve, reject) => {
|
|
22483
|
+
const handle = setTimeout(() => reject(new AdaEmbedError(errorMessage)), ms);
|
|
22484
|
+
Promise.resolve(promise).then(value => {
|
|
22485
|
+
clearTimeout(handle);
|
|
22486
|
+
resolve(value);
|
|
22487
|
+
}, err => {
|
|
22488
|
+
clearTimeout(handle);
|
|
22489
|
+
reject(err);
|
|
22490
|
+
});
|
|
22491
|
+
});
|
|
22492
|
+
}
|
|
21993
22493
|
;// CONCATENATED MODULE: ./src/interface.ts
|
|
21994
22494
|
|
|
21995
22495
|
|
|
@@ -21998,13 +22498,56 @@ function createEmbed(adaSettings) {
|
|
|
21998
22498
|
|
|
21999
22499
|
|
|
22000
22500
|
|
|
22501
|
+
|
|
22502
|
+
|
|
22001
22503
|
const EMBED_NOT_INITIALIZED_ERROR = new AdaEmbedError("Actions cannot be called until Embed has been instantiated. Try running `adaEmbed.start({...})`.");
|
|
22002
22504
|
|
|
22505
|
+
// MES-981 P1 #7: run the host's beforeSend hook with a 5s timeout, validate
|
|
22506
|
+
// its return value, and surface DelegateRejected / DelegateTimeout / shape
|
|
22507
|
+
// errors with the same wording as before. Extracted from sendMessage to
|
|
22508
|
+
// keep that method below the sonarjs cognitive-complexity threshold.
|
|
22509
|
+
async function applyBeforeSend(beforeSend, originalText) {
|
|
22510
|
+
let result;
|
|
22511
|
+
try {
|
|
22512
|
+
result = await withTimeout(beforeSend({
|
|
22513
|
+
text: originalText
|
|
22514
|
+
}), 5000, "DelegateTimeout");
|
|
22515
|
+
} catch (err) {
|
|
22516
|
+
if (err instanceof AdaEmbedError && err.message === "DelegateTimeout") {
|
|
22517
|
+
log("Delegate beforeSend timed out", {
|
|
22518
|
+
timeoutMs: 5000
|
|
22519
|
+
});
|
|
22520
|
+
} else {
|
|
22521
|
+
log("Delegate beforeSend threw", {
|
|
22522
|
+
error: err instanceof Error ? err.message : String(err)
|
|
22523
|
+
});
|
|
22524
|
+
}
|
|
22525
|
+
throw err;
|
|
22526
|
+
}
|
|
22527
|
+
if (result === false) {
|
|
22528
|
+
log("Delegate beforeSend canceled the send", {});
|
|
22529
|
+
throw new AdaEmbedError("DelegateRejected");
|
|
22530
|
+
}
|
|
22531
|
+
const candidate = result;
|
|
22532
|
+
if (!candidate || typeof candidate !== "object" || typeof candidate.text !== "string") {
|
|
22533
|
+
throw new AdaEmbedError("Delegate beforeSend must return `{ text: string }`, `false`, or a Promise resolving to one of these.");
|
|
22534
|
+
}
|
|
22535
|
+
const transformed = candidate.text;
|
|
22536
|
+
if (transformed.trim().length === 0) {
|
|
22537
|
+
throw new AdaEmbedError("sendMessage requires non-empty text after delegate transform");
|
|
22538
|
+
}
|
|
22539
|
+
log("Delegate beforeSend completed", {
|
|
22540
|
+
transformed: transformed !== originalText
|
|
22541
|
+
});
|
|
22542
|
+
return transformed;
|
|
22543
|
+
}
|
|
22544
|
+
|
|
22003
22545
|
/**
|
|
22004
22546
|
* Returns the public Embed methods to be bound to the window object.
|
|
22005
22547
|
*/
|
|
22006
22548
|
function createEmbedInterface() {
|
|
22007
22549
|
let embed = null;
|
|
22550
|
+
let delegate = {};
|
|
22008
22551
|
const toggle = async () => {
|
|
22009
22552
|
if (!embed) {
|
|
22010
22553
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22048,6 +22591,9 @@ function createEmbedInterface() {
|
|
|
22048
22591
|
}
|
|
22049
22592
|
const stopPromise = embed.stop();
|
|
22050
22593
|
embed = null;
|
|
22594
|
+
// MES-981: clear the registered delegate so a subsequent start() begins
|
|
22595
|
+
// with a clean interception state.
|
|
22596
|
+
delegate = {};
|
|
22051
22597
|
try {
|
|
22052
22598
|
await stopPromise;
|
|
22053
22599
|
} finally {
|
|
@@ -22067,6 +22613,12 @@ function createEmbedInterface() {
|
|
|
22067
22613
|
}
|
|
22068
22614
|
return embed.setMetaFields(options);
|
|
22069
22615
|
},
|
|
22616
|
+
getMetaFields: async () => {
|
|
22617
|
+
if (!embed) {
|
|
22618
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22619
|
+
}
|
|
22620
|
+
return embed.getMetaFields();
|
|
22621
|
+
},
|
|
22070
22622
|
setSensitiveMetaFields: async options => {
|
|
22071
22623
|
if (!embed) {
|
|
22072
22624
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22079,6 +22631,20 @@ function createEmbedInterface() {
|
|
|
22079
22631
|
}
|
|
22080
22632
|
return embed.getInfo();
|
|
22081
22633
|
},
|
|
22634
|
+
isOpen: async () => {
|
|
22635
|
+
if (!embed) {
|
|
22636
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22637
|
+
}
|
|
22638
|
+
|
|
22639
|
+
// MES-981: in headless mode the entry container is display:none, so
|
|
22640
|
+
// even a parentElement-mounted embed isn't visible to the user. Treat
|
|
22641
|
+
// it as "not open" regardless of the underlying isDrawerOpen flag.
|
|
22642
|
+
if (embed.adaSettings.headless) {
|
|
22643
|
+
return false;
|
|
22644
|
+
}
|
|
22645
|
+
const info = await embed.getInfo();
|
|
22646
|
+
return info.isChatOpen;
|
|
22647
|
+
},
|
|
22082
22648
|
reset: async resetParams => {
|
|
22083
22649
|
if (!embed) {
|
|
22084
22650
|
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
@@ -22120,6 +22686,12 @@ function createEmbedInterface() {
|
|
|
22120
22686
|
}
|
|
22121
22687
|
return embed.evaluateCampaignConditions(options);
|
|
22122
22688
|
},
|
|
22689
|
+
// MES-981: the public surface accepts both the upstream AdaEventKey set
|
|
22690
|
+
// and the new ada:* keys (ExtendedAdaEventKey). The underlying event
|
|
22691
|
+
// subscription registry is a string-keyed map at runtime, so casting
|
|
22692
|
+
// through any is safe and lets the implementation reuse the existing
|
|
22693
|
+
// subscribeEvent helper.
|
|
22694
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22123
22695
|
subscribeEvent: async (eventKey, callback) => subscribeEvent(eventKey, callback),
|
|
22124
22696
|
unsubscribeEvent: async id => unsubscribeEvent(id),
|
|
22125
22697
|
closeCampaign: async () => {
|
|
@@ -22146,6 +22718,126 @@ function createEmbedInterface() {
|
|
|
22146
22718
|
language
|
|
22147
22719
|
});
|
|
22148
22720
|
},
|
|
22721
|
+
setComposerText: async text => {
|
|
22722
|
+
if (!embed) {
|
|
22723
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22724
|
+
}
|
|
22725
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22726
|
+
if (embed.adaSettings.headless) {
|
|
22727
|
+
throw new AdaEmbedError("HeadlessModeError: setComposerText is not available in headless mode");
|
|
22728
|
+
}
|
|
22729
|
+
|
|
22730
|
+
// MES-981: wait for chat to finish init before forwarding the
|
|
22731
|
+
// postMessage, matching the existing behaviour of setMetaFields etc.
|
|
22732
|
+
await embed.initialized;
|
|
22733
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22734
|
+
if (!channel) {
|
|
22735
|
+
throw new AdaEmbedError("Chat is not ready yet to have composer text set.");
|
|
22736
|
+
}
|
|
22737
|
+
|
|
22738
|
+
// MES-981 P0 #3: SET_COMPOSER_TEXT is request/response so chat-side
|
|
22739
|
+
// validation failures (INVALID_PAYLOAD, TOO_LONG) reach the caller.
|
|
22740
|
+
const response = await channel.fetch("SET_COMPOSER_TEXT", "SET_COMPOSER_TEXT_RESPONSE", {
|
|
22741
|
+
text
|
|
22742
|
+
});
|
|
22743
|
+
if (!response) {
|
|
22744
|
+
throw new AdaEmbedError("setComposerText timed out — chat frame did not respond in time.");
|
|
22745
|
+
}
|
|
22746
|
+
if ("error" in response) {
|
|
22747
|
+
throw new AdaEmbedError(`setComposerText rejected by chat: ${response.error}`);
|
|
22748
|
+
}
|
|
22749
|
+
},
|
|
22750
|
+
getConversation: async () => {
|
|
22751
|
+
if (!embed) {
|
|
22752
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22753
|
+
}
|
|
22754
|
+
|
|
22755
|
+
// MES-981 P0 #4: getConversation returns the live-agent handoff
|
|
22756
|
+
// identity (id / name / avatarUrl) alongside the conversation id.
|
|
22757
|
+
// Same host-page exposure surface as ada:message:* and getMessages,
|
|
22758
|
+
// so the same opt-in gate applies.
|
|
22759
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22760
|
+
await embed.initialized;
|
|
22761
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22762
|
+
if (!channel) {
|
|
22763
|
+
throw new AdaEmbedError("Chat is not ready yet to read conversation.");
|
|
22764
|
+
}
|
|
22765
|
+
const response = await channel.fetch("GET_CONVERSATION", "GET_CONVERSATION_RESPONSE");
|
|
22766
|
+
if (!response) {
|
|
22767
|
+
throw new AdaEmbedError("getConversation timed out — chat frame did not respond in time.");
|
|
22768
|
+
}
|
|
22769
|
+
return response;
|
|
22770
|
+
},
|
|
22771
|
+
getMessages: async () => {
|
|
22772
|
+
if (!embed) {
|
|
22773
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22774
|
+
}
|
|
22775
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22776
|
+
await embed.initialized;
|
|
22777
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22778
|
+
if (!channel) {
|
|
22779
|
+
throw new AdaEmbedError("Chat is not ready yet to read messages.");
|
|
22780
|
+
}
|
|
22781
|
+
const response = await channel.fetch("GET_MESSAGES", "GET_MESSAGES_RESPONSE");
|
|
22782
|
+
|
|
22783
|
+
// MES-981 P1 #6: channel.fetch resolves to undefined on timeout.
|
|
22784
|
+
// The previous behavior normalized that to [], which made a real
|
|
22785
|
+
// chat-frame failure indistinguishable from an empty transcript.
|
|
22786
|
+
// Fail loudly instead so hosts can branch on the error.
|
|
22787
|
+
if (response === undefined) {
|
|
22788
|
+
throw new AdaEmbedError("getMessages timed out — chat frame did not respond in time.");
|
|
22789
|
+
}
|
|
22790
|
+
return response;
|
|
22791
|
+
},
|
|
22792
|
+
sendMessage: async text => {
|
|
22793
|
+
if (!embed) {
|
|
22794
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22795
|
+
}
|
|
22796
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22797
|
+
|
|
22798
|
+
// MES-981: reject empty AND whitespace-only text so we never POST a
|
|
22799
|
+
// meaningless body to /message/chat/.
|
|
22800
|
+
if (typeof text !== "string" || text.trim().length === 0) {
|
|
22801
|
+
throw new AdaEmbedError("sendMessage requires non-empty text");
|
|
22802
|
+
}
|
|
22803
|
+
|
|
22804
|
+
// MES-981: gate on init BEFORE running the host's beforeSend hook.
|
|
22805
|
+
// Otherwise an init failure (or a missing chat channel) leaves the
|
|
22806
|
+
// host with delegate side-effects — analytics logs, UI optimism — for
|
|
22807
|
+
// a message that can never be sent. Match the gating order used by
|
|
22808
|
+
// every other public method on this surface.
|
|
22809
|
+
await embed.initialized;
|
|
22810
|
+
const channel = embed.messageService.getChannel("chat");
|
|
22811
|
+
if (!channel) {
|
|
22812
|
+
throw new AdaEmbedError("Chat is not ready yet to send a message.");
|
|
22813
|
+
}
|
|
22814
|
+
const {
|
|
22815
|
+
beforeSend
|
|
22816
|
+
} = delegate;
|
|
22817
|
+
const finalText = beforeSend ? await applyBeforeSend(beforeSend, text) : text;
|
|
22818
|
+
const response = await channel.fetch("SEND_MESSAGE", "SEND_MESSAGE_RESPONSE", {
|
|
22819
|
+
text: finalText
|
|
22820
|
+
});
|
|
22821
|
+
if (!response) {
|
|
22822
|
+
throw new AdaEmbedError("sendMessage timed out — chat frame did not respond in time.");
|
|
22823
|
+
}
|
|
22824
|
+
|
|
22825
|
+
// MES-981 P0 #2: chat-side validation/rate-limit/dispatch failures
|
|
22826
|
+
// come back as `{ error: <code> }`. Surface the code to the caller
|
|
22827
|
+
// so they can branch on machine-readable reasons (TOO_LONG,
|
|
22828
|
+
// RATE_LIMITED, EMPTY_TEXT, INVALID_PAYLOAD, DISPATCH_FAILED).
|
|
22829
|
+
if ("error" in response) {
|
|
22830
|
+
throw new AdaEmbedError(`sendMessage rejected by chat: ${response.error}`);
|
|
22831
|
+
}
|
|
22832
|
+
return response;
|
|
22833
|
+
},
|
|
22834
|
+
setDelegate: newDelegate => {
|
|
22835
|
+
if (!embed) {
|
|
22836
|
+
throw EMBED_NOT_INITIALIZED_ERROR;
|
|
22837
|
+
}
|
|
22838
|
+
requireProgrammaticControl(embed.adaSettings);
|
|
22839
|
+
delegate = newDelegate ?? {};
|
|
22840
|
+
},
|
|
22149
22841
|
handleNotification: async () => {
|
|
22150
22842
|
if (!embed) {
|
|
22151
22843
|
throw EMBED_NOT_INITIALIZED_ERROR;
|