@ada-support/embed2 1.14.3 → 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.
@@ -1,3 +1,8 @@
1
1
  import type { Client } from "common/models/client";
2
+ import type { AdaCluster } from "common/types";
2
3
  import type { MessagePayload } from "common/types/events";
3
- export declare function storeChatterEventDataInBrowser(client: Client, payload: MessagePayload): void;
4
+ export declare function storeChatterEventDataInBrowser(client: Client, payload: MessagePayload, { cluster, domain, privateMode, }?: {
5
+ cluster?: AdaCluster;
6
+ domain?: string;
7
+ privateMode?: boolean;
8
+ }): void;
@@ -0,0 +1,34 @@
1
+ import type { AdaCluster } from "common/types";
2
+ export interface MessagingAuthState {
3
+ messagingToken: string;
4
+ messagingTokenExpiresAt: number;
5
+ sessionRefreshToken: string;
6
+ refreshGeneration: number;
7
+ }
8
+ type MessagingAuthStatePersistence = "normal" | "session" | "private" | string | null | undefined;
9
+ declare const MESSAGING_AUTH_STATE_STORAGE_KEY: "messagingAuthState";
10
+ export declare function buildMessagingAuthStateStorageKey({ handle, cluster, domain, }: {
11
+ handle: string | null | undefined;
12
+ cluster?: AdaCluster;
13
+ domain?: string;
14
+ }): typeof MESSAGING_AUTH_STATE_STORAGE_KEY | null;
15
+ export declare function parseMessagingAuthState(value: unknown): MessagingAuthState | null;
16
+ export declare function readMessagingAuthStateFromStorage({ handle, cluster, domain, }: {
17
+ handle: string | null | undefined;
18
+ cluster?: AdaCluster;
19
+ domain?: string;
20
+ }): MessagingAuthState | undefined;
21
+ export declare function writeMessagingAuthStateToStorage({ handle, cluster, domain, persistence, state, }: {
22
+ handle: string | null | undefined;
23
+ cluster?: AdaCluster;
24
+ domain?: string;
25
+ persistence: MessagingAuthStatePersistence;
26
+ state: MessagingAuthState | null | undefined;
27
+ }): boolean;
28
+ export declare function clearAllMessagingAuthStatesFromStorage(): void;
29
+ export declare function clearMessagingAuthStateFromStorage({ handle, cluster, domain, }: {
30
+ handle: string | null | undefined;
31
+ cluster?: AdaCluster;
32
+ domain?: string;
33
+ }): void;
34
+ export {};
@@ -1,11 +1,13 @@
1
1
  import type { Modality, StartOptions } from "@ada-support/embed-types";
2
2
  import type { ConnectionState } from "common/constants/events";
3
+ import type { MessagingAuthState } from "common/helpers/messaging-auth-state";
3
4
  import type { Client } from "common/models/client";
4
5
  import type { AdaCluster } from "common/types";
