@qualified-salesforce/web 0.0.1-oidc-bootstrap → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CAPABILITY-REFERENCE.md +44 -0
- package/CHANGELOG.md +75 -0
- package/constants.generated.js +30 -2
- package/css/widget/multimodal_v2/index.split-css.panda.css +265 -47
- package/package.json +17 -3
- package/packs/widget/api/docking/viewport_lock.js +93 -2
- package/packs/widget/esm/index.d.ts +134 -0
- package/packs/widget/esm/index.js +18 -2
- package/packs/widget/esm/qualified.css +265 -47
- package/src/graphql-types.js +74 -1
- package/src/url.js +4 -1
- package/vendor/actioncable/connection.js +40 -3
- package/vendor/actioncable/connection_monitor.js +8 -0
- package/vendor/actioncable/consumer.js +7 -1
- package/vendor/actioncable/index.js +5 -2
- package/vendor/actioncable/sse_socket.js +262 -0
- package/widget/analytics.js +8 -0
- package/widget/api_handler/base_api_handler.js +24 -0
- package/widget/booker_outcome_tracker.js +58 -20
- package/widget/capabilities.js +190 -0
- package/widget/channel.js +38 -6
- package/widget/constants.generated.js +2 -1
- package/widget/multimodal_v2/components/AppLayout.js +1 -1
- package/widget/multimodal_v2/components/app/Foreground.js +10 -9
- package/widget/multimodal_v2/components/app/Input.js +8 -3
- package/widget/multimodal_v2/components/app/LightboxExperience.js +17 -3
- package/widget/multimodal_v2/components/app/Main.js +87 -31
- package/widget/multimodal_v2/components/app/MessengerButton.js +18 -1
- package/widget/multimodal_v2/components/chat/ChatInputForm.js +8 -6
- package/widget/multimodal_v2/components/chat/timeline/CalendarEventPickRenderer.js +2 -2
- package/widget/multimodal_v2/components/chat/timeline/PresentDeckRenderer.js +346 -170
- package/widget/multimodal_v2/components/chat/timeline/SystemRenderer.js +4 -7
- package/widget/multimodal_v2/components/decks/index.js +506 -52
- package/widget/multimodal_v2/components/helpers/content_click_payloads.js +67 -1
- package/widget/multimodal_v2/components/lightbox_gather/index.js +4 -4
- package/widget/multimodal_v2/components/meetings/MeetingBookerEntry.js +8 -1
- package/widget/multimodal_v2/components/meetings/MeetingOfferEmailStep.js +1 -1
- package/widget/multimodal_v2/components/meetings/MeetingSummaryRail.js +1 -1
- package/widget/multimodal_v2/components/meetings/MeetingTimeSelector.js +1 -1
- package/widget/multimodal_v2/components/multimodal/Controls.js +11 -3
- package/widget/multimodal_v2/components/multimodal/useMultimodal.js +19 -7
- package/widget/multimodal_v2/components/presentations/index.js +61 -0
- package/widget/multimodal_v2/constants.js +1 -1
- package/widget/multimodal_v2/images/icons.js +17 -1
- package/widget/multimodal_v2/index.panda.js +2 -2
- package/widget/multimodal_v2/locales/cs.js +8 -1
- package/widget/multimodal_v2/locales/da.js +8 -1
- package/widget/multimodal_v2/locales/de.js +8 -1
- package/widget/multimodal_v2/locales/en.js +8 -1
- package/widget/multimodal_v2/locales/en_AU.js +8 -1
- package/widget/multimodal_v2/locales/en_GB.js +8 -1
- package/widget/multimodal_v2/locales/es.js +8 -1
- package/widget/multimodal_v2/locales/es_LA.js +8 -1
- package/widget/multimodal_v2/locales/fi.js +8 -1
- package/widget/multimodal_v2/locales/fr.js +8 -1
- package/widget/multimodal_v2/locales/fr_CA.js +8 -1
- package/widget/multimodal_v2/locales/id.js +8 -1
- package/widget/multimodal_v2/locales/it.js +8 -1
- package/widget/multimodal_v2/locales/ja.js +8 -1
- package/widget/multimodal_v2/locales/ko.js +8 -1
- package/widget/multimodal_v2/locales/nb.js +8 -1
- package/widget/multimodal_v2/locales/nl.js +8 -1
- package/widget/multimodal_v2/locales/pl.js +8 -1
- package/widget/multimodal_v2/locales/pt_BR.js +8 -1
- package/widget/multimodal_v2/locales/ru.js +8 -1
- package/widget/multimodal_v2/locales/sv.js +8 -1
- package/widget/multimodal_v2/locales/th.js +8 -1
- package/widget/multimodal_v2/locales/tr.js +8 -1
- package/widget/multimodal_v2/locales/vi.js +8 -1
- package/widget/multimodal_v2/locales/zh_CN.js +8 -1
- package/widget/multimodal_v2/locales/zh_TW.js +8 -1
- package/widget/multimodal_v2/multimodal.js +5 -1
- package/widget/multimodal_v2/multimodal_channel.js +13 -8
- package/widget/multimodal_v2/signals/messages_signal.js +4 -0
- package/widget/multimodal_v2/stores/ai_conversation_store.js +6 -2
- package/widget/multimodal_v2/stores/artifact_store.js +352 -27
- package/widget/multimodal_v2/stores/call_store.js +40 -1
- package/widget/multimodal_v2/stores/call_ui_adapter.js +1 -1
- package/widget/multimodal_v2/stores/decks_store.js +405 -39
- package/widget/multimodal_v2/stores/meeting_store.js +15 -10
- package/widget/multimodal_v2/stores/presentation_ga_adapter.js +64 -0
- package/widget/multimodal_v2/stores/presentation_telemetry_store.js +556 -0
- package/widget/multimodal_v2/stores/presentations_store.js +1 -0
- package/widget/multimodal_v2/stores/root_store.js +157 -268
- package/widget/multimodal_v2/stores/screen_share_store.js +41 -21
- package/widget/multimodal_v2/stores/translation_store.js +9 -0
- package/widget/multimodal_v2/stores/ui_store.js +7 -7
- package/widget/multimodal_v2/stores/website_navigation_store.js +3 -1
- package/widget/multimodal_v2/text_turn_response_tracker.js +419 -0
- package/widget/multimodal_v2/types.js +21 -1
- package/widget/multimodal_v2/utils/locale.js +2 -1
- package/widget/multimodal_v2/utils/signals.js +35 -4
- package/widget/pardot_visitor.js +7 -1
- package/widget/server-logger.js +97 -2
- package/widget/tracker.js +69 -21
- package/widget/widget/page_mirror_factory.js +9 -1
- package/widget/widget/widget.js +29 -4
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { __webpack_require__ } from "../../../js/runtime.js";
|
|
1
2
|
import { signals_core_module_d, signals_core_module_w } from "../../../js/multimodal_v2.js";
|
|
2
3
|
import { getCache } from "./multimodal_cache.js";
|
|
3
4
|
import { ObjectsMap } from "./objects_map.js";
|
|
5
|
+
import "../../utils/native_globals.js";
|
|
4
6
|
|
|
7
|
+
/* provided dependency */ var signals_setTimeout = __webpack_require__(68034).pS;
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
|
|
@@ -45,6 +48,31 @@ function $attr(signal, key) {
|
|
|
45
48
|
return (_ref = (_signal_value = signal.value) == null ? void 0 : _signal_value[key]) != null ? _ref : null;
|
|
46
49
|
});
|
|
47
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Backoff between extra attempts at a failed dynamic import.
|
|
53
|
+
*
|
|
54
|
+
* Small on purpose. A chunk whose hash was rotated away by a deploy 404s on
|
|
55
|
+
* every attempt, so only a transient fetch benefits and a longer budget just
|
|
56
|
+
* holds the caller — an overlay waiting to open — for no gain.
|
|
57
|
+
*/ const IMPORT_RETRY_DELAYS_MS = [
|
|
58
|
+
250,
|
|
59
|
+
1000
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* Runs a dynamic import, retrying a failure on the backoff above.
|
|
63
|
+
*
|
|
64
|
+
* Exported for chunks loaded outside a `$fromImport` store. Wrap the import
|
|
65
|
+
* itself, not work that follows it: a retry re-runs whatever it is given, and
|
|
66
|
+
* only the fetch is worth a second attempt.
|
|
67
|
+
*/ const importWithRetry = (importFn, attempt)=>{
|
|
68
|
+
if (attempt === void 0) attempt = 0;
|
|
69
|
+
return importFn().catch((error)=>{
|
|
70
|
+
if (attempt >= IMPORT_RETRY_DELAYS_MS.length) throw error;
|
|
71
|
+
return new Promise((resolve, reject)=>{
|
|
72
|
+
signals_setTimeout(()=>importWithRetry(importFn, attempt + 1).then(resolve, reject), IMPORT_RETRY_DELAYS_MS[attempt]);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
};
|
|
48
76
|
function $fromImport(importFn) {
|
|
49
77
|
for(var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
|
|
50
78
|
args[_key - 1] = arguments[_key];
|
|
@@ -60,12 +88,15 @@ function $fromImport(importFn) {
|
|
|
60
88
|
if (loadPromise) {
|
|
61
89
|
return loadPromise;
|
|
62
90
|
}
|
|
63
|
-
|
|
64
|
-
loadPromise = importFn().then((module)=>{
|
|
65
|
-
// Use default export
|
|
91
|
+
loadPromise = importWithRetry(importFn).then((module)=>{
|
|
66
92
|
const Class = module.default;
|
|
67
93
|
sig.value = new Class(...args);
|
|
68
94
|
return sig.value;
|
|
95
|
+
}) // Clear on failure so a later caller starts over instead of re-awaiting
|
|
96
|
+
// this rejection for the rest of the session.
|
|
97
|
+
.catch((error)=>{
|
|
98
|
+
loadPromise = null;
|
|
99
|
+
throw error;
|
|
69
100
|
});
|
|
70
101
|
return loadPromise;
|
|
71
102
|
};
|
|
@@ -94,4 +125,4 @@ var signals_$all = /* unused export */ undefined;
|
|
|
94
125
|
var signals_$attr = /* unused export */ undefined;
|
|
95
126
|
var signals_$empty = /* unused export */ undefined;
|
|
96
127
|
var signals_$present = /* unused export */ undefined;
|
|
97
|
-
export { $any, $exists, $fromImport, $not, isSignalike, signals_$absent as $absent, signals_$all as $all, signals_$attr as $attr, signals_$empty as $empty, signals_$present as $present };
|
|
128
|
+
export { $any, $exists, $fromImport, $not, importWithRetry, isSignalike, signals_$absent as $absent, signals_$all as $all, signals_$attr as $attr, signals_$empty as $empty, signals_$present as $present };
|
package/widget/pardot_visitor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __webpack_require__ } from "../js/runtime.js";
|
|
2
2
|
import { api } from "../js/4101.js";
|
|
3
3
|
import { delay as timing_delay } from "../src/timing.js";
|
|
4
|
+
import { isCapabilityAllowed } from "./capabilities.js";
|
|
4
5
|
import "./telemetry/index.js";
|
|
5
6
|
import "./utils/native_globals.js";
|
|
6
7
|
import { telemetry, getTelemetryCtx } from "./telemetry/telemetry.js";
|
|
@@ -9,6 +10,7 @@ import { telemetry, getTelemetryCtx } from "./telemetry/telemetry.js";
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
13
|
+
|
|
12
14
|
class PardotVisitor {
|
|
13
15
|
async getIdentities() {
|
|
14
16
|
const identities = {};
|
|
@@ -87,7 +89,11 @@ class PardotVisitor {
|
|
|
87
89
|
}
|
|
88
90
|
getProspectEmail() {
|
|
89
91
|
const { trackerDomain, accountId, dynamicContentId } = this.config;
|
|
90
|
-
|
|
92
|
+
// QAI-5864: never inject the third-party Pardot `dc.js` script when the consumer hasn't
|
|
93
|
+
// allowed the "pardot" capability. This is the one "must never load" third-party resource
|
|
94
|
+
// from the GitHub security review (finding 1). Allow-all for the hosted widget (no boundary
|
|
95
|
+
// installed); default-deny once an npm consumer enrols an allowlist via setup().
|
|
96
|
+
if (!isCapabilityAllowed("pardot") || !dynamicContentId) {
|
|
91
97
|
const promise = Promise.reject();
|
|
92
98
|
promise.cancel = ()=>{};
|
|
93
99
|
return promise;
|
package/widget/server-logger.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { __webpack_require__ } from "../js/runtime.js";
|
|
2
2
|
import { _class_private_field_loose_base, _class_private_field_loose_key, _extends } from "../js/4101.js";
|
|
3
3
|
import { getSentryClient } from "./widget/sentry.js";
|
|
4
|
+
import "./utils/native_globals.js";
|
|
4
5
|
|
|
5
6
|
const isNil = __webpack_require__("11655");
|
|
6
7
|
var isNil_default = /*#__PURE__*/__webpack_require__.n(isNil);
|
|
8
|
+
/* provided dependency */ var server_logger_setTimeout = __webpack_require__(68034).pS;
|
|
9
|
+
/* provided dependency */ var server_logger_clearTimeout = __webpack_require__(68034).Kj;
|
|
10
|
+
/* provided dependency */ var __nativeWindowAddEventListener = __webpack_require__(68034).zh;
|
|
11
|
+
/* provided dependency */ var __nativeDocumentAddEventListener = __webpack_require__(68034).Qj;
|
|
7
12
|
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
const VISITOR_EVENTS_BATCH_SIZE_LIMIT = 20;
|
|
18
|
+
const VISITOR_EVENTS_BATCH_FLUSH_INTERVAL_MS = 3000;
|
|
19
|
+
var _config = /*#__PURE__*/ _class_private_field_loose_key("_config"), _widgetId = /*#__PURE__*/ _class_private_field_loose_key("_widgetId"), _visitorId = /*#__PURE__*/ _class_private_field_loose_key("_visitorId"), _batchQueue = /*#__PURE__*/ _class_private_field_loose_key("_batchQueue"), _flushTimerId = /*#__PURE__*/ _class_private_field_loose_key("_flushTimerId");
|
|
13
20
|
class ServerLogger {
|
|
14
21
|
/**
|
|
15
22
|
* Updates the widget configuration.
|
|
@@ -66,9 +73,19 @@ class ServerLogger {
|
|
|
66
73
|
* serverLog({ message: "Page closing", fireAndForget: true });
|
|
67
74
|
*/ serverLog(param) {
|
|
68
75
|
let { type = "log", message: event, extra = {}, fireAndForget = false } = param;
|
|
76
|
+
var _class_private_field_loose_base__config_featureFlags;
|
|
69
77
|
if (!_class_private_field_loose_base(this, _config)[_config].host || !_class_private_field_loose_base(this, _config)[_config].token) {
|
|
70
78
|
return;
|
|
71
79
|
}
|
|
80
|
+
if ((_class_private_field_loose_base__config_featureFlags = _class_private_field_loose_base(this, _config)[_config].featureFlags) == null ? void 0 : _class_private_field_loose_base__config_featureFlags.widgetVisitorEventsBatching) {
|
|
81
|
+
this.enqueueEvent({
|
|
82
|
+
event,
|
|
83
|
+
type,
|
|
84
|
+
extra,
|
|
85
|
+
fireAndForget
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
72
89
|
this.sendEvent("visitor_events", {
|
|
73
90
|
params: {
|
|
74
91
|
wu: _class_private_field_loose_base(this, _widgetId)[_widgetId],
|
|
@@ -99,6 +116,54 @@ class ServerLogger {
|
|
|
99
116
|
})
|
|
100
117
|
});
|
|
101
118
|
}
|
|
119
|
+
enqueueEvent(item) {
|
|
120
|
+
_class_private_field_loose_base(this, _batchQueue)[_batchQueue].push(item);
|
|
121
|
+
if (_class_private_field_loose_base(this, _batchQueue)[_batchQueue].length >= VISITOR_EVENTS_BATCH_SIZE_LIMIT) {
|
|
122
|
+
this.flushBatch();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.scheduleFlush();
|
|
126
|
+
}
|
|
127
|
+
scheduleFlush() {
|
|
128
|
+
if (_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId] !== null) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId] = server_logger_setTimeout(()=>this.flushBatch(), VISITOR_EVENTS_BATCH_FLUSH_INTERVAL_MS);
|
|
132
|
+
}
|
|
133
|
+
flushBatch(param) {
|
|
134
|
+
let { fireAndForget = false } = param === void 0 ? {} : param;
|
|
135
|
+
if (_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId] !== null) {
|
|
136
|
+
server_logger_clearTimeout(_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId]);
|
|
137
|
+
_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId] = null;
|
|
138
|
+
}
|
|
139
|
+
if (_class_private_field_loose_base(this, _batchQueue)[_batchQueue].length === 0) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const events = _class_private_field_loose_base(this, _batchQueue)[_batchQueue];
|
|
143
|
+
_class_private_field_loose_base(this, _batchQueue)[_batchQueue] = [];
|
|
144
|
+
// A batch is one request: if any queued event asked to be fire-and-forgotten
|
|
145
|
+
// (e.g. an abandonment logged on its own pagehide listener), the whole flush
|
|
146
|
+
// is, since we can't selectively suppress errors for part of one response.
|
|
147
|
+
const shouldFireAndForget = fireAndForget || events.some((event)=>event.fireAndForget);
|
|
148
|
+
this.sendEvent("visitor_events/batch", {
|
|
149
|
+
params: {
|
|
150
|
+
wu: _class_private_field_loose_base(this, _widgetId)[_widgetId],
|
|
151
|
+
uuid: _class_private_field_loose_base(this, _visitorId)[_visitorId]
|
|
152
|
+
},
|
|
153
|
+
body: {
|
|
154
|
+
events: events.map((param)=>{
|
|
155
|
+
let { event, type, extra } = param;
|
|
156
|
+
return {
|
|
157
|
+
event,
|
|
158
|
+
type,
|
|
159
|
+
extra
|
|
160
|
+
};
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}, {
|
|
164
|
+
fireAndForget: shouldFireAndForget
|
|
165
|
+
});
|
|
166
|
+
}
|
|
102
167
|
async sendEvent(path, param, param1) {
|
|
103
168
|
let { params, body } = param;
|
|
104
169
|
let { fireAndForget = false } = param1 === void 0 ? {} : param1;
|
|
@@ -145,12 +210,42 @@ class ServerLogger {
|
|
|
145
210
|
writable: true,
|
|
146
211
|
value: void 0
|
|
147
212
|
});
|
|
213
|
+
Object.defineProperty(this, _batchQueue, {
|
|
214
|
+
writable: true,
|
|
215
|
+
value: void 0
|
|
216
|
+
});
|
|
217
|
+
Object.defineProperty(this, _flushTimerId, {
|
|
218
|
+
writable: true,
|
|
219
|
+
value: void 0
|
|
220
|
+
});
|
|
221
|
+
_class_private_field_loose_base(this, _batchQueue)[_batchQueue] = [];
|
|
222
|
+
_class_private_field_loose_base(this, _flushTimerId)[_flushTimerId] = null;
|
|
223
|
+
this.handlePagehide = ()=>{
|
|
224
|
+
this.flushBatch({
|
|
225
|
+
fireAndForget: true
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
this.handleVisibilityChange = ()=>{
|
|
229
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
230
|
+
this.flushBatch({
|
|
231
|
+
fireAndForget: true
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
};
|
|
148
235
|
_class_private_field_loose_base(this, _config)[_config] = config;
|
|
149
236
|
_class_private_field_loose_base(this, _widgetId)[_widgetId] = undefined;
|
|
150
237
|
_class_private_field_loose_base(this, _visitorId)[_visitorId] = undefined;
|
|
238
|
+
if (typeof window !== "undefined") {
|
|
239
|
+
__nativeWindowAddEventListener("pagehide", this.handlePagehide);
|
|
240
|
+
}
|
|
241
|
+
if (typeof document !== "undefined") {
|
|
242
|
+
__nativeDocumentAddEventListener("visibilitychange", this.handleVisibilityChange);
|
|
243
|
+
}
|
|
151
244
|
}
|
|
152
245
|
}
|
|
153
246
|
const serverLogger = new ServerLogger({});
|
|
154
247
|
|
|
155
248
|
var server_logger_ServerLogger = /* unused export */ undefined;
|
|
156
|
-
|
|
249
|
+
var server_logger_VISITOR_EVENTS_BATCH_FLUSH_INTERVAL_MS = /* unused export */ undefined;
|
|
250
|
+
var server_logger_VISITOR_EVENTS_BATCH_SIZE_LIMIT = /* unused export */ undefined;
|
|
251
|
+
export { serverLogger, server_logger_ServerLogger as ServerLogger, server_logger_VISITOR_EVENTS_BATCH_FLUSH_INTERVAL_MS as VISITOR_EVENTS_BATCH_FLUSH_INTERVAL_MS, server_logger_VISITOR_EVENTS_BATCH_SIZE_LIMIT as VISITOR_EVENTS_BATCH_SIZE_LIMIT };
|
package/widget/tracker.js
CHANGED
|
@@ -7,6 +7,7 @@ import { BUTTON_LIKE_SELECTOR, isWithinQualifiedElement } from "../src/smart_web
|
|
|
7
7
|
import { fromBase64 } from "../src/string.js";
|
|
8
8
|
import { every, after } from "../src/timing.js";
|
|
9
9
|
import { default as WidgetObject } from "./widget_object.js";
|
|
10
|
+
import { isCapabilityAllowed } from "./capabilities.js";
|
|
10
11
|
import { captureWidgetExceptions } from "./capture_widget_exceptions.js";
|
|
11
12
|
import { isSafariUserAgent } from "./constants.js";
|
|
12
13
|
import { default as data360_visitor } from "./data360_visitor.js";
|
|
@@ -53,6 +54,7 @@ var throttle_default = /*#__PURE__*/__webpack_require__.n(throttle);
|
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
const events = [
|
|
@@ -111,7 +113,12 @@ class Tracker extends WidgetObject {
|
|
|
111
113
|
if (this.isDisposed) {
|
|
112
114
|
return;
|
|
113
115
|
}
|
|
114
|
-
|
|
116
|
+
// QAI-5896: marketing-automation visitor-identity capture (Marketo/HubSpot/Data360/Eloqua)
|
|
117
|
+
// reads a local marketing cookie/global and forwards the token to Qualified. The `has*` flags
|
|
118
|
+
// are stripped by `filterRuntimeConfig` when `marketingIdentity` is denied; this `isCapability
|
|
119
|
+
// Allowed` guard is the client-side backstop, so the capture never runs even if a flag reaches
|
|
120
|
+
// the widget by an unfiltered path. Allow-all for the hosted widget (no boundary installed).
|
|
121
|
+
if (this.config.hasMarketo && isCapabilityAllowed("marketingIdentity")) {
|
|
115
122
|
await telemetry.startActiveSpanAsync("Init marketo", {}, this.telemetryCtx, async (span)=>{
|
|
116
123
|
const marketoToken = await new marketo_visitor().getToken();
|
|
117
124
|
if (marketoToken !== undefined) {
|
|
@@ -127,7 +134,7 @@ class Tracker extends WidgetObject {
|
|
|
127
134
|
if (this.isDisposed) {
|
|
128
135
|
return;
|
|
129
136
|
}
|
|
130
|
-
if (this.config.hasHubSpot) {
|
|
137
|
+
if (this.config.hasHubSpot && isCapabilityAllowed("marketingIdentity")) {
|
|
131
138
|
await telemetry.startActiveSpanAsync("Init hubspot", {}, this.telemetryCtx, async (span)=>{
|
|
132
139
|
const hubspotToken = await new hubspot_visitor().getToken(this.widget.config.hubspotTokenRetrievalTimeout);
|
|
133
140
|
if (hubspotToken !== undefined) {
|
|
@@ -143,7 +150,7 @@ class Tracker extends WidgetObject {
|
|
|
143
150
|
if (this.isDisposed) {
|
|
144
151
|
return;
|
|
145
152
|
}
|
|
146
|
-
if (this.config.hasData360) {
|
|
153
|
+
if (this.config.hasData360 && isCapabilityAllowed("marketingIdentity")) {
|
|
147
154
|
await telemetry.startActiveSpanAsync("Init data360", {}, this.telemetryCtx, async (span)=>{
|
|
148
155
|
const deviceId = await new data360_visitor().getDeviceId();
|
|
149
156
|
if (deviceId !== undefined) {
|
|
@@ -159,7 +166,7 @@ class Tracker extends WidgetObject {
|
|
|
159
166
|
if (this.isDisposed) {
|
|
160
167
|
return;
|
|
161
168
|
}
|
|
162
|
-
if (this.config.hasEloqua) {
|
|
169
|
+
if (this.config.hasEloqua && isCapabilityAllowed("marketingIdentity")) {
|
|
163
170
|
await telemetry.startActiveSpanAsync("Init eloqua", {}, this.telemetryCtx, async (span)=>{
|
|
164
171
|
const eloquaToken = new eloqua_visitor().getToken();
|
|
165
172
|
if (eloquaToken !== undefined) {
|
|
@@ -176,7 +183,12 @@ class Tracker extends WidgetObject {
|
|
|
176
183
|
return;
|
|
177
184
|
}
|
|
178
185
|
if (this.visitor.smartFormData) {
|
|
179
|
-
|
|
186
|
+
// QAI-5896: the smart-form replay egresses captured form-field values, so it belongs behind
|
|
187
|
+
// formCapture too — a client backstop to the config-strip of `hasSmartForms`, for the case a
|
|
188
|
+
// flag reaches the widget by an unfiltered path. `clearSmartFormData()` still runs when denied
|
|
189
|
+
// so a stashed submit can't leak on a later navigation.
|
|
190
|
+
const formCaptureAllowed = isCapabilityAllowed("formCapture");
|
|
191
|
+
if (formCaptureAllowed && this.config.hasSmartForms) {
|
|
180
192
|
this.experienceAdapter.showLightboxLoading();
|
|
181
193
|
// Pre-offer SLI: a submit saved by `saveSmartFormData` before this page
|
|
182
194
|
// context existed, replayed at init. Unlike the api_handler path this IS
|
|
@@ -192,12 +204,14 @@ class Tracker extends WidgetObject {
|
|
|
192
204
|
armFormCtaBookerIntent("form:smart_form", this.visitor.smartFormData.botApiName);
|
|
193
205
|
}
|
|
194
206
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
if (formCaptureAllowed) {
|
|
208
|
+
this.setInitializationParams({
|
|
209
|
+
smart_form: {
|
|
210
|
+
field_values: this.visitor.smartFormData.fieldValues,
|
|
211
|
+
bot_api_name: this.visitor.smartFormData.botApiName
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
201
215
|
this.visitor.clearSmartFormData();
|
|
202
216
|
}
|
|
203
217
|
if (!this.widget.isMeetingLink) {
|
|
@@ -534,11 +548,22 @@ class Tracker extends WidgetObject {
|
|
|
534
548
|
if (!this.config.hasSmartForms) return;
|
|
535
549
|
const validBotApiName = botApiName || ((_this_widget_visitor_smartFormData = this.widget.visitor.smartFormData) == null ? void 0 : _this_widget_visitor_smartFormData.botApiName);
|
|
536
550
|
const validFieldValues = ((_this_widget_visitor_formData = this.widget.visitor.formData) == null ? void 0 : _this_widget_visitor_formData.fieldValues) || ((_this_widget_visitor_smartFormData1 = this.widget.visitor.smartFormData) == null ? void 0 : _this_widget_visitor_smartFormData1.fieldValues);
|
|
551
|
+
// Minted and registered here, immediately before the request that carries it,
|
|
552
|
+
// so every registered id is guaranteed to actually round-trip (CORE-3488).
|
|
553
|
+
// Registering any earlier (e.g. at the caller's showLightboxLoading site)
|
|
554
|
+
// would leak the id if this method bails out above on `!hasSmartForms`.
|
|
555
|
+
const formTransactionId = esm_browser_v4();
|
|
556
|
+
try {
|
|
557
|
+
this.widget.iframeManager.registerLoadingRequest(formTransactionId);
|
|
558
|
+
} catch (unused) {
|
|
559
|
+
// V2 path: IframeManager not registered, safe to ignore
|
|
560
|
+
}
|
|
537
561
|
this.channel.perform("show_form_experience", {
|
|
538
562
|
bot_api_name: validBotApiName,
|
|
539
563
|
field_values: validFieldValues,
|
|
540
564
|
form_data: this.widget.visitor.formData,
|
|
541
|
-
form_destinations: formDestinations
|
|
565
|
+
form_destinations: formDestinations,
|
|
566
|
+
form_transaction_id: formTransactionId
|
|
542
567
|
});
|
|
543
568
|
this.widget.visitor.clearSmartFormData();
|
|
544
569
|
this.widget.visitor.clearFormData();
|
|
@@ -585,6 +610,15 @@ class Tracker extends WidgetObject {
|
|
|
585
610
|
armFormCtaBookerIntent("form:" + formType);
|
|
586
611
|
}
|
|
587
612
|
this.experienceAdapter.showLightboxLoading();
|
|
613
|
+
// Minted and registered here, immediately before the request that carries
|
|
614
|
+
// it, so every registered id is guaranteed to actually round-trip
|
|
615
|
+
// (CORE-3488).
|
|
616
|
+
const formTransactionId = esm_browser_v4();
|
|
617
|
+
try {
|
|
618
|
+
this.widget.iframeManager.registerLoadingRequest(formTransactionId);
|
|
619
|
+
} catch (unused) {
|
|
620
|
+
// V2 path: IframeManager not registered, safe to ignore
|
|
621
|
+
}
|
|
588
622
|
this.channel.perform("show_experience_for_form", {
|
|
589
623
|
form_type: formType,
|
|
590
624
|
form_data: {
|
|
@@ -592,7 +626,8 @@ class Tracker extends WidgetObject {
|
|
|
592
626
|
form_id: formData.formId,
|
|
593
627
|
form_email: formData.formEmail,
|
|
594
628
|
form_action_url: (_formData_formActionUrl1 = formData.formActionUrl) == null ? void 0 : _formData_formActionUrl1.replace(/^https?:\/\//, "")
|
|
595
|
-
}
|
|
629
|
+
},
|
|
630
|
+
form_transaction_id: formTransactionId
|
|
596
631
|
});
|
|
597
632
|
}
|
|
598
633
|
this.widget.debugState.logEvent("tracker:showExperienceForForm", "success", {});
|
|
@@ -640,7 +675,6 @@ class Tracker extends WidgetObject {
|
|
|
640
675
|
});
|
|
641
676
|
}, // TODO: remove once meeting link has its own pack
|
|
642
677
|
this.recordMeetingLinkLoad = (token)=>{
|
|
643
|
-
if (token === void 0) token = undefined;
|
|
644
678
|
const data = Object.assign({}, this.initializationParams, {
|
|
645
679
|
wu: this.widget.widgetId,
|
|
646
680
|
url: document.location.href,
|
|
@@ -779,14 +813,28 @@ class Tracker extends WidgetObject {
|
|
|
779
813
|
this.visitor.setQualifiedRedirect(true);
|
|
780
814
|
this.isBotRedirecting = true;
|
|
781
815
|
}, // @ts-expect-error property decorator typing
|
|
782
|
-
this.onEndLoadingState = ()=>{
|
|
783
|
-
|
|
784
|
-
//
|
|
785
|
-
//
|
|
786
|
-
|
|
787
|
-
|
|
816
|
+
this.onEndLoadingState = (payload)=>{
|
|
817
|
+
// Withhold the overlay teardown -- but not the fallback dispatch below -- when
|
|
818
|
+
// this answers for one outstanding request while another is still waiting
|
|
819
|
+
// (CORE-3488). Only the v1 iframe path tracks outstanding ids; v2 has nothing
|
|
820
|
+
// to withhold against, so it always tears down.
|
|
821
|
+
let shouldTeardown = true;
|
|
822
|
+
try {
|
|
823
|
+
shouldTeardown = this.widget.iframeManager.releaseLoadingRequest(payload == null ? void 0 : payload.formTransactionId);
|
|
824
|
+
} catch (unused) {
|
|
825
|
+
// V2 path: IframeManager not registered, safe to ignore
|
|
826
|
+
}
|
|
827
|
+
if (shouldTeardown) {
|
|
828
|
+
var // Clear any active loading overlay in the v2 adapter path.
|
|
829
|
+
// In v1, the iframe handles this via postMessage; v2 needs an explicit signal write.
|
|
830
|
+
// Guard: experienceAdapter may not be initialized yet if the channel fires before Widget.init() completes.
|
|
831
|
+
_this_experienceAdapter;
|
|
832
|
+
(_this_experienceAdapter = this.experienceAdapter) == null ? void 0 : _this_experienceAdapter.closeLightbox();
|
|
833
|
+
}
|
|
788
834
|
// This fallback is called if we should trigger the default behavior of the last button click
|
|
789
|
-
// i.e if the button click was hijacked but the visitor was disqualified
|
|
835
|
+
// i.e if the button click was hijacked but the visitor was disqualified. Not gated on
|
|
836
|
+
// shouldTeardown: it answers a different question (was this click's own bot a dead end?)
|
|
837
|
+
// than the outstanding-request gate above (is some OTHER request still waiting?).
|
|
790
838
|
this.lastButtonTriggerEvent && this.dispatchFallbackEvent(this.lastButtonTriggerEvent);
|
|
791
839
|
}, this.getRedirectCount = ()=>{
|
|
792
840
|
var _performance_getEntriesByType;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { isCapabilityAllowed } from "../capabilities.js";
|
|
1
2
|
import { default as PageMirror } from "../page_mirror.js";
|
|
2
3
|
import { default as WidgetObject } from "../widget_object.js";
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
|
|
6
8
|
class PageMirrorFactory extends WidgetObject {
|
|
7
9
|
create() {
|
|
8
|
-
|
|
10
|
+
// QAI-5864: skip DOM serialization/mirroring unless the consumer allowed the "liveView"
|
|
11
|
+
// capability. Live View has no positive config enabler (it is on unless `disableLiveView` is
|
|
12
|
+
// set) and its stream arrives on a separate cable subscription that bypasses the message,
|
|
13
|
+
// command, and config enforcement points — so this client-side guard is the only thing that
|
|
14
|
+
// stops the mirror for an enrolled npm consumer. Allow-all for the hosted widget (no boundary
|
|
15
|
+
// installed); default-deny once an npm consumer enrols via setup().
|
|
16
|
+
if (!this.widget.config.isComplete || this.widget.config.disableLiveView || !isCapabilityAllowed("liveView")) {
|
|
9
17
|
return this.container.resolve("emptyPageMirror");
|
|
10
18
|
} else {
|
|
11
19
|
return this.container.resolve("pageMirror", this.widget.config.denylistedVisitorStreamDomains || []);
|
package/widget/widget/widget.js
CHANGED
|
@@ -6,6 +6,7 @@ import { isDomainMatch, isIframed } from "../../src/iframes.js";
|
|
|
6
6
|
import { delay as timing_delay } from "../../src/timing.js";
|
|
7
7
|
import { normalizeURL, hasURLMatch } from "../../src/url-utils.js";
|
|
8
8
|
import { default as ApiHandler } from "../api_handler/api_handler.js";
|
|
9
|
+
import { isCapabilityAllowed } from "../capabilities.js";
|
|
9
10
|
import { captureWidgetExceptions } from "../capture_widget_exceptions.js";
|
|
10
11
|
import { default as channel } from "../channel.js";
|
|
11
12
|
import { default as Container } from "../container.js";
|
|
@@ -91,6 +92,7 @@ var cloneDeep_default = /*#__PURE__*/__webpack_require__.n(cloneDeep);
|
|
|
91
92
|
|
|
92
93
|
|
|
93
94
|
|
|
95
|
+
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
const LOOPBACK_HOSTS = new Set([
|
|
@@ -114,7 +116,10 @@ function isLoopbackHost(host) {
|
|
|
114
116
|
return host.includes("localhost");
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
|
-
|
|
119
|
+
// Presentation layer for a surface that never shows the messenger: every verb is
|
|
120
|
+
// a no-op and every counter is at rest. `MeetingLinkWidget` uses it; the base
|
|
121
|
+
// `V1Adapter` would dereference a missing iframe manager on the first verb.
|
|
122
|
+
class NoopExperienceAdapter {
|
|
118
123
|
dispose() {}
|
|
119
124
|
showLightboxLoading() {}
|
|
120
125
|
showMessengerLoading() {}
|
|
@@ -348,6 +353,10 @@ class Widget extends Injectable(Disposable(Object)) {
|
|
|
348
353
|
}
|
|
349
354
|
this.config = _extends({}, this.config, config);
|
|
350
355
|
this.config.requiresCookieConsent = this.config.hasCookieConsent !== undefined;
|
|
356
|
+
// The earlier setConfig() call (above, before this async gap) captured a config
|
|
357
|
+
// snapshot that predates this merge, so featureFlags (only present on the merged
|
|
358
|
+
// config, not the bootstrap-time envConfig) never reached serverLogger without this.
|
|
359
|
+
serverLogger.setConfig(this.config);
|
|
351
360
|
if (this.isIframed && !this.bootstrapsWhenIframed()) {
|
|
352
361
|
this.messengerUptime.dispose();
|
|
353
362
|
const iframeApiHandler = this.apiHandler;
|
|
@@ -516,7 +525,10 @@ class Widget extends Injectable(Disposable(Object)) {
|
|
|
516
525
|
error
|
|
517
526
|
});
|
|
518
527
|
}
|
|
519
|
-
|
|
528
|
+
// QAI-5864: registering the `<qualified-form>` embedded-form element wires its own submit
|
|
529
|
+
// listener that egresses via `channel.send` (bypassing the command-layer gate), so guard the
|
|
530
|
+
// registration on the "formCapture" capability too. Allow-all for the hosted widget.
|
|
531
|
+
if (isCapabilityAllowed("formCapture") && this.tracker.config.hasWebsiteEmbeddedForms) {
|
|
520
532
|
this.initQualifiedForms();
|
|
521
533
|
}
|
|
522
534
|
this.exposeDebugging();
|
|
@@ -802,7 +814,13 @@ class Widget extends Injectable(Disposable(Object)) {
|
|
|
802
814
|
// TODO: remove once meeting link has its own pack
|
|
803
815
|
get meetingLinkToken() {
|
|
804
816
|
if (!this.isMeetingLink) return;
|
|
805
|
-
|
|
817
|
+
// Strip trailing slashes as well as the leading one. Customer CMSes often
|
|
818
|
+
// emit the link as `https://schedule.qualified.com/mA7n1gd/`; Rails ignores
|
|
819
|
+
// the trailing slash when routing the page, but `pathname` keeps it, so the
|
|
820
|
+
// token sent with `record_meeting_link_load` became `mA7n1gd/`. The server
|
|
821
|
+
// cannot resolve that and broadcasts an empty conversation, leaving the
|
|
822
|
+
// visitor on the spinner until the watchdog fires (CORE-3725).
|
|
823
|
+
const pathParts = window.location.pathname.replace(/^\/+|\/+$/g, "").split("-");
|
|
806
824
|
return pathParts[pathParts.length - 1];
|
|
807
825
|
}
|
|
808
826
|
get connectionParams() {
|
|
@@ -910,6 +928,12 @@ class Widget extends Injectable(Disposable(Object)) {
|
|
|
910
928
|
}
|
|
911
929
|
initFormExperience() {
|
|
912
930
|
var _this_config_featureFlags;
|
|
931
|
+
// QAI-5864: don't arm the auto-armed third-party form listeners (Marketo / HubSpot) unless the
|
|
932
|
+
// consumer allowed the "formCapture" capability. These listeners are not driven by a public
|
|
933
|
+
// command verb, so the command-layer gate never sees them — only the `hasSmartForms` config key
|
|
934
|
+
// (which the runtime-config filter strips when denied) and this guard protect them. Allow-all
|
|
935
|
+
// for the hosted widget (no boundary installed); default-deny once an npm consumer enrols.
|
|
936
|
+
if (!isCapabilityAllowed("formCapture")) return;
|
|
913
937
|
if (!this.tracker.config.hasSmartForms) {
|
|
914
938
|
this.debugState.logEvent("widget:hasSmartForms", "error");
|
|
915
939
|
return;
|
|
@@ -1694,5 +1718,6 @@ __decorate([
|
|
|
1694
1718
|
], Widget.prototype, "trackVisitedContentActivity", null);
|
|
1695
1719
|
|
|
1696
1720
|
var widget_FormStorageKey = /* unused export */ undefined;
|
|
1697
|
-
|
|
1721
|
+
var widget_NoopExperienceAdapter = /* unused export */ undefined;
|
|
1722
|
+
export { widget_FormStorageKey as FormStorageKey, widget_NoopExperienceAdapter as NoopExperienceAdapter };
|
|
1698
1723
|
export default Widget;
|