@usermaven/nextjs 1.3.2 → 1.4.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.
Files changed (2) hide show
  1. package/lib/index.es.js +162 -11
  2. package/package.json +1 -1
package/lib/index.es.js CHANGED
@@ -790,10 +790,21 @@ function _copyAndTruncateStrings(object, maxStringLength) {
790
790
  }
791
791
  // Function to find the closest link element
792
792
  function _findClosestLink(element) {
793
- while (element && element.tagName && element.tagName.toLowerCase() !== 'a') {
793
+ while (element && element.tagName) {
794
+ if (element.tagName.toLowerCase() == 'a') {
795
+ return element;
796
+ }
794
797
  element = element.parentNode;
795
798
  }
796
- return element;
799
+ return null;
800
+ }
801
+ function _cleanObject(obj) {
802
+ for (var propName in obj) {
803
+ if (obj[propName] === '' || obj[propName] === null || obj[propName] === undefined || (typeof obj[propName] === 'object' && Object.keys(obj[propName]).length === 0)) {
804
+ delete obj[propName];
805
+ }
806
+ }
807
+ return obj;
797
808
  }
798
809
 
799
810
  /*
@@ -1404,10 +1415,131 @@ var autocapture = {
1404
1415
  _bind_instance_methods(autocapture);
1405
1416
  _safewrap_instance_methods(autocapture);
1406
1417
 
1418
+ var FormTracking = /** @class */ (function () {
1419
+ function FormTracking(instance, trackingType) {
1420
+ if (trackingType === void 0) { trackingType = 'all'; }
1421
+ this.instance = instance;
1422
+ this.trackingType = trackingType;
1423
+ // Wait for the DOM to be ready
1424
+ if (document.readyState === 'loading') {
1425
+ document.addEventListener('DOMContentLoaded', this.track.bind(this));
1426
+ }
1427
+ else {
1428
+ this.track();
1429
+ }
1430
+ }
1431
+ /**
1432
+ * Track form submit
1433
+ * @description this function will be called on every form submit event to track form submit
1434
+ */
1435
+ FormTracking.prototype.track = function () {
1436
+ var _this = this;
1437
+ this.formElements = document.querySelectorAll('form');
1438
+ if (this.trackingType === 'tagged') {
1439
+ this.formElements = document.querySelectorAll('form[data-um-form]');
1440
+ }
1441
+ this.formElements.forEach(function (form) {
1442
+ form.addEventListener('submit', function (event) {
1443
+ var form = event.target;
1444
+ var props = _this._getFormDetails(form);
1445
+ _this.instance.capture('$form', _cleanObject(props));
1446
+ });
1447
+ });
1448
+ };
1449
+ FormTracking.getInstance = function (instance, trackingType) {
1450
+ if (trackingType === void 0) { trackingType = 'all'; }
1451
+ if (!FormTracking.instance) {
1452
+ FormTracking.instance = new FormTracking(instance, trackingType);
1453
+ }
1454
+ return FormTracking.instance;
1455
+ };
1456
+ FormTracking.prototype._getFormDetails = function (form) {
1457
+ var _this = this;
1458
+ var formDetails = {
1459
+ form_id: form.id,
1460
+ form_name: form.name || '',
1461
+ form_action: form.action,
1462
+ form_method: form.method,
1463
+ };
1464
+ var formFields = form.querySelectorAll('input, select, textarea');
1465
+ // ignore form fields with class um-no-capture
1466
+ var filteredFormFields = Array.from(formFields).filter(function (field) { return !field.classList.contains('um-no-capture'); });
1467
+ filteredFormFields.forEach(function (field, index) {
1468
+ var fieldProps = _this._getFieldProps(field, index);
1469
+ Object.assign(formDetails, fieldProps);
1470
+ });
1471
+ return formDetails;
1472
+ };
1473
+ FormTracking.prototype._getFieldProps = function (field, index) {
1474
+ var _a;
1475
+ var fieldDataAttributes = Object.keys(field.dataset).length ? JSON.stringify(field.dataset) : undefined;
1476
+ var safeValue = this.getSafeText(field);
1477
+ return _a = {},
1478
+ _a["field_" + (index + 1) + "_tag"] = field.tagName.toLowerCase(),
1479
+ _a["field_" + (index + 1) + "_type"] = field instanceof HTMLInputElement ? field.type : undefined,
1480
+ _a["field_" + (index + 1) + "_data_attributes"] = fieldDataAttributes,
1481
+ _a["field_" + (index + 1) + "_id"] = field.id,
1482
+ _a["field_" + (index + 1) + "_value"] = safeValue,
1483
+ _a["field_" + (index + 1) + "_class"] = field.className,
1484
+ _a["field_" + (index + 1) + "_name"] = field.name,
1485
+ _a;
1486
+ };
1487
+ FormTracking.prototype.getSafeText = function (element) {
1488
+ var safeText = '';
1489
+ if ('value' in element && element.type !== "password") {
1490
+ safeText = element.value;
1491
+ }
1492
+ else if (element.hasChildNodes()) {
1493
+ var textNodes = Array.from(element.childNodes).filter(function (node) { return node.nodeType === Node.TEXT_NODE; });
1494
+ safeText = textNodes.map(function (node) { return node.textContent; }).join('');
1495
+ }
1496
+ else {
1497
+ safeText = element.textContent || '';
1498
+ }
1499
+ return this._scrubPotentiallySensitiveValues(safeText);
1500
+ };
1501
+ FormTracking.prototype._scrubPotentiallySensitiveValues = function (text) {
1502
+ if (!this._shouldCaptureValue(text)) {
1503
+ return '<redacted>';
1504
+ }
1505
+ return text;
1506
+ };
1507
+ FormTracking.prototype._shouldCaptureValue = function (value) {
1508
+ if (this._isNullish(value)) {
1509
+ return false;
1510
+ }
1511
+ if (this._isString(value)) {
1512
+ value = this._trim(value);
1513
+ // check to see if input value looks like a credit card number
1514
+ // see: https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s20.html
1515
+ var ccRegex = /^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/;
1516
+ if (ccRegex.test((value || '').replace(/[- ]/g, ''))) {
1517
+ return false;
1518
+ }
1519
+ // check to see if input value looks like a social security number
1520
+ var ssnRegex = /(^\d{3}-?\d{2}-?\d{4}$)/;
1521
+ if (ssnRegex.test(value)) {
1522
+ return false;
1523
+ }
1524
+ }
1525
+ return true;
1526
+ };
1527
+ FormTracking.prototype._isNullish = function (value) {
1528
+ return value === null || value === undefined;
1529
+ };
1530
+ FormTracking.prototype._isString = function (value) {
1531
+ return typeof value === 'string' || value instanceof String;
1532
+ };
1533
+ FormTracking.prototype._trim = function (value) {
1534
+ return value.trim().replace(/^\s+|\s+$/g, '');
1535
+ };
1536
+ return FormTracking;
1537
+ }());
1538
+
1407
1539
  var VERSION_INFO = {
1408
1540
  env: 'production',
1409
- date: '2024-02-20T05:52:39.092Z',
1410
- version: '1.3.2'
1541
+ date: '2024-05-21T10:41:05.452Z',
1542
+ version: '1.4.0'
1411
1543
  };
1412
1544
  var USERMAVEN_VERSION = VERSION_INFO.version + "/" + VERSION_INFO.env + "@" + VERSION_INFO.date;
1413
1545
  var MAX_AGE_TEN_YEARS = 31622400 * 10;
@@ -1762,6 +1894,7 @@ var UsermavenClientImpl = /** @class */ (function () {
1762
1894
  this.randomizeUrl = false;
1763
1895
  this.namespace = "usermaven";
1764
1896
  this.crossDomainLinking = true;
1897
+ this.formTracking = false;
1765
1898
  this.domains = [];
1766
1899
  this.apiKey = "";
1767
1900
  this.initialized = false;
@@ -2080,7 +2213,7 @@ var UsermavenClientImpl = /** @class */ (function () {
2080
2213
  };
2081
2214
  UsermavenClientImpl.prototype.init = function (options) {
2082
2215
  var _this = this;
2083
- var _a, _b, _c, _d, _e;
2216
+ var _a, _b, _c, _d, _e, _f;
2084
2217
  if (isWindowAvailable() && !options.force_use_fetch) {
2085
2218
  if (options.fetch) {
2086
2219
  getLogger().warn("Custom fetch implementation is provided to Usermaven. However, it will be ignored since Usermaven runs in browser");
@@ -2140,6 +2273,7 @@ var UsermavenClientImpl = /** @class */ (function () {
2140
2273
  this.cookieDomain = options.cookie_domain || getCookieDomain();
2141
2274
  this.namespace = options.namespace || "usermaven";
2142
2275
  this.crossDomainLinking = (_a = options.cross_domain_linking) !== null && _a !== void 0 ? _a : true;
2276
+ this.formTracking = (_b = options.form_tracking) !== null && _b !== void 0 ? _b : false;
2143
2277
  this.domains = options.domains ? (options.domains).split(',').map(function (domain) { return domain.trim(); }) : [];
2144
2278
  this.trackingHost = getHostWithProtocol(options["tracking_host"] || "t.usermaven.com");
2145
2279
  this.randomizeUrl = options.randomize_url || false;
@@ -2166,8 +2300,8 @@ var UsermavenClientImpl = /** @class */ (function () {
2166
2300
  var restored = this.propsPersistance.restore();
2167
2301
  if (restored) {
2168
2302
  this.permanentProperties = restored;
2169
- this.permanentProperties.globalProps = (_b = restored.globalProps) !== null && _b !== void 0 ? _b : {};
2170
- this.permanentProperties.propsPerEvent = (_c = restored.propsPerEvent) !== null && _c !== void 0 ? _c : {};
2303
+ this.permanentProperties.globalProps = (_c = restored.globalProps) !== null && _c !== void 0 ? _c : {};
2304
+ this.permanentProperties.propsPerEvent = (_d = restored.propsPerEvent) !== null && _d !== void 0 ? _d : {};
2171
2305
  }
2172
2306
  getLogger().debug("Restored persistent properties", this.permanentProperties);
2173
2307
  }
@@ -2184,6 +2318,7 @@ var UsermavenClientImpl = /** @class */ (function () {
2184
2318
  getLogger().debug('Default Configuration', this.config);
2185
2319
  // this.manageSession(this.config);
2186
2320
  this.manageAutoCapture(this.config);
2321
+ this.manageFormTracking(this.config);
2187
2322
  this.manageCrossDomainLinking({
2188
2323
  cross_domain_linking: this.crossDomainLinking,
2189
2324
  domains: this.domains,
@@ -2218,8 +2353,8 @@ var UsermavenClientImpl = /** @class */ (function () {
2218
2353
  enableAutoPageviews(this);
2219
2354
  }
2220
2355
  this.retryTimeout = [
2221
- (_d = options.min_send_timeout) !== null && _d !== void 0 ? _d : this.retryTimeout[0],
2222
- (_e = options.max_send_timeout) !== null && _e !== void 0 ? _e : this.retryTimeout[1],
2356
+ (_e = options.min_send_timeout) !== null && _e !== void 0 ? _e : this.retryTimeout[0],
2357
+ (_f = options.max_send_timeout) !== null && _f !== void 0 ? _f : this.retryTimeout[1],
2223
2358
  ];
2224
2359
  if (!!options.max_send_attempts) {
2225
2360
  this.maxSendAttempts = options.max_send_attempts;
@@ -2316,7 +2451,7 @@ var UsermavenClientImpl = /** @class */ (function () {
2316
2451
  var target = _findClosestLink(event.target);
2317
2452
  if (target) {
2318
2453
  // Check if the link is pointing to a different domain
2319
- var href = target.getAttribute('href');
2454
+ var href = (target === null || target === void 0 ? void 0 : target.hasAttribute('href')) ? target === null || target === void 0 ? void 0 : target.getAttribute('href') : '';
2320
2455
  if (href && href.startsWith('http')) {
2321
2456
  var url = new URL(href);
2322
2457
  var cookie = getCookie(cookieName);
@@ -2360,6 +2495,18 @@ var UsermavenClientImpl = /** @class */ (function () {
2360
2495
  autocapture.init(this, options);
2361
2496
  }
2362
2497
  };
2498
+ /**
2499
+ * Manage form tracking
2500
+ */
2501
+ UsermavenClientImpl.prototype.manageFormTracking = function (options) {
2502
+ if (!isWindowAvailable() || !this.formTracking || this.formTracking === "none") {
2503
+ return;
2504
+ }
2505
+ getLogger().debug('Form tracking enabled...');
2506
+ // all and true are the same
2507
+ var trackingType = this.formTracking === true ? 'all' : this.formTracking;
2508
+ FormTracking.getInstance(this, trackingType).track();
2509
+ };
2363
2510
  /**
2364
2511
  * Capture an event. This is the most important and
2365
2512
  * frequently used usermaven function.
@@ -2400,12 +2547,16 @@ var UsermavenClientImpl = /** @class */ (function () {
2400
2547
  if (event_name === '$scroll') {
2401
2548
  this.track(event_name, data.properties);
2402
2549
  }
2550
+ // send event if the event is $form
2551
+ if (event_name === '$form') {
2552
+ this.track(event_name, data.properties);
2553
+ }
2403
2554
  };
2404
2555
  UsermavenClientImpl.prototype._calculate_event_properties = function (event_name, event_properties) {
2405
2556
  var _a, _b;
2406
2557
  // set defaults
2407
2558
  var properties = event_properties || {};
2408
- if (event_name === '$snapshot' || event_name === '$scroll') {
2559
+ if (event_name === '$snapshot' || event_name === '$scroll' || event_name === '$form') {
2409
2560
  return properties;
2410
2561
  }
2411
2562
  if (_isArray(this.propertyBlacklist)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usermaven/nextjs",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Usermaven JavaScript SDK for NextJS",
5
5
  "author": "Usermaven <hello@usermaven.com>",
6
6
  "license": "MIT",