@saasquatch/squatch-js 2.4.3 → 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,8 +1,8 @@
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
6
 
7
7
  function _extends() {
8
8
  _extends = Object.assign || function (target) {
@@ -22,6 +22,45 @@ function _extends() {
22
22
  return _extends.apply(this, arguments);
23
23
  }
24
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
+ }
25
64
  function doGet(url, jwt = "") {
26
65
  const headers = {
27
66
  Accept: "application/json",
@@ -158,12 +197,37 @@ function validateConfig(raw) {
158
197
  npmCdn
159
198
  };
160
199
  }
200
+ function validateLocale(locale) {
201
+ if (locale && /^[a-z]{2}_(?:[A-Z]{2}|[0-9]{3})$/.test(locale)) {
202
+ return locale;
203
+ }
204
+ }
161
205
  function validateWidgetConfig(raw) {
162
206
  if (!isObject$1(raw)) throw new Error("Widget properties must be an object");
163
207
  if (!assertProp(raw, "user")) ; // TODO: This should be better type checked
164
208
 
165
209
  return raw;
166
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
+ `;
167
231
 
168
232
  /**
169
233
  *
@@ -196,39 +260,6 @@ class WidgetApi {
196
260
  this.domain = clean.domain;
197
261
  this.npmCdn = clean.npmCdn;
198
262
  }
199
- /**
200
- * Creates/upserts an anonymous user.
201
- *
202
- * @param {Object} params Parameters for request
203
- * @param {WidgetType} params.widgetType The content of the widget.
204
- * @param {EngagementMedium} params.engagementMedium How to display the widget.
205
- * @param {CookieUser} params.user An optional user object
206
- * @param {string} params.jwt the JSON Web Token (JWT) that is used to
207
- * validate the data (can be disabled)
208
- *
209
- * @return {Promise} json object if true, with the widget template, jsOptions and user details.
210
- */
211
-
212
-
213
- cookieUser(params) {
214
- // validateInput(params, CookieUserSchema);
215
- const {
216
- widgetType,
217
- engagementMedium = "POPUP",
218
- jwt,
219
- user
220
- } = params;
221
- const tenantAlias = encodeURIComponent(this.tenantAlias);
222
-
223
- const optionalParams = _buildParams({
224
- widgetType,
225
- engagementMedium
226
- });
227
-
228
- const path = `/api/v1/${tenantAlias}/widget/user/cookie_user${optionalParams}`;
229
- const url = this.domain + path;
230
- return doPut(url, JSON.stringify(user ? user : {}), jwt);
231
- }
232
263
  /**
233
264
  * Creates/upserts user.
234
265
  *
@@ -285,8 +316,10 @@ class WidgetApi {
285
316
 
286
317
 
287
318
  render(params) {
319
+ var _clean$locale;
320
+
288
321
  const raw = params;
289
- const clean = validateWidgetConfig(raw);
322
+ const clean = validatePasswordlessConfig(raw);
290
323
  const {
291
324
  widgetType,
292
325
  engagementMedium = "POPUP",
@@ -294,17 +327,29 @@ class WidgetApi {
294
327
  user
295
328
  } = clean;
296
329
  const tenantAlias = encodeURIComponent(this.tenantAlias);
297
- const accountId = encodeURIComponent(user.accountId);
298
- const userId = encodeURIComponent(user.id);
299
-
300
- const optionalParams = _buildParams({
301
- widgetType,
302
- engagementMedium
303
- });
304
-
305
- 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`;
306
334
  const url = this.domain + path;
307
- 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
+ });
308
353
  }
309
354
  /**
310
355
  * An API call to send out referral invites to contacts
@@ -395,6 +440,7 @@ class AnalyticsApi {
395
440
  }
396
441
 
397
442
  pushAnalyticsLoadEvent(params) {
443
+ if (!params.externalUserId || !params.externalAccountId) return;
398
444
  const tenantAlias = encodeURIComponent(params.tenantAlias);
399
445
  const accountId = encodeURIComponent(params.externalAccountId);
400
446
  const userId = encodeURIComponent(params.externalUserId);
@@ -421,7 +467,7 @@ class AnalyticsApi {
421
467
  // @ts-check
422
468
  /** @hidden */
