@hellotext/hellotext 2.4.51 → 2.4.53

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/lib/api/acks.cjs CHANGED
@@ -23,8 +23,9 @@ let AcksAPI = /*#__PURE__*/function () {
23
23
  }
24
24
  }, {
25
25
  key: "send",
26
- value: async function send() {
26
+ value: async function send(params = {}) {
27
27
  const payload = {
28
+ ...params,
28
29
  session: _hellotext.default.session,
29
30
  at: new Date().toISOString()
30
31
  };
package/lib/api/acks.js CHANGED
@@ -1,3 +1,6 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
3
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1
4
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
2
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
3
6
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -20,10 +23,11 @@ var AcksAPI = /*#__PURE__*/function () {
20
23
  key: "send",
21
24
  value: function () {
22
25
  var _send = _asyncToGenerator(function* () {
23
- var payload = {
26
+ var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
27
+ var payload = _objectSpread(_objectSpread({}, params), {}, {
24
28
  session: Hellotext.session,
25
29
  at: new Date().toISOString()
26
- };
30
+ });
27
31
  fetch(this.endpoint, {
28
32
  method: 'POST',
29
33
  headers: Hellotext.headers,
@@ -25,18 +25,28 @@ let EventsAPI = /*#__PURE__*/function () {
25
25
  key: "create",
26
26
  value: async function create({
27
27
  headers,
28
- body
28
+ body,
29
+ keepalive = false
29
30
  }) {
30
31
  if (_models.Query.inPreviewMode) {
31
32
  return new _response.Response(true, {
32
33
  received: true
33
34
  });
34
35
  }
35
- const response = await fetch(this.endpoint, {
36
+ const fetchOptions = {
36
37
  method: 'POST',
37
38
  headers,
38
39
  body: JSON.stringify(body)
39
- });
40
+ };
41
+
42
+ // Do not send `keepalive: false`. The track caller opts in only for payloads
43
+ // that fit the browser keepalive budget; omitting the key for larger events
44
+ // preserves normal fetch behavior for rich carts/orders instead of asking
45
+ // the browser to use an unload-safe transport it may reject.
46
+ if (keepalive) {
47
+ fetchOptions.keepalive = true;
48
+ }
49
+ const response = await fetch(this.endpoint, fetchOptions);
40
50
  return new _response.Response(response.status === 200, await response.json());
41
51
  }
42
52
  }]);
package/lib/api/events.js CHANGED
@@ -23,18 +23,28 @@ var EventsAPI = /*#__PURE__*/function () {
23
23
  var _create = _asyncToGenerator(function* (_ref) {
24
24
  var {
25
25
  headers,
26
- body
26
+ body,
27
+ keepalive = false
27
28
  } = _ref;
28
29
  if (Query.inPreviewMode) {
29
30
  return new Response(true, {
30
31
  received: true
31
32
  });
32
33
  }
33
- var response = yield fetch(this.endpoint, {
34
+ var fetchOptions = {
34
35
  method: 'POST',
35
36
  headers,
36
37
  body: JSON.stringify(body)
37
- });
38
+ };
39
+
40
+ // Do not send `keepalive: false`. The track caller opts in only for payloads
41
+ // that fit the browser keepalive budget; omitting the key for larger events
42
+ // preserves normal fetch behavior for rich carts/orders instead of asking
43
+ // the browser to use an unload-safe transport it may reject.
44
+ if (keepalive) {
45
+ fetchOptions.keepalive = true;
46
+ }
47
+ var response = yield fetch(this.endpoint, fetchOptions);
38
48
  return new Response(response.status === 200, yield response.json());
39
49
  });
40
50
  function create(_x) {
package/lib/api/index.cjs CHANGED
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "Response", {
10
10
  }
11
11
  });
12
12
  exports.default = void 0;
13
+ exports.keepaliveFor = keepaliveFor;
13
14
  var _businesses = _interopRequireDefault(require("./businesses"));
14
15
  var _events = _interopRequireDefault(require("./events"));
15
16
  var _forms = _interopRequireDefault(require("./forms"));
@@ -23,6 +24,26 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
23
24
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
24
25
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
25
26
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
27
+ // Browsers keep `fetch(..., { keepalive: true })` requests alive during page
28
+ // unload/navigation, which is exactly the failure mode for analytics events
29
+ // fired from checkout redirects, form submissions, tab closes, and pixel
30
+ // lifecycles. The platform also caps keepalive request bodies around 64KB, and
31
+ // browsers can reject or drop oversized requests instead of making delivery
32
+ // more reliable. Keep the limit below that ceiling so the SDK only opts in when
33
+ // the payload is small enough for the keepalive transport contract.
34
+ const KEEPALIVE_BODY_LIMIT = 60000;
35
+ function keepaliveFor(body) {
36
+ const serializedBody = JSON.stringify(body);
37
+
38
+ // Use byte size when the runtime exposes Blob because non-ASCII JSON can be
39
+ // larger on the wire than its JavaScript string length. The string-length
40
+ // fallback keeps older/non-browser runtimes conservative without pulling in
41
+ // another encoder just for this transport hint.
42
+ if (typeof Blob === 'undefined') {
43
+ return serializedBody.length < KEEPALIVE_BODY_LIMIT;
44
+ }
45
+ return new Blob([serializedBody]).size < KEEPALIVE_BODY_LIMIT;
46
+ }
26
47
  let API = /*#__PURE__*/function () {
27
48
  function API() {
28
49
  _classCallCheck(this, API);
package/lib/api/index.js CHANGED
@@ -9,6 +9,27 @@ import FormsAPI from './forms';
9
9
  import IdentificationsAPI from './identifications';
10
10
  import WebchatsAPI from './webchats';
11
11
  import AcksAPI from './acks';
12
+
13
+ // Browsers keep `fetch(..., { keepalive: true })` requests alive during page
14
+ // unload/navigation, which is exactly the failure mode for analytics events
15
+ // fired from checkout redirects, form submissions, tab closes, and pixel
16
+ // lifecycles. The platform also caps keepalive request bodies around 64KB, and
17
+ // browsers can reject or drop oversized requests instead of making delivery
18
+ // more reliable. Keep the limit below that ceiling so the SDK only opts in when
19
+ // the payload is small enough for the keepalive transport contract.
20
+ var KEEPALIVE_BODY_LIMIT = 60000;
21
+ function keepaliveFor(body) {
22
+ var serializedBody = JSON.stringify(body);
23
+
24
+ // Use byte size when the runtime exposes Blob because non-ASCII JSON can be
25
+ // larger on the wire than its JavaScript string length. The string-length
26
+ // fallback keeps older/non-browser runtimes conservative without pulling in
27
+ // another encoder just for this transport hint.
28
+ if (typeof Blob === 'undefined') {
29
+ return serializedBody.length < KEEPALIVE_BODY_LIMIT;
30
+ }
31
+ return new Blob([serializedBody]).size < KEEPALIVE_BODY_LIMIT;
32
+ }
12
33
  var API = /*#__PURE__*/function () {
13
34
  function API() {
14
35
  _classCallCheck(this, API);
@@ -47,4 +68,5 @@ var API = /*#__PURE__*/function () {
47
68
  return API;
48
69
  }();
49
70
  export { API as default };
50
- export { Response } from './response';
71
+ export { Response } from './response';
72
+ export { keepaliveFor };
package/lib/hellotext.cjs CHANGED
@@ -29,9 +29,9 @@ let Hellotext = /*#__PURE__*/function () {
29
29
  */
30
30
  async function initialize(business, config = {}) {
31
31
  this.business = new _models.Business(business);
32
- _core.Configuration.assign(config);
33
- _models.Session.initialize();
34
32
  this.page = new _models.Page();
33
+ _core.Configuration.assign(config);
34
+ _models.Session.initialize(this.page);
35
35
  this.forms = new _models.FormCollection();
36
36
  this.query = new _models.Query();
37
37
  const businessData = await this.business.hydrate();
@@ -104,7 +104,12 @@ let Hellotext = /*#__PURE__*/function () {
104
104
  delete body.headers;
105
105
  return await _api.default.events.create({
106
106
  headers,
107
- body
107
+ body,
108
+ // Track is the SDK's unload-sensitive analytics path. Keepalive belongs
109
+ // here rather than on identify/forms/webchat calls because event tracking
110
+ // is allowed to be fire-and-navigate, while those other calls have
111
+ // stronger request/response or interaction contracts.
112
+ keepalive: (0, _api.keepaliveFor)(body)
108
113
  });
109
114
  }
110
115
 
package/lib/hellotext.js CHANGED
@@ -9,7 +9,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
9
9
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
10
10
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
11
11
  import { Configuration, Event } from './core';
12
- import API, { Response } from './api';
12
+ import API, { Response, keepaliveFor } from './api';
13
13
  import { Business, Fingerprint, FormCollection, Page, Query, Session, User, Webchat } from './models';
14
14
  import { NotInitializedError } from './errors';
15
15
  var Hellotext = /*#__PURE__*/function () {
@@ -28,9 +28,9 @@ var Hellotext = /*#__PURE__*/function () {
28
28
  var _initialize = _asyncToGenerator(function* (business) {
29
29
  var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
30
30
  this.business = new Business(business);
31
- Configuration.assign(config);
32
- Session.initialize();
33
31
  this.page = new Page();
32
+ Configuration.assign(config);
33
+ Session.initialize(this.page);
34
34
  this.forms = new FormCollection();
35
35
  this.query = new Query();
36
36
  var businessData = yield this.business.hydrate();
@@ -101,7 +101,12 @@ var Hellotext = /*#__PURE__*/function () {
101
101
  delete body.headers;
102
102
  return yield API.events.create({
103
103
  headers,
104
- body
104
+ body,
105
+ // Track is the SDK's unload-sensitive analytics path. Keepalive belongs
106
+ // here rather than on identify/forms/webchat calls because event tracking
107
+ // is allowed to be fire-and-navigate, while those other calls have
108
+ // stronger request/response or interaction contracts.
109
+ keepalive: keepaliveFor(body)
105
110
  });
106
111
  });
107
112
  function track(_x2) {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.Session = void 0;
7
7
  var _core = require("../core");
8
8
  var _cookies = require("./cookies");
9
+ var _page2 = require("./page");
9
10
  var _query2 = require("./query");
10
11
  var _api = _interopRequireDefault(require("../api"));
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -19,6 +20,7 @@ var id = 0;
19
20
  function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
20
21
  var _session = /*#__PURE__*/_classPrivateFieldLooseKey("session");
21
22
  var _query = /*#__PURE__*/_classPrivateFieldLooseKey("query");
23
+ var _page = /*#__PURE__*/_classPrivateFieldLooseKey("page");
22
24
  let Session = /*#__PURE__*/function () {
23
25
  function Session() {
24
26
  _classCallCheck(this, Session);
@@ -36,14 +38,23 @@ let Session = /*#__PURE__*/function () {
36
38
  _cookies.Cookies.delete('hello_session_ack_at');
37
39
  }
38
40
  if (!_cookies.Cookies.get('hello_session_ack_at')) {
39
- _api.default.acks.send();
41
+ _api.default.acks.send(this.ackPayload);
40
42
  _cookies.Cookies.set('hello_session_ack_at', new Date().toISOString());
41
43
  }
42
44
  return _classPrivateFieldLooseBase(this, _session)[_session];
43
45
  }
46
+ }, {
47
+ key: "ackPayload",
48
+ get: function () {
49
+ var _classPrivateFieldLoo;
50
+ return {
51
+ utm_params: ((_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _page)[_page]) === null || _classPrivateFieldLoo === void 0 ? void 0 : _classPrivateFieldLoo.utmParams) || {}
52
+ };
53
+ }
44
54
  }, {
45
55
  key: "initialize",
46
- value: function initialize() {
56
+ value: function initialize(page = new _page2.Page()) {
57
+ _classPrivateFieldLooseBase(this, _page)[_page] = page;
47
58
  _classPrivateFieldLooseBase(this, _query)[_query] = new _query2.Query();
48
59
  this.session = _classPrivateFieldLooseBase(this, _query)[_query].session || _core.Configuration.session || _cookies.Cookies.get('hello_session');
49
60
  if (!this.session && _core.Configuration.autoGenerateSession) {
@@ -61,4 +72,8 @@ Object.defineProperty(Session, _session, {
61
72
  Object.defineProperty(Session, _query, {
62
73
  writable: true,
63
74
  value: void 0
75
+ });
76
+ Object.defineProperty(Session, _page, {
77
+ writable: true,
78
+ value: void 0
64
79
  });
@@ -8,10 +8,12 @@ var id = 0;
8
8
  function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
9
9
  import { Configuration } from '../core';
10
10
  import { Cookies } from './cookies';
11
+ import { Page } from './page';
11
12
  import { Query } from './query';
12
13
  import API from '../api';
13
14
  var _session = /*#__PURE__*/_classPrivateFieldLooseKey("session");
14
15
  var _query = /*#__PURE__*/_classPrivateFieldLooseKey("query");
16
+ var _page = /*#__PURE__*/_classPrivateFieldLooseKey("page");
15
17
  var Session = /*#__PURE__*/function () {
16
18
  function Session() {
17
19
  _classCallCheck(this, Session);
@@ -29,14 +31,24 @@ var Session = /*#__PURE__*/function () {
29
31
  Cookies.delete('hello_session_ack_at');
30
32
  }
31
33
  if (!Cookies.get('hello_session_ack_at')) {
32
- API.acks.send();
34
+ API.acks.send(this.ackPayload);
33
35
  Cookies.set('hello_session_ack_at', new Date().toISOString());
34
36
  }
35
37
  return _classPrivateFieldLooseBase(this, _session)[_session];
36
38
  }
39
+ }, {
40
+ key: "ackPayload",
41
+ get: function get() {
42
+ var _classPrivateFieldLoo;
43
+ return {
44
+ utm_params: ((_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _page)[_page]) === null || _classPrivateFieldLoo === void 0 ? void 0 : _classPrivateFieldLoo.utmParams) || {}
45
+ };
46
+ }
37
47
  }, {
38
48
  key: "initialize",
39
49
  value: function initialize() {
50
+ var page = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Page();
51
+ _classPrivateFieldLooseBase(this, _page)[_page] = page;
40
52
  _classPrivateFieldLooseBase(this, _query)[_query] = new Query();
41
53
  this.session = _classPrivateFieldLooseBase(this, _query)[_query].session || Configuration.session || Cookies.get('hello_session');
42
54
  if (!this.session && Configuration.autoGenerateSession) {
@@ -54,4 +66,8 @@ Object.defineProperty(Session, _query, {
54
66
  writable: true,
55
67
  value: void 0
56
68
  });
69
+ Object.defineProperty(Session, _page, {
70
+ writable: true,
71
+ value: void 0
72
+ });
57
73
  export { Session };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellotext/hellotext",
3
- "version": "2.4.51",
3
+ "version": "2.4.53",
4
4
  "description": "Hellotext JavaScript Client",
5
5
  "source": "src/index.js",
6
6
  "main": "lib/index.cjs",
package/src/api/acks.js CHANGED
@@ -7,8 +7,9 @@ class AcksAPI {
7
7
  return Configuration.endpoint('public/acks')
8
8
  }
9
9
 
10
- static async send() {
10
+ static async send(params = {}) {
11
11
  const payload = {
12
+ ...params,
12
13
  session: Hellotext.session,
13
14
  at: new Date().toISOString(),
14
15
  }
package/src/api/events.js CHANGED
@@ -8,16 +8,26 @@ export default class EventsAPI {
8
8
  return Configuration.endpoint('track/events')
9
9
  }
10
10
 
11
- static async create({ headers, body }) {
11
+ static async create({ headers, body, keepalive = false }) {
12
12
  if (Query.inPreviewMode) {
13
13
  return new Response(true, { received: true })
14
14
  }
15
15
 
16
- const response = await fetch(this.endpoint, {
16
+ const fetchOptions = {
17
17
  method: 'POST',
18
18
  headers,
19
19
  body: JSON.stringify(body),
20
- })
20
+ }
21
+
22
+ // Do not send `keepalive: false`. The track caller opts in only for payloads
23
+ // that fit the browser keepalive budget; omitting the key for larger events
24
+ // preserves normal fetch behavior for rich carts/orders instead of asking
25
+ // the browser to use an unload-safe transport it may reject.
26
+ if (keepalive) {
27
+ fetchOptions.keepalive = true
28
+ }
29
+
30
+ const response = await fetch(this.endpoint, fetchOptions)
21
31
 
22
32
  return new Response(response.status === 200, await response.json())
23
33
  }
package/src/api/index.js CHANGED
@@ -5,6 +5,29 @@ import IdentificationsAPI from './identifications'
5
5
  import WebchatsAPI from './webchats'
6
6
  import AcksAPI from './acks'
7
7
 
8
+ // Browsers keep `fetch(..., { keepalive: true })` requests alive during page
9
+ // unload/navigation, which is exactly the failure mode for analytics events
10
+ // fired from checkout redirects, form submissions, tab closes, and pixel
11
+ // lifecycles. The platform also caps keepalive request bodies around 64KB, and
12
+ // browsers can reject or drop oversized requests instead of making delivery
13
+ // more reliable. Keep the limit below that ceiling so the SDK only opts in when
14
+ // the payload is small enough for the keepalive transport contract.
15
+ const KEEPALIVE_BODY_LIMIT = 60000
16
+
17
+ function keepaliveFor(body) {
18
+ const serializedBody = JSON.stringify(body)
19
+
20
+ // Use byte size when the runtime exposes Blob because non-ASCII JSON can be
21
+ // larger on the wire than its JavaScript string length. The string-length
22
+ // fallback keeps older/non-browser runtimes conservative without pulling in
23
+ // another encoder just for this transport hint.
24
+ if (typeof Blob === 'undefined') {
25
+ return serializedBody.length < KEEPALIVE_BODY_LIMIT
26
+ }
27
+
28
+ return new Blob([serializedBody]).size < KEEPALIVE_BODY_LIMIT
29
+ }
30
+
8
31
  export default class API {
9
32
  static get businesses() {
10
33
  return BusinessesAPI
@@ -32,3 +55,4 @@ export default class API {
32
55
  }
33
56
 
34
57
  export { Response } from './response'
58
+ export { keepaliveFor }
package/src/hellotext.js CHANGED
@@ -1,7 +1,16 @@
1
1
  import { Configuration, Event } from './core'
2
2
 
3
- import API, { Response } from './api'
4
- import { Business, Fingerprint, FormCollection, Page, Query, Session, User, Webchat } from './models'
3
+ import API, { Response, keepaliveFor } from './api'
4
+ import {
5
+ Business,
6
+ Fingerprint,
7
+ FormCollection,
8
+ Page,
9
+ Query,
10
+ Session,
11
+ User,
12
+ Webchat,
13
+ } from './models'
5
14
 
6
15
  import { NotInitializedError } from './errors'
7
16
 
@@ -18,25 +27,28 @@ class Hellotext {
18
27
  */
19
28
  static async initialize(business, config = {}) {
20
29
  this.business = new Business(business)
30
+ this.page = new Page()
21
31
 
22
32
  Configuration.assign(config)
23
- Session.initialize()
33
+ Session.initialize(this.page)
24
34
 
25
- this.page = new Page()
26
35
  this.forms = new FormCollection()
27
36
 
28
37
  this.query = new Query()
29
38
 
30
39
  const businessData = await this.business.hydrate()
31
- const webchatConfig = config.webchat === false ?
32
- false :
33
- this.mergeWebchatConfig((businessData && businessData.webchat) || {}, config.webchat || {})
34
-
35
- const hasExplicitBehaviourOverride = (
40
+ const webchatConfig =
41
+ config.webchat === false
42
+ ? false
43
+ : this.mergeWebchatConfig(
44
+ (businessData && businessData.webchat) || {},
45
+ config.webchat || {},
46
+ )
47
+
48
+ const hasExplicitBehaviourOverride =
36
49
  config.webchat &&
37
50
  config.webchat !== false &&
38
51
  Object.prototype.hasOwnProperty.call(config.webchat, 'behaviour')
39
- )
40
52
  Configuration.webchat.behaviourOverride = hasExplicitBehaviourOverride
41
53
 
42
54
  if (webchatConfig && webchatConfig.id) {
@@ -108,6 +120,11 @@ class Hellotext {
108
120
  return await API.events.create({
109
121
  headers,
110
122
  body,
123
+ // Track is the SDK's unload-sensitive analytics path. Keepalive belongs
124
+ // here rather than on identify/forms/webchat calls because event tracking
125
+ // is allowed to be fire-and-navigate, while those other calls have
126
+ // stronger request/response or interaction contracts.
127
+ keepalive: keepaliveFor(body),
111
128
  })
112
129
  }
113
130
 
@@ -142,11 +159,7 @@ class Hellotext {
142
159
  })
143
160
 
144
161
  if (response.succeeded) {
145
- User.remember(
146
- externalId,
147
- options.source,
148
- fingerprint,
149
- )
162
+ User.remember(externalId, options.source, fingerprint)
150
163
  }
151
164
 
152
165
  return response
@@ -1,16 +1,24 @@
1
1
  import { Configuration } from '../core'
2
2
  import { Cookies } from './cookies'
3
+ import { Page } from './page'
3
4
  import { Query } from './query'
4
5
  import API from '../api'
5
6
 
6
7
  class Session {
7
8
  static #session
8
9
  static #query
10
+ static #page
9
11
 
10
12
  static get session() {
11
13
  return this.#session
12
14
  }
13
15
 
16
+ static get ackPayload() {
17
+ return {
18
+ utm_params: this.#page?.utmParams || {},
19
+ }
20
+ }
21
+
14
22
  static set session(value) {
15
23
  const oldSession = Cookies.get('hello_session')
16
24
 
@@ -22,14 +30,15 @@ class Session {
22
30
  }
23
31
 
24
32
  if (!Cookies.get('hello_session_ack_at')) {
25
- API.acks.send()
33
+ API.acks.send(this.ackPayload)
26
34
  Cookies.set('hello_session_ack_at', new Date().toISOString())
27
35
  }
28
36
 
29
37
  return this.#session
30
38
  }
31
39
 
32
- static initialize() {
40
+ static initialize(page = new Page()) {
41
+ this.#page = page
33
42
  this.#query = new Query()
34
43
 
35
44
  this.session = this.#query.session || Configuration.session || Cookies.get('hello_session')