5
6
  export interface StoreState extends StartOptionsNoFunction {
6
7
  chatterCreated: string | undefined;
7
8
  chatterToken: string | undefined;
8
9
  sessionToken: string | undefined;
10
+ messagingAuthState?: MessagingAuthState;
9
11
  client?: Client;
10
12
  enabledLanguages: string[];
11
13
  isDrawerOpen: boolean;
@@ -15919,7 +15919,7 @@ const client = new BrowserClient({
15919
15919
  return event;
15920
15920
  },
15921
15921
  environment: "production",
15922
- release: "1.14.3-00422f5",
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
@@ -16543,7 +16543,7 @@ function getEmbedURL(_ref) {
16543
16543
  } else {
16544
16544
  host = `http://${handle}.localhost:${ports.localhost.default}`;
16545
16545
  }
16546
- return `${host}/embed/${frameName}/${"00422f5"}/index.html`;
16546
+ return `${host}/embed/${frameName}/${"57d2690"}/index.html`;
16547
16547
  }
16548
16548
  function constructQueryString(query) {
16549
16549
  return Object.keys(query).map(key => {
@@ -17037,11 +17037,192 @@ const ZD_MESSAGING_CHATTER_CREATED_STORAGE_KEY = "ada-embed_zd-messaging-chatter
17037
17037
 
17038
17038
  /** @deprecated - Use CHATTER_TOKEN_STORAGE_KEY */
17039
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
+ }
17040
17220
  ;// CONCATENATED MODULE: ./src/client/store/state.ts
17041
17221
 
17042
17222
 
17043
17223
 
17044
17224
 
17225
+
17045
17226
  function getValueFromStorage(key) {
17046
17227
  return dist/* adaLocalStorage */.BB.getItem(key) || dist/* adaSessionStorage */.ad.getItem(key);
17047
17228
  }
@@ -17076,6 +17257,11 @@ const getInitialState = adaSettings => ({
17076
17257
  chatterToken: getValueFromStorage(CHATTER_TOKEN_STORAGE_KEY) || undefined,
17077
17258
  chatterCreated: getValueFromStorage(CHATTER_CREATED_STORAGE_KEY) || undefined,
17078
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
+ }),
17079
17265
  zdSessionId: getValueFromStorage(ZD_SESSION_STORAGE_KEY) || undefined,
17080
17266
  zdPreviousTags: getValueFromStorage(ZD_PREVIOUS_TAGS_STORAGE_KEY) || undefined,
17081
17267
  zdMessagingExternalUserId: getValueFromStorage(ZD_MESSAGING_EXTERNAL_USER_ID_STORAGE_KEY) || null,
@@ -17143,9 +17329,9 @@ async function log(message, extra, options) {
17143
17329
  service: "embed",
17144
17330
  env: "production",
17145
17331
  embedVersion: 2,
17146
- version: "1.14.3",
17332
+ version: "1.14.4",
17147
17333
  isNpm: true,
17148
- commitHash: "00422f5"
17334
+ commitHash: "57d2690"
17149
17335
  }))
17150
17336
  });
17151
17337
  }