423
469
 
424
- const _log$6 = debug__default("squatch-js:widget");
470
+ const _log$7 = debug__default("squatch-js:widget");
425
471
  /*
426
472
  * The Widget class is the base class for the different widget types available
427
473
  *
@@ -434,7 +480,7 @@ const _log$6 = debug__default("squatch-js:widget");
434
480
 
435
481
  class Widget {
436
482
  constructor(params) {
437
- _log$6("widget initializing ...");
483
+ _log$7("widget initializing ...");
438
484
 
439
485
  this.content = params.content === "error" ? this._error(params.rsCode) : params.content;
440
486
  this.type = params.type;
@@ -452,6 +498,8 @@ class Widget {
452
498
  }
453
499
 
454
500
  _loadEvent(sqh) {
501
+ var _this$analyticsApi$pu;
502
+
455
503
  if (!sqh) return; // No non-truthy value
456
504
 
457
505
  if (!isObject$1(sqh)) {
@@ -485,10 +533,10 @@ class Widget {
485
533
  };
486
534
  }
487
535
 
488
- this.analyticsApi.pushAnalyticsLoadEvent(params).then(response => {
489
- _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.`);
490
538
  }).catch(ex => {
491
- _log$6(new Error(`pushAnalyticsLoadEvent() ${ex}`));
539
+ _log$7(new Error(`pushAnalyticsLoadEvent() ${ex}`));
492
540
  });
493
541
  }
494
542
 
@@ -501,9 +549,9 @@ class Widget {
501
549
  engagementMedium: sqh.mode.widgetMode,
502
550
  shareMedium: medium
503
551
  }).then(response => {
504
- _log$6(`${sqh.mode.widgetMode} share ${medium} event recorded. ${response}`);
552
+ _log$7(`${sqh.mode.widgetMode} share ${medium} event recorded. ${response}`);
505
553
  }).catch(ex => {
506
- _log$6(new Error(`pushAnalyticsLoadEvent() ${ex}`));
554
+ _log$7(new Error(`pushAnalyticsLoadEvent() ${ex}`));
507
555
  });
508
556
  }
509
557
  }
@@ -516,9 +564,9 @@ class Widget {
516
564
  userId: sqh.analytics.attributes.userId,
517
565
  emailList
518
566
  }).then(response => {
519
- _log$6(`Sent email invites to share ${emailList}. ${response}`);
567
+ _log$7(`Sent email invites to share ${emailList}. ${response}`);
520
568
  }).catch(ex => {
521
- _log$6(new Error(`invite() ${ex}`));
569
+ _log$7(new Error(`invite() ${ex}`));
522
570
  });
523
571
  }
524
572
  }
@@ -607,6 +655,7 @@ class Widget {
607
655
  email: email || null,
608
656
  firstName: firstName || null,
609
657
  lastName: lastName || null,
658
+ // FIXME: Double check this
610
659
  id: this.context.user.id,
611
660
  accountId: this.context.user.accountId
612
661
  };
@@ -616,17 +665,12 @@ class Widget {
616
665
  widgetType: this.type,
617
666
  jwt
618
667
  });
619
- } else if (this.context.type === "cookie") {
620
- let userObj = {
621
- email: email || null,
622
- firstName: firstName || null,
623
- lastName: lastName || null
624
- };
625
- response = this.widgetApi.cookieUser({
626
- user: userObj,
668
+ } else if (this.context.type === "passwordless") {
669
+ response = this.widgetApi.render({
670
+ user: undefined,
627
671
  engagementMedium,
628
672
  widgetType: this.type,
629
- jwt
673
+ jwt: undefined
630
674
  });
631
675
  } else {
632
676
  throw new Error("can't reload an error widget");
@@ -662,7 +706,7 @@ class Widget {
662
706
  }).catch(({
663
707
  message
664
708
  }) => {
665
- _log$6(`${message}`);
709
+ _log$7(`${message}`);
666
710
  });
667
711
  }
668
712
 
@@ -699,7 +743,7 @@ function domready(targetDoc, fn) {
699
743
 
700
744
  // @ts-check
701
745
 
702
- const _log$5 = debug__default("squatch-js:EMBEDwidget");
746
+ const _log$6 = debug__default("squatch-js:EMBEDwidget");
703
747
  /**
704
748
  * An EmbedWidget is displayed inline in part of your page.
705
749
  *
@@ -717,22 +761,22 @@ class EmbedWidget extends Widget {
717
761
  // selector is a string
718
762
  element = document.querySelector(container);
719
763
 
720
- _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
721
765
 
722
766
  } else if (container instanceof HTMLElement) {
723
767
  element = container;
724
768
 
725
- _log$5("loading widget with container", element); // garbage container found
769
+ _log$6("loading widget with container", element); // garbage container found
726
770
 
727
771
  } else if (container) {
728
772
  element = null;
729
773
 
730
- _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
731
775
 
732
776
  } else {
733
777
  element = document.querySelector("#squatchembed") || document.querySelector(".squatchembed");
734
778
 
735
- _log$5("loading widget with default selector", element);
779
+ _log$6("loading widget with default selector", element);
736
780
  }
737
781
 
738
782
  if (!(element instanceof HTMLElement)) throw new Error(`element with selector '${container}' not found.'`);
@@ -798,7 +842,7 @@ class EmbedWidget extends Widget {
798
842
  if (!this.context.container) {
799
843
  this._loadEvent(_sqh);
800
844
 
801
- _log$5("loaded");
845
+ _log$6("loaded");
802
846
  }
803
847
  });
804
848
  } // Un-hide if element is available and refresh data
@@ -807,7 +851,7 @@ class EmbedWidget extends Widget {
807
851
  open() {
808
852
  var _this$frame, _this$frame$contentDo, _this$frame2, _this$frame2$contentW, _this$frame3, _this$frame3$contentW;
809
853
 
810
- if (!this.frame) return _log$5("no target element to open");
854
+ if (!this.frame) return _log$6("no target element to open");
811
855
  this.element.style.visibility = "unset";
812
856
  this.element.style.height = "auto";
813
857
  this.element.style["overflow-y"] = "auto";
@@ -817,16 +861,16 @@ class EmbedWidget extends Widget {
817
861
 
818
862
  this._loadEvent(_sqh);
819
863
 
820
- _log$5("loaded");
864
+ _log$6("loaded");
821
865
  }
822
866
 
823
867
  close() {
824
- if (!this.frame) return _log$5("no target element to close");
868
+ if (!this.frame) return _log$6("no target element to close");
825
869
  this.element.style.visibility = "hidden";
826
870
  this.element.style.height = "0";
827
871
  this.element.style["overflow-y"] = "hidden";
828
872
 
829
- _log$5("Embed widget closed");
873
+ _log$6("Embed widget closed");
830
874
  }
831
875
 
832
876
  _error(rs, mode = "embed", style = "") {
@@ -837,7 +881,7 @@ class EmbedWidget extends Widget {
837
881
 
838
882
  // @ts-check
839
883
 
840
- const _log$4 = debug__default("squatch-js:POPUPwidget");
884
+ const _log$5 = debug__default("squatch-js:POPUPwidget");
841
885
  /**
842
886
  * The PopupWidget is used to display popups (also known as "Modals").
843
887
  * Popups widgets are rendered on top of other elements in a page.
@@ -855,9 +899,9 @@ class PopupWidget extends Widget {
855
899
  this.triggerElement
856
900
  /* HTMLButton */
