@saasquatch/squatch-js 2.5.0-0 → 2.5.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.
@@ -1,9 +1,66 @@
1
1
  import * as debug from 'debug';
2
2
  import debug__default from 'debug';
3
3
  import * as EventBus from 'eventbusjs';
4
- import * as superagent from 'superagent';
5
4
  import Cookies from 'js-cookie';
5
+ import * as superagent from 'superagent';
6
+
7
+ function _extends() {
8
+ _extends = Object.assign || function (target) {
9
+ for (var i = 1; i < arguments.length; i++) {
10
+ var source = arguments[i];
11
+
12
+ for (var key in source) {
13
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
14
+ target[key] = source[key];
15
+ }
16
+ }
17
+ }
18
+
19
+ return target;
20
+ };
6
21
 
22
+ return _extends.apply(this, arguments);
23
+ }
24
+
25
+ function _objectWithoutPropertiesLoose(source, excluded) {
26
+ if (source == null) return {};
27
+ var target = {};
28
+ var sourceKeys = Object.keys(source);
29
+ var key, i;
30
+
31
+ for (i = 0; i < sourceKeys.length; i++) {
32
+ key = sourceKeys[i];
33
+ if (excluded.indexOf(key) >= 0) continue;
34
+ target[key] = source[key];
35
+ }
36
+
37
+ return target;
38
+ }
39
+
40
+ function doQuery(url, query, variables, token) {
41
+ const headers = _extends({
42
+ Accept: "application/json"
43
+ }, token ? {
44
+ Authorization: `Bearer ${token}`
45
+ } : {}, {
46
+ "X-SaaSquatch-Referrer": window ? window.location.href : ""
47
+ });
48
+
49
+ const request = superagent.post(url).send({
50
+ query,
51
+ variables
52
+ }).set(headers);
53
+ return thenableSuperagent(request).then(response => response, error => {
54
+ let json;
55
+
56
+ try {
57
+ json = JSON.parse(error.response.text);
58
+ } catch (e) {
59
+ }
60
+
61
+ throw json;
62
+ });
63
+ }
7
64
  function doGet(url, jwt = "") {
8
65
  const headers = {
9
66
  Accept: "application/json",
@@ -140,12 +197,37 @@ function validateConfig(raw) {
140
197
  npmCdn
141
198
  };
142
199
  }
200
+ function validateLocale(locale) {
201
+ if (locale && /^[a-z]{2}_(?:[A-Z]{2}|[0-9]{3})$/.test(locale)) {
202
+ return locale;
203
+ }
204
+ }
143
205
  function validateWidgetConfig(raw) {
144
206
  if (!isObject$1(raw)) throw new Error("Widget properties must be an object");
145
207
  if (!assertProp(raw, "user")) ; // TODO: This should be better type checked
146
208
 
147
209
  return raw;
148
210
  }
211
+ function validatePasswordlessConfig(raw) {
212
+ if (!isObject$1(raw)) throw new Error("Widget properties must be an object");
213
+ return raw;
214
+ }
215
+
216
+ const RENDER_WIDGET_QUERY = `
217
+ query renderWidget ($user: UserIdInput, $engagementMedium: UserEngagementMedium, $widgetType: WidgetType, $locale: RSLocale) {
218
+ renderWidget(user: $user, engagementMedium: $engagementMedium, widgetType: $widgetType, locale: $locale) {
219
+ template
220
+ user {
221
+ id
222
+ accountId
223
+ }
224
+ jsOptions
225
+ widgetConfig {
226
+ values
227
+ }
228
+ }
229
+ }
230
+ `;
149
231
 
150
232
  /**
151
233
  *
@@ -234,8 +316,10 @@ class WidgetApi {
234
316
 
235
317
 
236
318
  render(params) {
319
+ var _clean$locale;
320
+
237
321
  const raw = params;
238
- const clean = validateWidgetConfig(raw);
322
+ const clean = validatePasswordlessConfig(raw);
239
323
  const {
240
324
  widgetType,
241
325
  engagementMedium = "POPUP",
@@ -243,17 +327,29 @@ class WidgetApi {
243
327
  user
244
328
  } = clean;
245
329
  const tenantAlias = encodeURIComponent(this.tenantAlias);
246
- const accountId = encodeURIComponent(user.accountId);
247
- const userId = encodeURIComponent(user.id);
248
-
249
- const optionalParams = _buildParams({
250
- widgetType,
251
- engagementMedium
252
- });
253
-
254
- const path = `/api/v1/${tenantAlias}/widget/account/${accountId}/user/${userId}/render${optionalParams}`;
330
+ const accountId = user ? encodeURIComponent(user.accountId) : null;
331
+ const userId = user ? encodeURIComponent(user.id) : null;
332
+ const locale = (_clean$locale = clean.locale) != null ? _clean$locale : validateLocale(navigator.language.replace(/\-/g, "_"));
333
+ const path = `/api/v1/${tenantAlias}/graphql`;
255
334
  const url = this.domain + path;
256
- return doGet(url, jwt);
335
+ return new Promise(async (resolve, reject) => {
336
+ try {
337
+ var _res$body, _res$body$data;
338
+
339
+ const res = await doQuery(url, RENDER_WIDGET_QUERY, {
340
+ user: userId && accountId ? {
341
+ id: userId,
342
+ accountId
343
+ } : null,
344
+ engagementMedium,
345
+ widgetType,
346
+ locale
347
+ }, jwt);
348
+ resolve(res == null ? void 0 : (_res$body = res.body) == null ? void 0 : (_res$body$data = _res$body.data) == null ? void 0 : _res$body$data.renderWidget);
349
+ } catch (e) {
350
+ reject(e);
351
+ }
352
+ });
257
353
  }
258
354
  /**
259
355
  * An API call to send out referral invites to contacts
@@ -287,18 +383,21 @@ class WidgetApi {
287
383
  /**
288
384
  * Looks up the referral code of the current user, if there is any.
289
385
  *
290
- * @return {Promise<Object>} code referral code if true.
386
+ * @return {Promise<ReferralCookie>} code referral code if true.
291
387
  */
292
388
 
293
389
 
294
- squatchReferralCookie() {
390
+ async squatchReferralCookie() {
295
391
  const tenantAlias = encodeURIComponent(this.tenantAlias);
296
392
 
297
- const _saasquatch = Cookies.get("_saasquatch");
393
+ const _saasquatch = Cookies.get("_saasquatch") || "";
298
394
 
299
395
  const cookie = _saasquatch ? `?cookies=${encodeURIComponent(_saasquatch)}` : ``;
300
396
  const url = `${this.domain}/a/${tenantAlias}/widgets/squatchcookiejson${cookie}`;
301
- return doGet(url);
397
+ const response = await doGet(url);
398
+ return Promise.resolve(_extends({}, response, {
399
+ encodedCookie: _saasquatch
400
+ }));
302
401
  }
303
402
 
304
403
  } // builds a param string for widgets
@@ -341,6 +440,7 @@ class AnalyticsApi {
341
440
  }
342
441
 
343
442
  pushAnalyticsLoadEvent(params) {
443
+ if (!params.externalUserId || !params.externalAccountId) return;
344
444
  const tenantAlias = encodeURIComponent(params.tenantAlias);
345
445
  const accountId = encodeURIComponent(params.externalAccountId);
346
446
  const userId = encodeURIComponent(params.externalUserId);
@@ -367,7 +467,7 @@ class AnalyticsApi {
367
467
  // @ts-check
368
468
  /** @hidden */
369
469
 
370
- const _log$6 = debug__default("squatch-js:widget");
470
+ const _log$7 = debug__default("squatch-js:widget");
371
471
  /*
372
472
  * The Widget class is the base class for the different widget types available
373
473
  *
@@ -380,7 +480,7 @@ const _log$6 = debug__default("squatch-js:widget");
380
480
 
381
481
  class Widget {
382
482
  constructor(params) {
383
- _log$6("widget initializing ...");
483
+ _log$7("widget initializing ...");
384
484
 
385
485
  this.content = params.content === "error" ? this._error(params.rsCode) : params.content;
386
486
  this.type = params.type;
@@ -398,6 +498,8 @@ class Widget {
398
498
  }
399
499
 
400
500
  _loadEvent(sqh) {
501
+ var _this$analyticsApi$pu;
502
+
401
503
  if (!sqh) return; // No non-truthy value
402
504
 
403
505
  if (!isObject$1(sqh)) {
@@ -431,10 +533,10 @@ class Widget {
431
533
  };
432
534
  }
433
535
 
434
- this.analyticsApi.pushAnalyticsLoadEvent(params).then(response => {
435
- _log$6(`${params.engagementMedium} loaded event recorded.`);
536
+ (_this$analyticsApi$pu = this.analyticsApi.pushAnalyticsLoadEvent(params)) == null ? void 0 : _this$analyticsApi$pu.then(response => {
537
+ _log$7(`${params.engagementMedium} loaded event recorded.`);
436
538
  }).catch(ex => {
437
- _log$6(new Error(`pushAnalyticsLoadEvent() ${ex}`));
539
+ _log$7(new Error(`pushAnalyticsLoadEvent() ${ex}`));
438
540
  });
439
541
  }
440
542
 
@@ -447,9 +549,9 @@ class Widget {
447
549
  engagementMedium: sqh.mode.widgetMode,
448
550
  shareMedium: medium
449
551
  }).then(response => {
450
- _log$6(`${sqh.mode.widgetMode} share ${medium} event recorded. ${response}`);
552
+ _log$7(`${sqh.mode.widgetMode} share ${medium} event recorded. ${response}`);
451
553
  }).catch(ex => {
452
- _log$6(new Error(`pushAnalyticsLoadEvent() ${ex}`));
554
+ _log$7(new Error(`pushAnalyticsLoadEvent() ${ex}`));
453
555
  });
454
556
  }
455
557
  }
@@ -462,9 +564,9 @@ class Widget {
462
564
  userId: sqh.analytics.attributes.userId,
463
565
  emailList
464
566
  }).then(response => {
465
- _log$6(`Sent email invites to share ${emailList}. ${response}`);
567
+ _log$7(`Sent email invites to share ${emailList}. ${response}`);
466
568
  }).catch(ex => {
467
- _log$6(new Error(`invite() ${ex}`));
569
+ _log$7(new Error(`invite() ${ex}`));
468
570
  });
469
571
  }
470
572
  }
@@ -553,6 +655,7 @@ class Widget {
553
655
  email: email || null,
554
656
  firstName: firstName || null,
555
657
  lastName: lastName || null,
658
+ // FIXME: Double check this
556
659
  id: this.context.user.id,
557
660
  accountId: this.context.user.accountId
558
661
  };
@@ -562,6 +665,13 @@ class Widget {
562
665
  widgetType: this.type,
563
666
  jwt
564
667
  });
668
+ } else if (this.context.type === "passwordless") {
669
+ response = this.widgetApi.render({
670
+ user: undefined,
671
+ engagementMedium,
672
+ widgetType: this.type,
673
+ jwt: undefined
674
+ });
565
675
  } else {
566
676
  throw new Error("can't reload an error widget");
567
677
  }
@@ -596,7 +706,7 @@ class Widget {
596
706
  }).catch(({
597
707
  message
598
708
  }) => {
599
- _log$6(`${message}`);
709
+ _log$7(`${message}`);
600
710
  });
601
711
  }
602
712
 
@@ -633,7 +743,7 @@ function domready(targetDoc, fn) {
633
743
 
634
744
  // @ts-check
635
745
 
636
- const _log$5 = debug__default("squatch-js:EMBEDwidget");
746
+ const _log$6 = debug__default("squatch-js:EMBEDwidget");
637
747
  /**
638
748
  * An EmbedWidget is displayed inline in part of your page.
639
749
  *
@@ -651,22 +761,22 @@ class EmbedWidget extends Widget {
651
761
  // selector is a string
652
762
  element = document.querySelector(container);
653
763
 
654
- _log$5("loading widget with selector", element); // selector is an HTML element
764
+ _log$6("loading widget with selector", element); // selector is an HTML element
655
765
 
656
766
  } else if (container instanceof HTMLElement) {
657
767
  element = container;
658
768
 
659
- _log$5("loading widget with container", element); // garbage container found
769
+ _log$6("loading widget with container", element); // garbage container found
660
770
 
661
771
  } else if (container) {
662
772
  element = null;
663
773
 
664
- _log$5("container must be an HTMLElement or string", container); // find element on page
774
+ _log$6("container must be an HTMLElement or string", container); // find element on page
665
775
 
666
776
  } else {
667
777
  element = document.querySelector("#squatchembed") || document.querySelector(".squatchembed");
668
778
 
669
- _log$5("loading widget with default selector", element);
779
+ _log$6("loading widget with default selector", element);
670
780
  }
671
781
 
672
782
  if (!(element instanceof HTMLElement)) throw new Error(`element with selector '${container}' not found.'`);
@@ -732,7 +842,7 @@ class EmbedWidget extends Widget {
732
842
  if (!this.context.container) {
733
843
  this._loadEvent(_sqh);
734
844
 
735
- _log$5("loaded");
845
+ _log$6("loaded");
736
846
  }
737
847
  });
738
848
  } // Un-hide if element is available and refresh data
@@ -741,7 +851,7 @@ class EmbedWidget extends Widget {
741
851
  open() {
742
852
  var _this$frame, _this$frame$contentDo, _this$frame2, _this$frame2$contentW, _this$frame3, _this$frame3$contentW;
743
853
 
744
- if (!this.frame) return _log$5("no target element to open");
854
+ if (!this.frame) return _log$6("no target element to open");
745
855
  this.element.style.visibility = "unset";
746
856
  this.element.style.height = "auto";
747
857
  this.element.style["overflow-y"] = "auto";
@@ -751,16 +861,16 @@ class EmbedWidget extends Widget {
751
861
 
752
862
  this._loadEvent(_sqh);
753
863
 
754
- _log$5("loaded");
864
+ _log$6("loaded");
755
865
  }
756
866
 
757
867
  close() {
758
- if (!this.frame) return _log$5("no target element to close");
868
+ if (!this.frame) return _log$6("no target element to close");
759
869
  this.element.style.visibility = "hidden";
760
870
  this.element.style.height = "0";
761
871
  this.element.style["overflow-y"] = "hidden";
762
872
 
763
- _log$5("Embed widget closed");
873
+ _log$6("Embed widget closed");
764
874
  }
765
875
 
766
876
  _error(rs, mode = "embed", style = "") {
@@ -771,7 +881,7 @@ class EmbedWidget extends Widget {
771
881
 
772
882
  // @ts-check
773
883
 
774
- const _log$4 = debug__default("squatch-js:POPUPwidget");
884
+ const _log$5 = debug__default("squatch-js:POPUPwidget");
775
885
  /**
776
886
  * The PopupWidget is used to display popups (also known as "Modals").
777
887
  * Popups widgets are rendered on top of other elements in a page.
@@ -789,9 +899,9 @@ class PopupWidget extends Widget {
789
899
  this.triggerElement
790
900
  /* HTMLButton */
791
901
  = document.querySelector(trigger);
792
- if (trigger && !this.triggerElement) _log$4("No element found with trigger selector", trigger);
902
+ if (trigger && !this.triggerElement) _log$5("No element found with trigger selector", trigger);
793
903
  } catch (_unused) {
794
- _log$4("Not a valid selector", trigger);
904
+ _log$5("Not a valid selector", trigger);
795
905
  } // Trigger is optional
796
906
 
797
907
 
@@ -814,6 +924,7 @@ class PopupWidget extends Widget {
814
924
  this.popupdiv = document.createElement("div");
815
925
  this.popupdiv.id = "squatchModal";
816
926
  this.popupdiv.setAttribute("style", "display: none; position: fixed; z-index: 1; padding-top: 5%; left: 0; top: -2000px; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);");
927
+ document.head.insertAdjacentHTML("beforeend", `<style>#squatchModal::-webkit-scrollbar { display: none; }</style>`);
817
928
  this.popupcontent = document.createElement("div");
818
929
  this.popupcontent.setAttribute("style", "margin: auto; width: 80%; max-width: 500px; position: relative;");
819
930
 
@@ -833,7 +944,7 @@ class PopupWidget extends Widget {
833
944
  frameDoc.write(`<script src="${this.npmCdn}/resize-observer-polyfill@1.5.x"></script>`);
834
945
  frameDoc.close();
835
946
 
836
- _log$4("Popup template loaded into iframe");
947
+ _log$5("Popup template loaded into iframe");
837
948
 
838
949
  this._setupResizeHandler();
839
950
  }
@@ -906,7 +1017,7 @@ class PopupWidget extends Widget {
906
1017
 
907
1018
  this._loadEvent(_sqh);
908
1019
 
909
- _log$4("Popup opened");
1020
+ _log$5("Popup opened");
910
1021
  });
911
1022
  }
912
1023
 
@@ -914,7 +1025,7 @@ class PopupWidget extends Widget {
914
1025
  this.popupdiv.style.visibility = "hidden";
915
1026
  this.popupdiv.style.top = "-2000px";
916
1027
 
917
- _log$4("Popup closed");
1028
+ _log$5("Popup closed");
918
1029
  }
919
1030
 
920
1031
  _clickedOutside({
@@ -932,7 +1043,7 @@ class PopupWidget extends Widget {
932
1043
 
933
1044
  }
934
1045
 
935
- const _log$3 = debug("squatch-js:CTAwidget");
1046
+ const _log$4 = debug("squatch-js:CTAwidget");
936
1047
  /**
937
1048
  * A CtaWidget is displayed on top of your page
938
1049
  *
@@ -943,7 +1054,7 @@ const _log$3 = debug("squatch-js:CTAwidget");
943
1054
 
944
1055
  class CtaWidget extends PopupWidget {
945
1056
  constructor(params, opts) {
946
- _log$3("CTA constructor");
1057
+ _log$4("CTA constructor");
947
1058
 
948
1059
  const ctaElement = document.createElement("div");
949
1060
  ctaElement.id = "cta";
@@ -971,7 +1082,7 @@ class CtaWidget extends PopupWidget {
971
1082
  this.ctaFrame.setAttribute("style", `border:0; background-color:transparent; position:fixed; display:none;${this.side}${this.position}`);
972
1083
  document.body.appendChild(this.ctaFrame);
973
1084
 
974
- _log$3("ctaframe appended to body");
1085
+ _log$4("ctaframe appended to body");
975
1086
  }
976
1087
 
977
1088
  load() {
@@ -1035,10 +1146,10 @@ class CtaWidget extends PopupWidget {
1035
1146
  });
1036
1147
  ro.observe(ctaContainer);
1037
1148
 
1038
- _log$3("CTA template loaded into iframe");
1149
+ _log$4("CTA template loaded into iframe");
1039
1150
  });
1040
1151
  } else {
1041
- _log$3(new Error("CTA element not found in theme"));
1152
+ _log$4(new Error("CTA element not found in theme"));
1042
1153
  }
1043
1154
  });
1044
1155
  }
@@ -1061,7 +1172,7 @@ class CtaWidget extends PopupWidget {
1061
1172
 
1062
1173
  }
1063
1174
 
1064
- const _log$2 = debug__default("squatch-js:widgets");
1175
+ const _log$3 = debug__default("squatch-js:widgets");
1065
1176
  /**
1066
1177
  *
1067
1178
  * `Widgets` is a factory for creating widgets. It's possible to build your own widgets using the
@@ -1126,7 +1237,7 @@ class Widgets {
1126
1237
  return {
1127
1238
  widget: this._renderWidget(response, clean, {
1128
1239
  type: "upsert",
1129
- user: clean.user,
1240
+ user: clean.user || null,
1130
1241
  engagementMedium: config.engagementMedium,
1131
1242
  container: config.container,
1132
1243
  trigger: config.trigger
@@ -1134,7 +1245,7 @@ class Widgets {
1134
1245
  user: response.user
1135
1246
  };
1136
1247
  } catch (err) {
1137
- _log$2(err);
1248
+ _log$3(err);
1138
1249
 
1139
1250
  if (err.apiErrorCode) {
1140
1251
  this._renderErrorWidget(err, config.engagementMedium);
@@ -1162,15 +1273,13 @@ class Widgets {
1162
1273
 
1163
1274
  async render(config) {
1164
1275
  const raw = config;
1165
- const clean = validateWidgetConfig(raw);
1276
+ const clean = validatePasswordlessConfig(raw);
1166
1277
 
1167
1278
  try {
1168
- const response = await this.api.upsertUser(clean);
1279
+ const response = await this.api.render(clean);
1169
1280
  return {
1170
- widget: this._renderWidget({
1171
- template: response
1172
- }, clean, {
1173
- type: "cookie",
1281
+ widget: this._renderWidget(response, clean, {
1282
+ type: "passwordless",
1174
1283
  engagementMedium: clean.engagementMedium
1175
1284
  }),
1176
1285
  user: response.user
@@ -1197,7 +1306,7 @@ class Widgets {
1197
1306
 
1198
1307
  if (typeof input === "function") {
1199
1308
  this.api.squatchReferralCookie().then((...args) => input(...args)).catch(ex => {
1200
- _log$2("Autofill error", ex);
1309
+ _log$3("Autofill error", ex);
1201
1310
 
1202
1311
  throw ex;
1203
1312
  });
@@ -1212,7 +1321,7 @@ class Widgets {
1212
1321
  // Only use the first element found
1213
1322
  elem = elems[0];
1214
1323
  } else {
1215
- _log$2("Element id/class or function missing");
1324
+ _log$3("Element id/class or function missing");
1216
1325
 
1217
1326
  throw new Error("Element id/class or function missing");
1218
1327
  }
@@ -1250,11 +1359,11 @@ class Widgets {
1250
1359
 
1251
1360
 
1252
1361
  _renderWidget(response, config, context) {
1253
- _log$2("Rendering Widget...");
1362
+ _log$3("Rendering Widget...");
1254
1363
 
1255
1364
  if (!response) throw new Error("Unable to get a response");
1256
1365
  let widget;
1257
- let displayOnLoad = false;
1366
+ let displayOnLoad = !!config.displayOnLoad;
1258
1367
  let displayCTA = false;
1259
1368
  const opts = response.jsOptions || "";
1260
1369
  const params = {
@@ -1273,9 +1382,9 @@ class Widgets {
1273
1382
  displayOnLoad = rule.displayOnLoad;
1274
1383
  displayCTA = rule.showAsCTA;
1275
1384
 
1276
- _log$2(`Display ${rule.widgetType} on ${rule.url}`);
1385
+ _log$3(`Display ${rule.widgetType} on ${rule.url}`);
1277
1386
  } else {
1278
- _log$2(`Don't display ${rule.widgetType} when no referral on widget rule match ${rule.url}`);
1387
+ _log$3(`Don't display ${rule.widgetType} when no referral on widget rule match ${rule.url}`);
1279
1388
  }
1280
1389
  }
1281
1390
  });
@@ -1284,20 +1393,20 @@ class Widgets {
1284
1393
  if (opts.conversionUrls) {
1285
1394
  opts.conversionUrls.forEach(rule => {
1286
1395
  if (response.user.referredBy && Widgets._matchesUrl(rule)) {
1287
- _log$2("This is a conversion URL", rule);
1396
+ _log$3("This is a conversion URL", rule);
1288
1397
  }
1289
1398
  });
1290
1399
  }
1291
1400
 
1292
1401
  if (opts.fuelTankAutofillUrls) {
1293
- _log$2("We found a fuel tank autofill!");
1402
+ _log$3("We found a fuel tank autofill!");
1294
1403
 
1295
1404
  opts.fuelTankAutofillUrls.forEach(({
1296
1405
  url,
1297
1406
  formSelector
1298
1407
  }) => {
1299
1408
  if (Widgets._matchesUrl(url)) {
1300
- _log$2("Fuel Tank URL matches");
1409
+ _log$3("Fuel Tank URL matches");
1301
1410
 
1302
1411
  if (response.user.referredBy && response.user.referredBy.code) {
1303
1412
  const formAutofill = document.querySelector(formSelector);
@@ -1305,7 +1414,7 @@ class Widgets {
1305
1414
  if (formAutofill) {
1306
1415
  formAutofill.value = response.user.referredBy.referredReward.fuelTankCode || "";
1307
1416
  } else {
1308
- _log$2(new Error(`Element with id/class ${formSelector} was not found.`));
1417
+ _log$3(new Error(`Element with id/class ${formSelector} was not found.`));
1309
1418
  }
1310
1419
  }
1311
1420
  }
@@ -1320,7 +1429,7 @@ class Widgets {
1320
1429
  widget.load();
1321
1430
  if (displayOnLoad) widget.open();
1322
1431
  } else if (displayCTA) {
1323
- _log$2("display CTA");
1432
+ _log$3("display CTA");
1324
1433
 
1325
1434
  const side = opts.cta.content.buttonSide;
1326
1435
  const position = opts.cta.content.buttonPosition;
@@ -1331,7 +1440,7 @@ class Widgets {
1331
1440
  widget.load();
1332
1441
  if (displayOnLoad) widget.open();
1333
1442
  } else {
1334
- _log$2("display popup on load");
1443
+ _log$3("display popup on load");
1335
1444
 
1336
1445
  widget = new PopupWidget(params);
1337
1446
  widget.load();
@@ -1355,7 +1464,7 @@ class Widgets {
1355
1464
  message
1356
1465
  } = props;
1357
1466
 
1358
- _log$2(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1467
+ _log$3(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1359
1468
 
1360
1469
  const params = {
1361
1470
  content: "error",
@@ -1495,7 +1604,8 @@ function asyncLoad() {
1495
1604
 
1496
1605
  if (loaded && cached) {
1497
1606
  const ready = cached.ready || [];
1498
- ready.forEach(cb => setTimeout(() => cb(), 0)); // @ts-ignore -- intetionally deletes `_squatch` to cleanup initialization
1607
+ ready.forEach(cb => setTimeout(() => cb(), 0));
1608
+ setTimeout(() => window.squatch._auto(), 0); // @ts-ignore -- intetionally deletes `_squatch` to cleanup initialization
1499
1609
 
1500
1610
  window._squatch = undefined;
1501
1611
 
@@ -1507,24 +1617,6 @@ function asyncLoad() {
1507
1617
  }
1508
1618
  }
1509
1619
 
1510
- function _extends() {
1511
- _extends = Object.assign || function (target) {
1512
- for (var i = 1; i < arguments.length; i++) {
1513
- var source = arguments[i];
1514
-
1515
- for (var key in source) {
1516
- if (Object.prototype.hasOwnProperty.call(source, key)) {
1517
- target[key] = source[key];
1518
- }
1519
- }
1520
- }
1521
-
1522
- return target;
1523
- };
1524
-
1525
- return _extends.apply(this, arguments);
1526
- }
1527
-
1528
1620
  /*! (c) Andrea Giammarchi - ISC */
1529
1621
  var self = undefined || /* istanbul ignore next */ {};
1530
1622
  try {
@@ -1903,7 +1995,7 @@ var URLSearchParams$1 = self.URLSearchParams;
1903
1995
 
1904
1996
  /** @hidden */
1905
1997
 
1906
- const _log$1 = debug__default("squatch-js");
1998
+ const _log$2 = debug__default("squatch-js");
1907
1999
 
1908
2000
  const isObject = item => typeof item === "object" && !Array.isArray(item);
1909
2001
 
@@ -1956,7 +2048,7 @@ function _pushCookie() {
1956
2048
  try {
1957
2049
  paramsJSON = JSON.parse(b64decode(refParam));
1958
2050
  } catch (error) {
1959
- _log$1("Unable to decode params", error); // don't merge invalid params
2051
+ _log$2("Unable to decode params", error); // don't merge invalid params
1960
2052
 
1961
2053
 
1962
2054
  return;
@@ -1965,26 +2057,26 @@ function _pushCookie() {
1965
2057
  try {
1966
2058
  existingCookie = JSON.parse(b64decode(Cookies.get("_saasquatch")));
1967
2059
 
1968
- _log$1("existing cookie", existingCookie);
2060
+ _log$2("existing cookie", existingCookie);
1969
2061
  } catch (error) {
1970
- _log$1("Unable to retrieve cookie", error);
2062
+ _log$2("Unable to retrieve cookie", error);
1971
2063
  } // don't merge if there's no existing object
1972
2064
 
1973
2065
 
1974
2066
  try {
1975
2067
  const domain = getTopDomain();
1976
2068
 
1977
- _log$1("domain retrieved:", domain);
2069
+ _log$2("domain retrieved:", domain);
1978
2070
 
1979
2071
  if (existingCookie) {
1980
2072
  const newCookie = deepMerge(existingCookie, paramsJSON);
1981
2073
  reEncodedCookie = b64encode(JSON.stringify(newCookie));
1982
2074
 
1983
- _log$1("cookie to store:", newCookie);
2075
+ _log$2("cookie to store:", newCookie);
1984
2076
  } else {
1985
2077
  reEncodedCookie = b64encode(JSON.stringify(paramsJSON));
1986
2078
 
1987
- _log$1("cookie to store:", paramsJSON);
2079
+ _log$2("cookie to store:", paramsJSON);
1988
2080
  }
1989
2081
 
1990
2082
  Cookies.set("_saasquatch", reEncodedCookie, {
@@ -1995,11 +2087,86 @@ function _pushCookie() {
1995
2087
  path: "/"
1996
2088
  });
1997
2089
  } catch (error) {
1998
- _log$1("Unable to set cookie", error);
2090
+ _log$2("Unable to set cookie", error);
1999
2091
  }
2000
2092
  }
2001
2093
  }
2002
2094
 
2095
+ /** @hidden */
2096
+
2097
+ const _log$1 = debug__default("squatch-js");
2098
+
2099
+ function _getAutoConfig(configIn) {
2100
+ const queryString = window.location.search;
2101
+ const urlParams = new URLSearchParams(queryString);
2102
+ const refParam = urlParams.get("_saasquatchExtra") || "";
2103
+
2104
+ if (!refParam) {
2105
+ _log$1("No _saasquatchExtra param");
2106
+
2107
+ return;
2108
+ }
2109
+
2110
+ let raw;
2111
+
2112
+ try {
2113
+ raw = JSON.parse(b64decode(refParam));
2114
+ } catch (e) {
2115
+ _log$1("Unable to decode _saasquatchExtra config");
2116
+
2117
+ return;
2118
+ }
2119
+
2120
+ const {
2121
+ domain,
2122
+ tenantAlias,
2123
+ widgetConfig
2124
+ } = convertExtraToConfig(raw);
2125
+
2126
+ if (!domain || !tenantAlias || !widgetConfig) {
2127
+ _log$1("_saasquatchExtra did not have an expected structure");
2128
+
2129
+ return undefined;
2130
+ }
2131
+
2132
+ const {
2133
+ autoPopupWidgetType
2134
+ } = widgetConfig,
2135
+ rest = _objectWithoutPropertiesLoose(widgetConfig, ["autoPopupWidgetType"]);
2136
+
2137
+ return {
2138
+ widgetConfig: _extends({
2139
+ widgetType: autoPopupWidgetType,
2140
+ displayOnLoad: true
2141
+ }, rest),
2142
+ squatchConfig: _extends({}, configIn ? {
2143
+ configIn
2144
+ } : {}, {
2145
+ domain,
2146
+ tenantAlias
2147
+ })
2148
+ };
2149
+ }
2150
+ /**
2151
+ * Deconstructs _saasquatchExtra into domain, tenantAlias, and widgetConfig
2152
+ * @param obj {Record<string, any>} Expected to be of the form `{ [appDomain]: { [tenantAlias]: { autoPopupWidgetType: [widgetType], [rest]?: ... } } }`
2153
+ */
2154
+
2155
+ function convertExtraToConfig(obj) {
2156
+ var _obj$_domain;
2157
+
2158
+ const _domain = Object.keys(obj || {})[0];
2159
+ const tenantAlias = Object.keys((obj == null ? void 0 : obj[_domain]) || {})[0];
2160
+ const widgetConfig = obj == null ? void 0 : (_obj$_domain = obj[_domain]) == null ? void 0 : _obj$_domain[tenantAlias]; // domain in _saasquatchExtra doesn't contain "https://"
2161
+
2162
+ const domain = _domain ? `https://${_domain}` : undefined;
2163
+ return {
2164
+ domain,
2165
+ tenantAlias,
2166
+ widgetConfig
2167
+ };
2168
+ }
2169
+
2003
2170
  // @ts-check
2004
2171
  function help() {
2005
2172
  console.log(`Having trouble using Squatch.js? Go to https://docs.referralsaasquatch.com/developer/ for tutorials, references and error codes.`);
@@ -2053,6 +2220,33 @@ function widgets() {
2053
2220
  function events() {
2054
2221
  return _events;
2055
2222
  }
2223
+ /**
2224
+ * Entry-point for high level API to render a widget using the instance of {@link Widgets} created when you call {@link #init init}.
2225
+ */
2226
+
2227
+ function widget(widgetConfig) {
2228
+ var _widgets2;
2229
+
2230
+ return (_widgets2 = widgets()) == null ? void 0 : _widgets2.render(widgetConfig);
2231
+ }
2232
+ /**
2233
+ * Extracts widget configuration from `_saasquatchExtra` UTM parameter. Initialises `squatch` and renders the widget as a {@link PopupWidget} via static instanct of {@link Widgets}.
2234
+ */
2235
+
2236
+ function _auto(configIn) {
2237
+ const configs = _getAutoConfig(configIn);
2238
+
2239
+ if (configs) {
2240
+ var _widgets3;
2241
+
2242
+ const {
2243
+ squatchConfig,
2244
+ widgetConfig
2245
+ } = configs;
2246
+ init(squatchConfig);
2247
+ return (_widgets3 = widgets()) == null ? void 0 : _widgets3.render(widgetConfig);
2248
+ }
2249
+ }
2056
2250
  /**
2057
2251
  * Initializes the static `squatch` global. This sets up:
2058
2252
  *
@@ -2095,7 +2289,7 @@ function init(configIn) {
2095
2289
  * @example
2096
2290
  * squatch.ready(function() {
2097
2291
  * console.log("ready!");
2098
- * squatch.api().cookieUser();
2292
+ * squatch.api().upsertUser();
2099
2293
  * });
2100
2294
  */
2101
2295
 
@@ -2157,5 +2351,5 @@ if (typeof document !== "undefined" && !window.SaaSquatchDoNotAutoDrop) {
2157
2351
 
2158
2352
  if (typeof document !== "undefined") asyncLoad();
2159
2353
 
2160
- export { CtaWidget, EmbedWidget, PopupWidget, WidgetApi, Widgets, api, autofill, events, help, init, pushCookie, ready, submitEmail, widgets };
2354
+ export { CtaWidget, EmbedWidget, PopupWidget, WidgetApi, Widgets, _auto, api, autofill, events, help, init, pushCookie, ready, submitEmail, widget, widgets };
2161
2355
  //# sourceMappingURL=squatch.esm.js.map