@morgan-and-morgan/intake-agent 1.0.0-alpha.4 → 1.0.0-alpha.5

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.
@@ -11,6 +11,92 @@
11
11
  chatUrl
12
12
  };
13
13
  };
14
+ const ATTRIBUTION_FIELD_MAX_LENGTH = {
15
+ tracked_landing_page: 4096,
16
+ tracked_landing_timestamp: 255,
17
+ conversion_page: 255,
18
+ ga_client_id: 255,
19
+ gclid_value: 255,
20
+ marketing_source: 255,
21
+ marketing_sub_source: 255
22
+ };
23
+ const ATTRIBUTION_FIELDS = Object.keys(ATTRIBUTION_FIELD_MAX_LENGTH);
24
+ const sanitizeIntakeChatAttribution = (value) => {
25
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
26
+ return null;
27
+ }
28
+ const record = value;
29
+ const sanitized = {};
30
+ for (const field of ATTRIBUTION_FIELDS) {
31
+ const fieldValue = record[field];
32
+ const trimmed = typeof fieldValue === "string" ? fieldValue.trim() : "";
33
+ if (trimmed !== "") {
34
+ sanitized[field] = trimmed.slice(0, ATTRIBUTION_FIELD_MAX_LENGTH[field]);
35
+ }
36
+ }
37
+ return Object.keys(sanitized).length === 0 ? null : sanitized;
38
+ };
39
+ const LANDING_PAGE_COOKIE = "tracked_landing_page";
40
+ const LANDING_TIMESTAMP_COOKIE = "tracked_landing_timestamp";
41
+ const readTimestampCookie = (cookie) => {
42
+ const raw = readCookie(cookie, LANDING_TIMESTAMP_COOKIE);
43
+ return raw === void 0 ? void 0 : decodeCookieValue(raw);
44
+ };
45
+ const readCookie = (cookie, name) => {
46
+ var _a;
47
+ const raw = (_a = cookie.split(";").map((entry) => entry.trim()).find((entry) => entry.startsWith(`${name}=`))) == null ? void 0 : _a.slice(name.length + 1);
48
+ return raw === void 0 || raw === "" ? void 0 : raw;
49
+ };
50
+ const decodeCookieValue = (raw) => {
51
+ try {
52
+ return decodeURIComponent(raw);
53
+ } catch {
54
+ return raw;
55
+ }
56
+ };
57
+ const parseUrl = (value) => {
58
+ try {
59
+ return new URL(value);
60
+ } catch {
61
+ return null;
62
+ }
63
+ };
64
+ const readLandingPage = (cookie) => {
65
+ const raw = readCookie(cookie, LANDING_PAGE_COOKIE);
66
+ if (raw === void 0 || parseUrl(raw) !== null) {
67
+ return raw;
68
+ }
69
+ const decoded = decodeCookieValue(raw);
70
+ return parseUrl(decoded) === null ? raw : decoded;
71
+ };
72
+ const readGaClientId = (cookie) => {
73
+ const raw = readCookie(cookie, "_ga");
74
+ if (raw === void 0) {
75
+ return void 0;
76
+ }
77
+ const value = decodeCookieValue(raw);
78
+ const parts = value.split(".");
79
+ return parts.length >= 4 ? parts.slice(-2).join(".") : value;
80
+ };
81
+ const readGclid = (landingUrl) => {
82
+ var _a, _b;
83
+ return landingUrl === void 0 ? void 0 : (_b = (_a = parseUrl(landingUrl)) == null ? void 0 : _a.searchParams.get("gclid")) != null ? _b : void 0;
84
+ };
85
+ const readPathname = (url) => {
86
+ var _a;
87
+ return (_a = parseUrl(url)) == null ? void 0 : _a.pathname;
88
+ };
89
+ const buildHostAttribution = (currentUrl = globalThis.location.href, cookie = document.cookie) => {
90
+ var _a;
91
+ const landingPage = readLandingPage(cookie);
92
+ return (_a = sanitizeIntakeChatAttribution({
93
+ tracked_landing_page: landingPage,
94
+ tracked_landing_timestamp: readTimestampCookie(cookie),
95
+ conversion_page: readPathname(currentUrl),
96
+ ga_client_id: readGaClientId(cookie),
97
+ gclid_value: readGclid(landingPage)
98
+ })) != null ? _a : {};
99
+ };
14
100
  const OPEN_STATE_KEY = "mm-intake-widget-open";
15
101
  const readOpenState = (storage = sessionStorage) => {
16
102
  try {
@@ -241,6 +327,12 @@
241
327
  const hostUrl = buildSigningReturnUrl(currentUrl);
242
328
  postToChat(
243
329
  createEmbedProtocolMessage(EMBED_MESSAGE_TYPE.HOST_READY, {
330
+ // Marketing attribution (MX2-25162): the marketing site's first-touch
331
+ // cookies and the page the chat opened on are only visible from this
332
+ // page, never from the cross-origin chat frame. The chat forwards them
333
+ // on its first /chat turn and Salesforce builds the intake's
334
+ // Marketing_Tracking_Info__c record from them.
335
+ attribution: buildHostAttribution(),
244
336
  ...hostUrl === null ? {} : { hostUrl },
245
337
  ...completedEnvelopeId === null ? {} : { completedEnvelopeId },
246
338
  // Sent even without an envelope id: the Salesforce service is what
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morgan-and-morgan/intake-agent",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-alpha.5",
4
4
  "description": "Embeddable chat widget loader.",
5
5
  "license": "UNLICENSED",
6
6
  "files": [
@@ -11,6 +11,7 @@
11
11
  "exports": {
12
12
  ".": "./dist/mm-intake-widget.js",
13
13
  "./widget": "./src/widget.ts",
14
+ "./attribution": "./src/attribution.ts",
14
15
  "./protocol": "./src/protocol.ts",
15
16
  "./signing": "./src/signing.ts",
16
17
  "./loader-config": "./src/loader-config.ts"