857
901
  = document.querySelector(trigger);
858
- 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);
859
903
  } catch (_unused) {
860
- _log$4("Not a valid selector", trigger);
904
+ _log$5("Not a valid selector", trigger);
861
905
  } // Trigger is optional
862
906
 
863
907
 
@@ -880,6 +924,7 @@ class PopupWidget extends Widget {
880
924
  this.popupdiv = document.createElement("div");
881
925
  this.popupdiv.id = "squatchModal";
882
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>`);
883
928
  this.popupcontent = document.createElement("div");
884
929
  this.popupcontent.setAttribute("style", "margin: auto; width: 80%; max-width: 500px; position: relative;");
885
930
 
@@ -899,7 +944,7 @@ class PopupWidget extends Widget {
899
944
  frameDoc.write(`<script src="${this.npmCdn}/resize-observer-polyfill@1.5.x"></script>`);
900
945
  frameDoc.close();
901
946
 
902
- _log$4("Popup template loaded into iframe");
947
+ _log$5("Popup template loaded into iframe");
903
948
 
904
949
  this._setupResizeHandler();
905
950
  }
@@ -972,7 +1017,7 @@ class PopupWidget extends Widget {
972
1017
 
973
1018
  this._loadEvent(_sqh);
974
1019
 
975
- _log$4("Popup opened");
1020
+ _log$5("Popup opened");
976
1021
  });
977
1022
  }
978
1023
 
@@ -980,7 +1025,7 @@ class PopupWidget extends Widget {
980
1025
  this.popupdiv.style.visibility = "hidden";
981
1026
  this.popupdiv.style.top = "-2000px";
982
1027
 
983
- _log$4("Popup closed");
1028
+ _log$5("Popup closed");
984
1029
  }
985
1030
 
986
1031
  _clickedOutside({
@@ -998,7 +1043,7 @@ class PopupWidget extends Widget {
998
1043
 
999
1044
  }
1000
1045
 
1001
- const _log$3 = debug("squatch-js:CTAwidget");
1046
+ const _log$4 = debug("squatch-js:CTAwidget");
1002
1047
  /**
1003
1048
  * A CtaWidget is displayed on top of your page
1004
1049
  *
@@ -1009,7 +1054,7 @@ const _log$3 = debug("squatch-js:CTAwidget");
1009
1054
 
1010
1055
  class CtaWidget extends PopupWidget {
1011
1056
  constructor(params, opts) {
1012
- _log$3("CTA constructor");
1057
+ _log$4("CTA constructor");
1013
1058
 
1014
1059
  const ctaElement = document.createElement("div");
1015
1060
  ctaElement.id = "cta";
@@ -1037,7 +1082,7 @@ class CtaWidget extends PopupWidget {
1037
1082
  this.ctaFrame.setAttribute("style", `border:0; background-color:transparent; position:fixed; display:none;${this.side}${this.position}`);
1038
1083
  document.body.appendChild(this.ctaFrame);
1039
1084
 
1040
- _log$3("ctaframe appended to body");
1085
+ _log$4("ctaframe appended to body");
1041
1086
  }
1042
1087
 
1043
1088
  load() {
@@ -1101,10 +1146,10 @@ class CtaWidget extends PopupWidget {
1101
1146
  });
1102
1147
  ro.observe(ctaContainer);
1103
1148
 
1104
- _log$3("CTA template loaded into iframe");
1149
+ _log$4("CTA template loaded into iframe");
1105
1150
  });
1106
1151
  } else {
1107
- _log$3(new Error("CTA element not found in theme"));
1152
+ _log$4(new Error("CTA element not found in theme"));
1108
1153
  }
1109
1154
  });
1110
1155
  }
@@ -1127,7 +1172,7 @@ class CtaWidget extends PopupWidget {
1127
1172
 
1128
1173
  }
1129
1174
 
1130
- const _log$2 = debug__default("squatch-js:widgets");
1175
+ const _log$3 = debug__default("squatch-js:widgets");
1131
1176
  /**
1132
1177
  *
1133
1178
  * `Widgets` is a factory for creating widgets. It's possible to build your own widgets using the
@@ -1165,41 +1210,6 @@ class Widgets {
1165
1210
 
1166
1211
  EventBus.addEventListener("submit_email", Widgets._cb);
1167
1212
  }
1168
- /**
1169
- * This function calls the {@link WidgetApi.cookieUser} method, and it renders
1170
- * the widget if it is successful. Otherwise it shows the "error" widget.
1171
- *
1172
- * @param {Object} config Config details
1173
- * @param {WidgetType} config.widgetType The content of the widget.
1174
- * @param {EngagementMedium} config.engagementMedium How to display the widget.
1175
- * @param {User} config.user An optional user to include
1176
- * @param {string} config.jwt the JSON Web Token (JWT) that is used to
1177
- * validate the data (can be disabled)
1178
- *
1179
- * @return {Promise<WidgetResult>} json object if true, with a Widget and user details.
1180
- */
1181
-
1182
-
1183
- async createCookieUser(config) {
1184
- try {
1185
- const response = await this.api.cookieUser(config);
1186
- return {
1187
- widget: this._renderWidget(response, config, {
1188
- type: "cookie",
1189
- engagementMedium: config.engagementMedium
1190
- }),
1191
- user: response.user
1192
- };
1193
- } catch (err) {
1194
- _log$2(err);
1195
-
1196
- if (err.apiErrorCode) {
1197
- this._renderErrorWidget(err, config.engagementMedium);
1198
- }
1199
-
1200
- throw err;
1201
- }
1202
- }
1203
1213
  /**
1204
1214
  * This function calls the {@link WidgetApi.upsertUser} method, and it renders
1205
1215
  * the widget if it is successful. Otherwise it shows the "error" widget.
@@ -1227,7 +1237,7 @@ class Widgets {
1227
1237
  return {
1228
1238
  widget: this._renderWidget(response, clean, {
1229
1239
  type: "upsert",
1230
- user: clean.user,
1240
+ user: clean.user || null,
1231
1241
  engagementMedium: config.engagementMedium,
1232
1242
  container: config.container,
1233
1243
  trigger: config.trigger
@@ -1235,7 +1245,7 @@ class Widgets {
1235
1245
  user: response.user
1236
1246
  };
1237
1247
  } catch (err) {
1238
- _log$2(err);
1248
+ _log$3(err);
1239
1249
 
1240
1250
  if (err.apiErrorCode) {
1241
1251
  this._renderErrorWidget(err, config.engagementMedium);
@@ -1263,15 +1273,13 @@ class Widgets {
1263
1273
 
1264
1274
  async render(config) {
1265
1275
  const raw = config;
1266
- const clean = validateWidgetConfig(raw);
1276
+ const clean = validatePasswordlessConfig(raw);
1267
1277
 
1268
1278
  try {
1269
- const response = await this.api.cookieUser(clean);
1279
+ const response = await this.api.render(clean);
1270
1280
  return {
1271
- widget: this._renderWidget({
1272
- template: response
1273
- }, clean, {
1274
- type: "cookie",
1281
+ widget: this._renderWidget(response, clean, {
1282
+ type: "passwordless",
1275
1283
  engagementMedium: clean.engagementMedium
1276
1284
  }),
1277
1285
  user: response.user
@@ -1298,7 +1306,7 @@ class Widgets {
1298
1306
 
1299
1307
  if (typeof input === "function") {
1300
1308
  this.api.squatchReferralCookie().then((...args) => input(...args)).catch(ex => {
1301
- _log$2("Autofill error", ex);
1309
+ _log$3("Autofill error", ex);
1302
1310
 
1303
1311
  throw ex;
1304
1312
  });
@@ -1313,7 +1321,7 @@ class Widgets {
1313
1321
  // Only use the first element found
1314
1322
  elem = elems[0];
1315
1323
  } else {
1316
- _log$2("Element id/class or function missing");
1324
+ _log$3("Element id/class or function missing");
1317
1325
 
1318
1326
  throw new Error("Element id/class or function missing");
1319
1327
  }
@@ -1351,11 +1359,11 @@ class Widgets {
1351
1359
 
1352
1360
 
1353
1361
  _renderWidget(response, config, context) {
1354
- _log$2("Rendering Widget...");
1362
+ _log$3("Rendering Widget...");
1355
1363
 
1356
1364
  if (!response) throw new Error("Unable to get a response");
1357
1365
  let widget;
1358
- let displayOnLoad = false;
1366
+ let displayOnLoad = !!config.displayOnLoad;
1359
1367
  let displayCTA = false;
1360
1368
  const opts = response.jsOptions || "";
1361
1369
  const params = {
@@ -1374,9 +1382,9 @@ class Widgets {
1374
1382
  displayOnLoad = rule.displayOnLoad;
1375
1383
  displayCTA = rule.showAsCTA;
1376
1384
 
1377
- _log$2(`Display ${rule.widgetType} on ${rule.url}`);
1385
+ _log$3(`Display ${rule.widgetType} on ${rule.url}`);
1378
1386
  } else {
1379
- _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}`);
1380
1388
  }