@@ -19465,20 +19651,72 @@ function shouldDeliverTranscriptEvent(eventKey, adaSettings) {
19465
19651
  ;// CONCATENATED MODULE: ./src/client/components/ChatFrame/chatFrameEvents/chatterEvent/index.ts
19466
19652
 
19467
19653
 
19654
+
19468
19655
  function storeChatterEventDataInBrowser(client, payload) {
19469
- const {
19470
- persistence
19471
- } = client;
19656
+ let {
19657
+ cluster,
19658
+ domain,
19659
+ privateMode
19660
+ } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
19472
19661
  const {
19473
19662
  chatter,
19474
19663
  created,
19475
- sessionToken
19664
+ sessionToken,
19665
+ messagingAuthState
19476
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
+ }
19477
19689
  setBrowserStorageItem(CHATTER_TOKEN_STORAGE_KEY, chatter, persistence);
19478
19690
  setBrowserStorageItem(CHATTER_CREATED_STORAGE_KEY, created, persistence);
19479
19691
  if (sessionToken) {
19480
19692
  setBrowserStorageItem(SESSION_AUTH_TOKEN_STORAGE_KEY, sessionToken, persistence);
19481
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
+ }
19482
19720
  }
19483
19721
  ;// CONCATENATED MODULE: ./src/client/components/ChatFrame/chatFrameEvents/index.ts
19484
19722
 
@@ -19706,7 +19944,7 @@ class ChatFrame extends preact_module_d {
19706
19944
  log("Chat frame mount", {
19707
19945
  handle,
19708
19946
  chatUrl: this.url,
19709
- embedVersion: "00422f5".slice(0, 7),
19947
+ embedVersion: "57d2690".slice(0, 7),
19710
19948
  embedSettings: adaSettings
19711
19949
  });
19712
19950
 
@@ -19794,7 +20032,7 @@ class ChatFrame extends preact_module_d {
19794
20032
  const hostPageUrlParams = new URL(window.location.href).searchParams;
19795
20033
  const smsToken = hostPageUrlParams.get("adaSMSToken");
19796
20034
  const queryParams = {
19797
- embedVersion: "00422f5".slice(0, 7),
20035
+ embedVersion: "57d2690".slice(0, 7),
19798
20036
  greeting,
19799
20037
  language,
19800
20038
  skipGreeting,
@@ -20132,12 +20370,16 @@ class ChatFrame extends preact_module_d {
20132
20370
  case CHATTER_EVENT:
20133
20371
  {
20134
20372
  const {
20135
- client
20373
+ client,
20374
+ cluster,
20375
+ domain,
20376
+ privateMode
20136
20377
  } = this.props;
20137
20378
  const {
20138
20379
  chatter,
20139
20380
  created,
20140
- sessionToken
20381
+ sessionToken,
20382
+ messagingAuthState
20141
20383
  } = payload;
20142
20384
  const {
20143
20385
  chatterTokenCallback
@@ -20145,14 +20387,19 @@ class ChatFrame extends preact_module_d {
20145
20387
  if (!client) {
20146
20388
  throw new AdaEmbedError("`client` is undefined");
20147
20389
  }
20148
- storeChatterEventDataInBrowser(client, payload);
20390
+ storeChatterEventDataInBrowser(client, payload, {
20391
+ cluster,
20392
+ domain,
20393
+ privateMode
20394
+ });
20149
20395
  if (chatterTokenCallback) {
20150
20396
  chatterTokenCallback(chatter);
20151
20397
  }
20152
20398
  await setGlobalState({
20153
20399
  chatterToken: chatter,
20154
20400
  chatterCreated: created,
20155
- sessionToken
20401
+ sessionToken,
20402
+ messagingAuthState
20156
20403
  });
20157
20404
  break;
20158
20405
  }
@@ -20824,6 +21071,7 @@ function Container_objectSpread(e) { for (var r = 1; r < arguments.length; r++)
20824
21071
 
20825
21072
 
20826
21073
 
21074
+
20827
21075
 
20828
21076
 
20829
21077
  class Container extends preact_module_d {
@@ -21478,11 +21726,20 @@ class Container extends preact_module_d {
21478
21726
  dist/* adaSessionStorage */.ad.removeItem(CHATTER_TOKEN_STORAGE_KEY);
21479
21727
  dist/* adaLocalStorage */.BB.removeItem(CHATTER_CREATED_STORAGE_KEY);
21480
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
+ });
21481
21737
 
21482
21738
  // And from state
21483
21739
  newState = Container_objectSpread(Container_objectSpread({}, newState), {}, {
21484
21740
  chatterToken: undefined,
21485
- chatterCreated: undefined
21741
+ chatterCreated: undefined,
21742
+ messagingAuthState: undefined
21486
21743
  });
21487
21744
  }
21488
21745
  await setGlobalState(newState);
@@ -21512,11 +21769,19 @@ class Container extends preact_module_d {
21512
21769
  dist/* adaSessionStorage */.ad.removeItem(CHATTER_TOKEN_STORAGE_KEY);
21513
21770
  dist/* adaLocalStorage */.BB.removeItem(CHATTER_CREATED_STORAGE_KEY);
21514
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
+ });
21515
21779
 
21516
21780
  // And from state
21517
21781
  await setGlobalState({
21518
21782
  chatterToken: undefined,
21519
- chatterCreated: undefined
21783
+ chatterCreated: undefined,
21784
+ messagingAuthState: undefined
21520
21785
  });
21521
21786
  xStorageChannel.postMessage(DELETE_HISTORY_EVENT, undefined);
21522
21787
  localChannel.postMessage(DELETE_HISTORY_RESPONSE, null, id);
@@ -21747,6 +22012,15 @@ class Container extends preact_module_d {
21747
22012
  adaSettings: Container_objectSpread(Container_objectSpread({}, adaSettings), {}, {
21748
22013
  handle: assignedClient.handle
21749
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
+ }),
21750
22024
  chatterInLiveChat
21751
22025
  }));
21752
22026
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ada-support/embed2",
3
- "version": "1.14.3",
3
+ "version": "1.14.4",
4
4
  "description": "",
5
5
  "main": "dist/npm-entry",
6
6
  "typings": "dist/npm-entry/index-npm.d.ts",
@@ -91,7 +91,7 @@
91
91
  },
92
92
  "dependencies": {
93
93
  "@ada-support/embed-types": "^1.9.2",
94
- "@ada-support/web-storage": "^1.2.9",
94
+ "@ada-support/web-storage": "^1.3.0",
95
95
  "@babel/runtime-corejs3": "^7.26.10",
96
96
  "@sentry/browser": "^8.33.0",
97
97
  "@sentry/types": "^8.33.1",