1381
1389
  }
1382
1390
  });
@@ -1385,20 +1393,20 @@ class Widgets {
1385
1393
  if (opts.conversionUrls) {
1386
1394
  opts.conversionUrls.forEach(rule => {
1387
1395
  if (response.user.referredBy && Widgets._matchesUrl(rule)) {
1388
- _log$2("This is a conversion URL", rule);
1396
+ _log$3("This is a conversion URL", rule);
1389
1397
  }
1390
1398
  });
1391
1399
  }
1392
1400
 
1393
1401
  if (opts.fuelTankAutofillUrls) {
1394
- _log$2("We found a fuel tank autofill!");
1402
+ _log$3("We found a fuel tank autofill!");
1395
1403
 
1396
1404
  opts.fuelTankAutofillUrls.forEach(({
1397
1405
  url,
1398
1406
  formSelector
1399
1407
  }) => {
1400
1408
  if (Widgets._matchesUrl(url)) {
1401
- _log$2("Fuel Tank URL matches");
1409
+ _log$3("Fuel Tank URL matches");
1402
1410
 
1403
1411
  if (response.user.referredBy && response.user.referredBy.code) {
1404
1412
  const formAutofill = document.querySelector(formSelector);
@@ -1406,7 +1414,7 @@ class Widgets {
1406
1414
  if (formAutofill) {
1407
1415
  formAutofill.value = response.user.referredBy.referredReward.fuelTankCode || "";
1408
1416
  } else {
1409
- _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.`));
1410
1418
  }
1411
1419
  }
1412
1420
  }
@@ -1421,7 +1429,7 @@ class Widgets {
1421
1429
  widget.load();
1422
1430
  if (displayOnLoad) widget.open();
1423
1431
  } else if (displayCTA) {
1424
- _log$2("display CTA");
1432
+ _log$3("display CTA");
1425
1433
 
1426
1434
  const side = opts.cta.content.buttonSide;
1427
1435
  const position = opts.cta.content.buttonPosition;
@@ -1432,7 +1440,7 @@ class Widgets {
1432
1440
  widget.load();
1433
1441
  if (displayOnLoad) widget.open();
1434
1442
  } else {
1435
- _log$2("display popup on load");
1443
+ _log$3("display popup on load");
1436
1444
 
1437
1445
  widget = new PopupWidget(params);
1438
1446
  widget.load();
@@ -1456,7 +1464,7 @@ class Widgets {
1456
1464
  message
1457
1465
  } = props;
1458
1466
 
1459
- _log$2(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1467
+ _log$3(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1460
1468
 
1461
1469
  const params = {
1462
1470
  content: "error",
@@ -1596,7 +1604,8 @@ function asyncLoad() {
1596
1604
 
1597
1605
  if (loaded && cached) {
1598
1606
  const ready = cached.ready || [];
1599
- 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
1600
1609
 
1601
1610
  window._squatch = undefined;
1602
1611
 
@@ -1986,7 +1995,7 @@ var URLSearchParams$1 = self.URLSearchParams;
1986
1995
 
1987
1996
  /** @hidden */
1988
1997
 
1989
- const _log$1 = debug__default("squatch-js");
1998
+ const _log$2 = debug__default("squatch-js");
1990
1999
 
1991
2000
  const isObject = item => typeof item === "object" && !Array.isArray(item);
1992
2001
 
@@ -2039,7 +2048,7 @@ function _pushCookie() {
2039
2048
  try {
2040
2049
  paramsJSON = JSON.parse(b64decode(refParam));
2041
2050
  } catch (error) {
2042
- _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
2043
2052
 
2044
2053
 
2045
2054
  return;
@@ -2048,26 +2057,26 @@ function _pushCookie() {
2048
2057
  try {
2049
2058
  existingCookie = JSON.parse(b64decode(Cookies.get("_saasquatch")));
2050
2059
 
2051
- _log$1("existing cookie", existingCookie);
2060
+ _log$2("existing cookie", existingCookie);
2052
2061
  } catch (error) {
2053
- _log$1("Unable to retrieve cookie", error);
2062
+ _log$2("Unable to retrieve cookie", error);
2054
2063
  } // don't merge if there's no existing object
2055
2064
 
2056
2065
 
2057
2066
  try {
2058
2067
  const domain = getTopDomain();
2059
2068
 
2060
- _log$1("domain retrieved:", domain);
2069
+ _log$2("domain retrieved:", domain);
2061
2070
 
2062
2071
  if (existingCookie) {
2063
2072
  const newCookie = deepMerge(existingCookie, paramsJSON);
2064
2073
  reEncodedCookie = b64encode(JSON.stringify(newCookie));
2065
2074
 
2066
- _log$1("cookie to store:", newCookie);
2075
+ _log$2("cookie to store:", newCookie);
2067
2076
  } else {
2068
2077
  reEncodedCookie = b64encode(JSON.stringify(paramsJSON));
2069
2078
 
2070
- _log$1("cookie to store:", paramsJSON);
2079
+ _log$2("cookie to store:", paramsJSON);
2071
2080
  }
2072
2081
 
2073
2082
  Cookies.set("_saasquatch", reEncodedCookie, {
@@ -2078,11 +2087,86 @@ function _pushCookie() {
2078
2087
  path: "/"
2079
2088
  });
2080
2089
  } catch (error) {
2081
- _log$1("Unable to set cookie", error);
2090
+ _log$2("Unable to set cookie", error);
2082
2091
  }
2083
2092
  }
2084
2093
  }
2085
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
+
2086
2170
  // @ts-check
2087
2171
  function help() {
2088
2172
  console.log(`Having trouble using Squatch.js? Go to https://docs.referralsaasquatch.com/developer/ for tutorials, references and error codes.`);
@@ -2136,6 +2220,33 @@ function widgets() {
2136
2220
  function events() {
2137
2221
  return _events;
2138
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
+ }
2139
2250
  /**
2140
2251
  * Initializes the static `squatch` global. This sets up:
2141
2252
  *
@@ -2178,7 +2289,7 @@ function init(configIn) {
2178
2289
  * @example
2179
2290
  * squatch.ready(function() {
2180
2291
  * console.log("ready!");
2181
- * squatch.api().cookieUser();
2292
+ * squatch.api().upsertUser();
2182
2293
  * });
2183
2294
  */
2184
2295
 
@@ -2240,5 +2351,5 @@ if (typeof document !== "undefined" && !window.SaaSquatchDoNotAutoDrop) {
2240
2351
 
2241
2352
  if (typeof document !== "undefined") asyncLoad();
2242
2353
 
2243
- 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 };
2244
2355
  //# sourceMappingURL=squatch.esm.js.map