@tiquo/dom-package 1.5.1 → 1.5.2

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/dist/index.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ TiquoAnalytics: () => TiquoAnalytics,
23
24
  TiquoAuth: () => TiquoAuth,
24
25
  TiquoAuthError: () => TiquoAuthError,
25
26
  TiquoCMS: () => TiquoCMS,
@@ -678,8 +679,258 @@ function printTiquoBranding() {
678
679
  }
679
680
  }
680
681
  printTiquoBranding();
682
+ var ANALYTICS_LOCATION_EVENT = "tiquo:locationchange";
683
+ var analyticsHistoryPatched = false;
684
+ function randomId() {
685
+ try {
686
+ if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
687
+ return crypto.randomUUID();
688
+ }
689
+ } catch {
690
+ }
691
+ return `ev_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
692
+ }
693
+ function normalizeHostname(hostname) {
694
+ if (!hostname) return void 0;
695
+ const clean = hostname.trim().toLowerCase().split(":")[0];
696
+ return clean.startsWith("www.") ? clean.slice(4) : clean;
697
+ }
698
+ function getBrowser() {
699
+ if (typeof navigator === "undefined") return "Other";
700
+ const ua = navigator.userAgent;
701
+ if (/Edg(e|A|iOS)?\//i.test(ua)) return "Edge";
702
+ if (/Firefox\//i.test(ua)) return "Firefox";
703
+ if (/Chrome\/|CriOS\//i.test(ua)) return "Chrome";
704
+ if (/Safari\//i.test(ua) && !/Chrome/i.test(ua)) return "Safari";
705
+ return "Other";
706
+ }
707
+ function getDevice() {
708
+ if (typeof navigator === "undefined") return "Desktop";
709
+ const ua = navigator.userAgent;
710
+ if (/iPad|tablet|PlayBook|Silk/i.test(ua)) return "Tablet";
711
+ if (/Android(?!.*Mobile)/i.test(ua) && /Android/i.test(ua) && !/Mobile/i.test(ua))
712
+ return "Tablet";
713
+ if (/Mobile|iPhone|iPod|Android.*Mobile|webOS|BlackBerry|Opera Mini|IEMobile/i.test(
714
+ ua
715
+ ))
716
+ return "Mobile";
717
+ return "Desktop";
718
+ }
719
+ function getOperatingSystem() {
720
+ if (typeof navigator === "undefined") return "Other";
721
+ const ua = navigator.userAgent;
722
+ if (/iPhone|iPad|iPod/i.test(ua)) return "iOS";
723
+ if (/Android/i.test(ua)) return "Android";
724
+ if (/CrOS/i.test(ua)) return "Chrome OS";
725
+ if (/Windows/i.test(ua)) return "Windows";
726
+ if (/Macintosh|Mac OS X/i.test(ua)) return "macOS";
727
+ if (/Linux/i.test(ua)) return "Linux";
728
+ return "Other";
729
+ }
730
+ function getUtmParams() {
731
+ if (typeof window === "undefined") return {};
732
+ const params = new URLSearchParams(window.location.search);
733
+ return {
734
+ source: params.get("utm_source") || void 0,
735
+ medium: params.get("utm_medium") || void 0,
736
+ campaign: params.get("utm_campaign") || void 0,
737
+ content: params.get("utm_content") || void 0,
738
+ term: params.get("utm_term") || void 0
739
+ };
740
+ }
741
+ function patchHistoryForAnalytics() {
742
+ if (analyticsHistoryPatched || typeof window === "undefined") return;
743
+ analyticsHistoryPatched = true;
744
+ const notify = () => {
745
+ window.dispatchEvent(
746
+ new Event(ANALYTICS_LOCATION_EVENT)
747
+ );
748
+ };
749
+ const pushState = history.pushState;
750
+ history.pushState = function patchedPushState(...args) {
751
+ const result = pushState.apply(this, args);
752
+ notify();
753
+ return result;
754
+ };
755
+ const replaceState = history.replaceState;
756
+ history.replaceState = function patchedReplaceState(...args) {
757
+ const result = replaceState.apply(this, args);
758
+ notify();
759
+ return result;
760
+ };
761
+ window.addEventListener("popstate", notify);
762
+ }
763
+ var _TiquoAnalytics = class _TiquoAnalytics {
764
+ constructor(config) {
765
+ this.pageStartedAt = Date.now();
766
+ this.lastPath = null;
767
+ this.started = false;
768
+ if (!config.publicKey) {
769
+ throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
770
+ }
771
+ if (!config.publicKey.startsWith("pk_dom_")) {
772
+ throw new TiquoAuthError(
773
+ "Invalid public key format. Expected pk_dom_xxx",
774
+ "INVALID_PUBLIC_KEY"
775
+ );
776
+ }
777
+ this.config = {
778
+ publicKey: config.publicKey,
779
+ apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
780
+ debug: config.debug || false,
781
+ autoTrackPageviews: config.autoTrackPageviews !== false,
782
+ getAccessToken: config.getAccessToken,
783
+ siteSlug: config.siteSlug
784
+ };
785
+ this.clientSessionId = this.getClientSessionId();
786
+ if (this.config.autoTrackPageviews) {
787
+ this.start();
788
+ }
789
+ }
790
+ start() {
791
+ if (this.started || typeof window === "undefined") return;
792
+ const activeKey = `${this.config.publicKey}:${this.config.siteSlug || ""}`;
793
+ const existing = _TiquoAnalytics.activeInstances.get(activeKey);
794
+ if (existing && existing !== this) {
795
+ existing.adoptConfig(this.config);
796
+ return;
797
+ }
798
+ _TiquoAnalytics.activeInstances.set(activeKey, this);
799
+ this.started = true;
800
+ patchHistoryForAnalytics();
801
+ this.trackPageview();
802
+ window.addEventListener(
803
+ ANALYTICS_LOCATION_EVENT,
804
+ () => this.trackPageview()
805
+ );
806
+ window.addEventListener("pagehide", () => this.trackEngagement());
807
+ document.addEventListener("visibilitychange", () => {
808
+ if (document.visibilityState === "hidden") this.trackEngagement();
809
+ });
810
+ }
811
+ async trackPageview(options = {}) {
812
+ if (typeof window === "undefined") return;
813
+ const path = options.path || `${window.location.pathname}${window.location.search}`;
814
+ if (path === this.lastPath) return;
815
+ if (this.lastPath) {
816
+ this.trackEngagement().catch(() => void 0);
817
+ }
818
+ this.lastPath = path;
819
+ this.pageStartedAt = Date.now();
820
+ await this.track("pageview", {
821
+ ...options,
822
+ path,
823
+ url: options.url || window.location.href,
824
+ title: options.title || document.title,
825
+ referrer: options.referrer || document.referrer || void 0
826
+ });
827
+ }
828
+ async track(eventType, options = {}) {
829
+ if (typeof window === "undefined") return;
830
+ const utm = getUtmParams();
831
+ const payload = {
832
+ publicKey: this.config.publicKey,
833
+ eventId: randomId(),
834
+ eventType,
835
+ eventName: options.eventName,
836
+ eventProperties: options.eventProperties,
837
+ clientSessionId: this.clientSessionId,
838
+ siteSlug: options.siteSlug || this.config.siteSlug,
839
+ pageSlug: options.pageSlug,
840
+ hostname: normalizeHostname(window.location.hostname),
841
+ path: options.path || `${window.location.pathname}${window.location.search}`,
842
+ url: options.url || window.location.href,
843
+ title: options.title || document.title,
844
+ referrer: options.referrer || document.referrer || void 0,
845
+ timestamp: Date.now(),
846
+ browser: getBrowser(),
847
+ device: getDevice(),
848
+ operatingSystem: getOperatingSystem(),
849
+ language: navigator.language,
850
+ screenWidth: window.screen?.width,
851
+ screenHeight: window.screen?.height,
852
+ viewportWidth: window.innerWidth,
853
+ viewportHeight: window.innerHeight,
854
+ durationMs: options.durationMs,
855
+ scrollDepth: options.scrollDepth,
856
+ identityLinkType: options.identityLinkType,
857
+ ...utm
858
+ };
859
+ await this.send(payload);
860
+ }
861
+ async identify(options = {}) {
862
+ await this.track("identify", {
863
+ ...options,
864
+ identityLinkType: options.identityLinkType || "auth_dom_login"
865
+ });
866
+ }
867
+ async trackEngagement() {
868
+ if (typeof window === "undefined" || !this.lastPath) return;
869
+ const durationMs = Date.now() - this.pageStartedAt;
870
+ const scrollHeight = Math.max(
871
+ document.documentElement.scrollHeight,
872
+ document.body?.scrollHeight || 0,
873
+ window.innerHeight
874
+ );
875
+ const scrollDepth = scrollHeight > 0 ? Math.min(1, (window.scrollY + window.innerHeight) / scrollHeight) : void 0;
876
+ await this.track("engagement", {
877
+ path: this.lastPath,
878
+ durationMs,
879
+ scrollDepth
880
+ });
881
+ }
882
+ async send(payload) {
883
+ const headers = {
884
+ "Content-Type": "text/plain;charset=UTF-8",
885
+ "X-Public-Key": this.config.publicKey
886
+ };
887
+ const accessToken = this.config.getAccessToken?.();
888
+ if (accessToken) {
889
+ headers.Authorization = `Bearer ${accessToken}`;
890
+ }
891
+ try {
892
+ await fetch(`${this.config.apiEndpoint}/api/dom-analytics/event`, {
893
+ method: "POST",
894
+ headers,
895
+ credentials: "include",
896
+ keepalive: true,
897
+ body: JSON.stringify(payload)
898
+ });
899
+ } catch (error) {
900
+ this.log("Analytics event failed:", error);
901
+ }
902
+ }
903
+ getClientSessionId() {
904
+ const key = `tiquo_analytics_session_${this.config.publicKey}`;
905
+ try {
906
+ const existing = sessionStorage.getItem(key);
907
+ if (existing) return existing;
908
+ const next = randomId();
909
+ sessionStorage.setItem(key, next);
910
+ return next;
911
+ } catch {
912
+ return randomId();
913
+ }
914
+ }
915
+ log(...args) {
916
+ if (this.config.debug) {
917
+ console.log("[TiquoAnalytics]", ...args);
918
+ }
919
+ }
920
+ adoptConfig(nextConfig) {
921
+ if (nextConfig.getAccessToken) {
922
+ this.config.getAccessToken = nextConfig.getAccessToken;
923
+ }
924
+ if (nextConfig.siteSlug && !this.config.siteSlug) {
925
+ this.config.siteSlug = nextConfig.siteSlug;
926
+ }
927
+ }
928
+ };
929
+ _TiquoAnalytics.activeInstances = /* @__PURE__ */ new Map();
930
+ var TiquoAnalytics = _TiquoAnalytics;
681
931
  var TiquoCMS = class {
682
932
  constructor(config) {
933
+ this.analytics = null;
683
934
  if (!config.publicKey) {
684
935
  throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
685
936
  }
@@ -692,8 +943,16 @@ var TiquoCMS = class {
692
943
  this.config = {
693
944
  publicKey: config.publicKey,
694
945
  apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
695
- debug: config.debug || false
946
+ debug: config.debug || false,
947
+ analytics: config.analytics !== false
696
948
  };
949
+ if (this.config.analytics) {
950
+ this.analytics = new TiquoAnalytics({
951
+ publicKey: this.config.publicKey,
952
+ apiEndpoint: this.config.apiEndpoint,
953
+ debug: this.config.debug
954
+ });
955
+ }
697
956
  }
698
957
  /**
699
958
  * Fetch a published CMS page for the website attached to this public key.
@@ -702,19 +961,22 @@ var TiquoCMS = class {
702
961
  * Convex connection details to the consuming website.
703
962
  */
704
963
  async getPage(request) {
705
- const response = await fetch(`${this.config.apiEndpoint}/api/dom-cms/page`, {
706
- method: "POST",
707
- headers: {
708
- "Content-Type": "text/plain;charset=UTF-8"
709
- },
710
- credentials: "include",
711
- body: JSON.stringify({
712
- publicKey: this.config.publicKey,
713
- siteSlug: request.siteSlug,
714
- pageSlug: request.pageSlug || "home",
715
- templateId: request.templateId
716
- })
717
- });
964
+ const response = await fetch(
965
+ `${this.config.apiEndpoint}/api/dom-cms/page`,
966
+ {
967
+ method: "POST",
968
+ headers: {
969
+ "Content-Type": "text/plain;charset=UTF-8"
970
+ },
971
+ credentials: "include",
972
+ body: JSON.stringify({
973
+ publicKey: this.config.publicKey,
974
+ siteSlug: request.siteSlug,
975
+ pageSlug: request.pageSlug || "home",
976
+ templateId: request.templateId
977
+ })
978
+ }
979
+ );
718
980
  if (response.status === 404) {
719
981
  return null;
720
982
  }
@@ -725,7 +987,11 @@ var TiquoCMS = class {
725
987
  if (typeof error?.error === "string") message = error.error;
726
988
  } catch {
727
989
  }
728
- throw new TiquoAuthError(message, "CMS_PAGE_FETCH_FAILED", response.status);
990
+ throw new TiquoAuthError(
991
+ message,
992
+ "CMS_PAGE_FETCH_FAILED",
993
+ response.status
994
+ );
729
995
  }
730
996
  const result = await response.json();
731
997
  if (!result?.success || !result?.data) {
@@ -777,6 +1043,7 @@ var TiquoAuth = class {
777
1043
  this.visibilityHandler = null;
778
1044
  this.iframeObserver = null;
779
1045
  this.injectedIframes = /* @__PURE__ */ new WeakSet();
1046
+ this.analytics = null;
780
1047
  // Multi-tab sync
781
1048
  this.broadcastChannel = null;
782
1049
  this.isProcessingTabSync = false;
@@ -797,10 +1064,19 @@ var TiquoAuth = class {
797
1064
  debug: config.debug || false,
798
1065
  enableTabSync: config.enableTabSync !== false,
799
1066
  // Default true
1067
+ analytics: config.analytics !== false,
800
1068
  accessToken: config.accessToken,
801
1069
  refreshToken: config.refreshToken
802
1070
  };
803
1071
  this.tabId = this.generateTabId();
1072
+ if (this.config.analytics) {
1073
+ this.analytics = new TiquoAnalytics({
1074
+ publicKey: this.config.publicKey,
1075
+ apiEndpoint: this.config.apiEndpoint,
1076
+ debug: this.config.debug,
1077
+ getAccessToken: () => this.accessToken
1078
+ });
1079
+ }
804
1080
  if (this.config.enableTabSync) {
805
1081
  this.initTabSync();
806
1082
  }
@@ -826,7 +1102,11 @@ var TiquoAuth = class {
826
1102
  });
827
1103
  if (!response.ok) {
828
1104
  const error = await response.json().catch(() => ({ error: "Failed to send OTP" }));
829
- throw new TiquoAuthError(error.error || "Failed to send OTP", "OTP_SEND_FAILED", response.status);
1105
+ throw new TiquoAuthError(
1106
+ error.error || "Failed to send OTP",
1107
+ "OTP_SEND_FAILED",
1108
+ response.status
1109
+ );
830
1110
  }
831
1111
  const result = await response.json();
832
1112
  return {
@@ -849,7 +1129,11 @@ var TiquoAuth = class {
849
1129
  });
850
1130
  if (!response.ok) {
851
1131
  const error = await response.json().catch(() => ({ error: "Invalid OTP" }));
852
- throw new TiquoAuthError(error.error || "Invalid OTP", "OTP_VERIFY_FAILED", response.status);
1132
+ throw new TiquoAuthError(
1133
+ error.error || "Invalid OTP",
1134
+ "OTP_VERIFY_FAILED",
1135
+ response.status
1136
+ );
853
1137
  }
854
1138
  const result = await response.json();
855
1139
  this.accessToken = result.accessToken;
@@ -859,6 +1143,7 @@ var TiquoAuth = class {
859
1143
  if (this.session?.user?.id) {
860
1144
  addCustomerUserId(this.session.user.id);
861
1145
  }
1146
+ this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
862
1147
  this.broadcastTabSync("LOGIN");
863
1148
  return {
864
1149
  success: true,
@@ -906,7 +1191,9 @@ var TiquoAuth = class {
906
1191
  async updateProfile(updates) {
907
1192
  await this.ensureValidToken();
908
1193
  const normalizedUpdates = { ...updates };
909
- const profilePhotoUpload = this.extractUploadableProfilePhoto(normalizedUpdates.profilePhoto);
1194
+ const profilePhotoUpload = this.extractUploadableProfilePhoto(
1195
+ normalizedUpdates.profilePhoto
1196
+ );
910
1197
  if (profilePhotoUpload) {
911
1198
  delete normalizedUpdates.profilePhoto;
912
1199
  }
@@ -914,7 +1201,12 @@ var TiquoAuth = class {
914
1201
  const normalized = normalizePhone(normalizedUpdates.phone);
915
1202
  const validation = validatePhone(normalizedUpdates.phone);
916
1203
  if (!validation.valid) {
917
- this.log("\u26A0\uFE0F Phone validation warning:", validation.reason, "- Original:", normalizedUpdates.phone);
1204
+ this.log(
1205
+ "\u26A0\uFE0F Phone validation warning:",
1206
+ validation.reason,
1207
+ "- Original:",
1208
+ normalizedUpdates.phone
1209
+ );
918
1210
  } else {
919
1211
  this.log("Phone normalized:", normalizedUpdates.phone, "\u2192", normalized);
920
1212
  }
@@ -926,7 +1218,12 @@ var TiquoAuth = class {
926
1218
  const normalized = normalizePhone(p.number);
927
1219
  const validation = validatePhone(p.number);
928
1220
  if (!validation.valid) {
929
- this.log("\u26A0\uFE0F Phone validation warning:", validation.reason, "- Original:", p.number);
1221
+ this.log(
1222
+ "\u26A0\uFE0F Phone validation warning:",
1223
+ validation.reason,
1224
+ "- Original:",
1225
+ p.number
1226
+ );
930
1227
  }
931
1228
  return { ...p, number: normalized || p.number };
932
1229
  });
@@ -940,7 +1237,11 @@ var TiquoAuth = class {
940
1237
  });
941
1238
  if (!response.ok) {
942
1239
  const error = await response.json().catch(() => ({ error: "Failed to update profile" }));
943
- throw new TiquoAuthError(error.error || "Failed to update profile", "PROFILE_UPDATE_FAILED", response.status);
1240
+ throw new TiquoAuthError(
1241
+ error.error || "Failed to update profile",
1242
+ "PROFILE_UPDATE_FAILED",
1243
+ response.status
1244
+ );
944
1245
  }
945
1246
  const result = await response.json();
946
1247
  if (this.session && result.data?.customer) {
@@ -972,12 +1273,18 @@ var TiquoAuth = class {
972
1273
  await this.ensureValidToken();
973
1274
  const blob = await this.profilePhotoToBlob(photo);
974
1275
  if (!blob.type.startsWith("image/")) {
975
- throw new TiquoAuthError("Profile photo must be an image", "INVALID_PROFILE_PHOTO");
1276
+ throw new TiquoAuthError(
1277
+ "Profile photo must be an image",
1278
+ "INVALID_PROFILE_PHOTO"
1279
+ );
976
1280
  }
977
- const uploadUrlResponse = await this.request("/api/client/v1/profile/photo-upload-url", {
978
- method: "POST",
979
- body: JSON.stringify({})
980
- });
1281
+ const uploadUrlResponse = await this.request(
1282
+ "/api/client/v1/profile/photo-upload-url",
1283
+ {
1284
+ method: "POST",
1285
+ body: JSON.stringify({})
1286
+ }
1287
+ );
981
1288
  if (!uploadUrlResponse.ok) {
982
1289
  const error = await uploadUrlResponse.json().catch(() => ({ error: "Failed to create profile photo upload URL" }));
983
1290
  throw new TiquoAuthError(
@@ -989,7 +1296,10 @@ var TiquoAuth = class {
989
1296
  const uploadUrlResult = await uploadUrlResponse.json();
990
1297
  const uploadUrl = uploadUrlResult.data?.uploadUrl;
991
1298
  if (!uploadUrl) {
992
- throw new TiquoAuthError("Profile photo upload URL was missing", "PROFILE_PHOTO_UPLOAD_URL_FAILED");
1299
+ throw new TiquoAuthError(
1300
+ "Profile photo upload URL was missing",
1301
+ "PROFILE_PHOTO_UPLOAD_URL_FAILED"
1302
+ );
993
1303
  }
994
1304
  const uploadResponse = await fetch(uploadUrl, {
995
1305
  method: "POST",
@@ -997,17 +1307,27 @@ var TiquoAuth = class {
997
1307
  body: blob
998
1308
  });
999
1309
  if (!uploadResponse.ok) {
1000
- throw new TiquoAuthError("Failed to upload profile photo", "PROFILE_PHOTO_UPLOAD_FAILED", uploadResponse.status);
1310
+ throw new TiquoAuthError(
1311
+ "Failed to upload profile photo",
1312
+ "PROFILE_PHOTO_UPLOAD_FAILED",
1313
+ uploadResponse.status
1314
+ );
1001
1315
  }
1002
1316
  const uploadResult = await uploadResponse.json();
1003
1317
  const storageId = uploadResult.storageId;
1004
1318
  if (!storageId) {
1005
- throw new TiquoAuthError("Profile photo storage ID was missing", "PROFILE_PHOTO_UPLOAD_FAILED");
1319
+ throw new TiquoAuthError(
1320
+ "Profile photo storage ID was missing",
1321
+ "PROFILE_PHOTO_UPLOAD_FAILED"
1322
+ );
1006
1323
  }
1007
- const finalizeResponse = await this.request("/api/client/v1/profile/photo", {
1008
- method: "POST",
1009
- body: JSON.stringify({ storageId })
1010
- });
1324
+ const finalizeResponse = await this.request(
1325
+ "/api/client/v1/profile/photo",
1326
+ {
1327
+ method: "POST",
1328
+ body: JSON.stringify({ storageId })
1329
+ }
1330
+ );
1011
1331
  if (!finalizeResponse.ok) {
1012
1332
  const error = await finalizeResponse.json().catch(() => ({ error: "Failed to update profile photo" }));
1013
1333
  throw new TiquoAuthError(
@@ -1020,7 +1340,10 @@ var TiquoAuth = class {
1020
1340
  const customer = finalizeResult.data?.customer;
1021
1341
  const profilePhoto = finalizeResult.data?.profilePhoto;
1022
1342
  if (!customer || !profilePhoto) {
1023
- throw new TiquoAuthError("Profile photo update response was incomplete", "PROFILE_PHOTO_UPDATE_FAILED");
1343
+ throw new TiquoAuthError(
1344
+ "Profile photo update response was incomplete",
1345
+ "PROFILE_PHOTO_UPDATE_FAILED"
1346
+ );
1024
1347
  }
1025
1348
  if (this.session && customer) {
1026
1349
  this.session = {
@@ -1095,13 +1418,17 @@ var TiquoAuth = class {
1095
1418
  const response = await fetch(url.toString(), {
1096
1419
  method: "GET",
1097
1420
  headers: {
1098
- "Authorization": `Bearer ${this.accessToken}`
1421
+ Authorization: `Bearer ${this.accessToken}`
1099
1422
  },
1100
1423
  credentials: "include"
1101
1424
  });
1102
1425
  if (!response.ok) {
1103
1426
  const error = await response.json().catch(() => ({ error: "Failed to get orders" }));
1104
- throw new TiquoAuthError(error.error || "Failed to get orders", "GET_ORDERS_FAILED", response.status);
1427
+ throw new TiquoAuthError(
1428
+ error.error || "Failed to get orders",
1429
+ "GET_ORDERS_FAILED",
1430
+ response.status
1431
+ );
1105
1432
  }
1106
1433
  const result = await response.json();
1107
1434
  return result.data || { orders: [], hasMore: false };
@@ -1133,13 +1460,17 @@ var TiquoAuth = class {
1133
1460
  const response = await fetch(url.toString(), {
1134
1461
  method: "GET",
1135
1462
  headers: {
1136
- "Authorization": `Bearer ${this.accessToken}`
1463
+ Authorization: `Bearer ${this.accessToken}`
1137
1464
  },
1138
1465
  credentials: "include"
1139
1466
  });
1140
1467
  if (!response.ok) {
1141
1468
  const error = await response.json().catch(() => ({ error: "Failed to get bookings" }));
1142
- throw new TiquoAuthError(error.error || "Failed to get bookings", "GET_BOOKINGS_FAILED", response.status);
1469
+ throw new TiquoAuthError(
1470
+ error.error || "Failed to get bookings",
1471
+ "GET_BOOKINGS_FAILED",
1472
+ response.status
1473
+ );
1143
1474
  }
1144
1475
  const result = await response.json();
1145
1476
  return result.data || { bookings: [], hasMore: false };
@@ -1181,14 +1512,18 @@ var TiquoAuth = class {
1181
1512
  const response = await fetch(url.toString(), {
1182
1513
  method: "GET",
1183
1514
  headers: {
1184
- "Authorization": `Bearer ${this.accessToken}`
1515
+ Authorization: `Bearer ${this.accessToken}`
1185
1516
  },
1186
1517
  credentials: "include"
1187
1518
  });
1188
1519
  if (!response.ok) {
1189
1520
  const error = await response.json().catch(() => ({ error: "Failed to get receipt" }));
1190
1521
  const code = response.status === 404 ? "RECEIPT_NOT_AVAILABLE" : "GET_RECEIPT_FAILED";
1191
- throw new TiquoAuthError(error.error || "Failed to get receipt", code, response.status);
1522
+ throw new TiquoAuthError(
1523
+ error.error || "Failed to get receipt",
1524
+ code,
1525
+ response.status
1526
+ );
1192
1527
  }
1193
1528
  const result = await response.json();
1194
1529
  return result.data;
@@ -1213,13 +1548,17 @@ var TiquoAuth = class {
1213
1548
  const response = await fetch(url.toString(), {
1214
1549
  method: "GET",
1215
1550
  headers: {
1216
- "Authorization": `Bearer ${this.accessToken}`
1551
+ Authorization: `Bearer ${this.accessToken}`
1217
1552
  },
1218
1553
  credentials: "include"
1219
1554
  });
1220
1555
  if (!response.ok) {
1221
1556
  const error = await response.json().catch(() => ({ error: "Failed to get enquiries" }));
1222
- throw new TiquoAuthError(error.error || "Failed to get enquiries", "GET_ENQUIRIES_FAILED", response.status);
1557
+ throw new TiquoAuthError(
1558
+ error.error || "Failed to get enquiries",
1559
+ "GET_ENQUIRIES_FAILED",
1560
+ response.status
1561
+ );
1223
1562
  }
1224
1563
  const result = await response.json();
1225
1564
  return result.data || { enquiries: [], hasMore: false };
@@ -1237,16 +1576,23 @@ var TiquoAuth = class {
1237
1576
  async getCompanies() {
1238
1577
  await this.ensureValidToken();
1239
1578
  this.log("Fetching customer companies");
1240
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/companies`, {
1241
- method: "GET",
1242
- headers: {
1243
- "Authorization": `Bearer ${this.accessToken}`
1244
- },
1245
- credentials: "include"
1246
- });
1579
+ const response = await fetch(
1580
+ `${this.config.apiEndpoint}/api/client/v1/companies`,
1581
+ {
1582
+ method: "GET",
1583
+ headers: {
1584
+ Authorization: `Bearer ${this.accessToken}`
1585
+ },
1586
+ credentials: "include"
1587
+ }
1588
+ );
1247
1589
  if (!response.ok) {
1248
1590
  const error = await response.json().catch(() => ({ error: "Failed to get companies" }));
1249
- throw new TiquoAuthError(error.error || "Failed to get companies", "GET_COMPANIES_FAILED", response.status);
1591
+ throw new TiquoAuthError(
1592
+ error.error || "Failed to get companies",
1593
+ "GET_COMPANIES_FAILED",
1594
+ response.status
1595
+ );
1250
1596
  }
1251
1597
  const result = await response.json();
1252
1598
  return result.data || { companies: [] };
@@ -1268,19 +1614,25 @@ var TiquoAuth = class {
1268
1614
  async getCompanyColleagues(companyId) {
1269
1615
  await this.ensureValidToken();
1270
1616
  this.log("Fetching company colleagues for:", companyId);
1271
- const url = new URL(`${this.config.apiEndpoint}/api/client/v1/companies/colleagues`);
1617
+ const url = new URL(
1618
+ `${this.config.apiEndpoint}/api/client/v1/companies/colleagues`
1619
+ );
1272
1620
  url.searchParams.set("companyId", companyId);
1273
1621
  const response = await fetch(url.toString(), {
1274
1622
  method: "GET",
1275
1623
  headers: {
1276
- "Authorization": `Bearer ${this.accessToken}`
1624
+ Authorization: `Bearer ${this.accessToken}`
1277
1625
  },
1278
1626
  credentials: "include"
1279
1627
  });
1280
1628
  if (!response.ok) {
1281
1629
  const error = await response.json().catch(() => ({ error: "Failed to get colleagues" }));
1282
1630
  const code = response.status === 403 ? "NOT_COMPANY_ADMIN" : "GET_COLLEAGUES_FAILED";
1283
- throw new TiquoAuthError(error.error || "Failed to get colleagues", code, response.status);
1631
+ throw new TiquoAuthError(
1632
+ error.error || "Failed to get colleagues",
1633
+ code,
1634
+ response.status
1635
+ );
1284
1636
  }
1285
1637
  const result = await response.json();
1286
1638
  return result.data;
@@ -1301,13 +1653,17 @@ var TiquoAuth = class {
1301
1653
  });
1302
1654
  if (!response.ok) {
1303
1655
  const error = await response.json().catch(() => ({ error: "Failed to generate token" }));
1304
- throw new TiquoAuthError(error.error || "Failed to generate token", "IFRAME_TOKEN_FAILED", response.status);
1656
+ throw new TiquoAuthError(
1657
+ error.error || "Failed to generate token",
1658
+ "IFRAME_TOKEN_FAILED",
1659
+ response.status
1660
+ );
1305
1661
  }
1306
1662
  return response.json();
1307
1663
  }
1308
1664
  /**
1309
1665
  * Embed a customer flow with automatic authentication
1310
- *
1666
+ *
1311
1667
  * @param flowUrl - The URL of the customer flow (book.tiquo.app/...)
1312
1668
  * @param container - Container element or selector
1313
1669
  * @param options - Optional iframe configuration
@@ -1315,7 +1671,10 @@ var TiquoAuth = class {
1315
1671
  async embedCustomerFlow(flowUrl, container, options) {
1316
1672
  const containerEl = typeof container === "string" ? document.querySelector(container) : container;
1317
1673
  if (!containerEl) {
1318
- throw new TiquoAuthError("Container element not found", "CONTAINER_NOT_FOUND");
1674
+ throw new TiquoAuthError(
1675
+ "Container element not found",
1676
+ "CONTAINER_NOT_FOUND"
1677
+ );
1319
1678
  }
1320
1679
  let authToken;
1321
1680
  if (this.accessToken) {
@@ -1341,7 +1700,10 @@ var TiquoAuth = class {
1341
1700
  iframe.addEventListener("load", options.onLoad);
1342
1701
  }
1343
1702
  if (options?.onError) {
1344
- iframe.addEventListener("error", () => options.onError(new Error("Failed to load iframe")));
1703
+ iframe.addEventListener(
1704
+ "error",
1705
+ () => options.onError(new Error("Failed to load iframe"))
1706
+ );
1345
1707
  }
1346
1708
  containerEl.innerHTML = "";
1347
1709
  containerEl.appendChild(iframe);
@@ -1470,7 +1832,11 @@ var TiquoAuth = class {
1470
1832
  this.accessToken = accessToken;
1471
1833
  this.refreshToken = params.get("refresh_token");
1472
1834
  if (window.history?.replaceState) {
1473
- window.history.replaceState(null, "", window.location.pathname + window.location.search);
1835
+ window.history.replaceState(
1836
+ null,
1837
+ "",
1838
+ window.location.pathname + window.location.search
1839
+ );
1474
1840
  }
1475
1841
  return;
1476
1842
  }
@@ -1498,7 +1864,10 @@ var TiquoAuth = class {
1498
1864
  if (typeof photo === "string" && this.isProfilePhotoBlobUrl(photo)) {
1499
1865
  const response = await fetch(photo);
1500
1866
  if (!response.ok) {
1501
- throw new TiquoAuthError("Failed to read profile photo URI", "INVALID_PROFILE_PHOTO");
1867
+ throw new TiquoAuthError(
1868
+ "Failed to read profile photo URI",
1869
+ "INVALID_PROFILE_PHOTO"
1870
+ );
1502
1871
  }
1503
1872
  return response.blob();
1504
1873
  }
@@ -1566,16 +1935,19 @@ var TiquoAuth = class {
1566
1935
  this.isRefreshing = true;
1567
1936
  this.log("Refreshing access token");
1568
1937
  try {
1569
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/refresh`, {
1570
- method: "POST",
1571
- headers: {
1572
- "Content-Type": "application/json"
1573
- },
1574
- body: JSON.stringify({
1575
- refresh_token: this.refreshToken
1576
- }),
1577
- credentials: "include"
1578
- });
1938
+ const response = await fetch(
1939
+ `${this.config.apiEndpoint}/api/client/v1/refresh`,
1940
+ {
1941
+ method: "POST",
1942
+ headers: {
1943
+ "Content-Type": "application/json"
1944
+ },
1945
+ body: JSON.stringify({
1946
+ refresh_token: this.refreshToken
1947
+ }),
1948
+ credentials: "include"
1949
+ }
1950
+ );
1579
1951
  if (!response.ok) {
1580
1952
  this.log("Token refresh failed, clearing session");
1581
1953
  this.clearTokens();
@@ -1612,13 +1984,16 @@ var TiquoAuth = class {
1612
1984
  }
1613
1985
  try {
1614
1986
  await this.refreshTokenIfNeeded();
1615
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/profile`, {
1616
- method: "GET",
1617
- headers: {
1618
- "Authorization": `Bearer ${this.accessToken}`
1619
- },
1620
- credentials: "include"
1621
- });
1987
+ const response = await fetch(
1988
+ `${this.config.apiEndpoint}/api/client/v1/profile`,
1989
+ {
1990
+ method: "GET",
1991
+ headers: {
1992
+ Authorization: `Bearer ${this.accessToken}`
1993
+ },
1994
+ credentials: "include"
1995
+ }
1996
+ );
1622
1997
  if (!response.ok) {
1623
1998
  this.log("Session invalid, clearing");
1624
1999
  this.clearTokens();
@@ -1636,6 +2011,9 @@ var TiquoAuth = class {
1636
2011
  if (this.session.user?.id) {
1637
2012
  addCustomerUserId(this.session.user.id);
1638
2013
  }
2014
+ if (this.session.customer) {
2015
+ this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
2016
+ }
1639
2017
  this.notifyListeners();
1640
2018
  this.scheduleRefresh();
1641
2019
  return this.session;
@@ -1670,8 +2048,12 @@ var TiquoAuth = class {
1670
2048
  return;
1671
2049
  }
1672
2050
  try {
1673
- const accessToken = localStorage.getItem(`${this.config.storagePrefix}access_token`);
1674
- const refreshToken = localStorage.getItem(`${this.config.storagePrefix}refresh_token`);
2051
+ const accessToken = localStorage.getItem(
2052
+ `${this.config.storagePrefix}access_token`
2053
+ );
2054
+ const refreshToken = localStorage.getItem(
2055
+ `${this.config.storagePrefix}refresh_token`
2056
+ );
1675
2057
  if (accessToken) {
1676
2058
  this.accessToken = accessToken;
1677
2059
  this.refreshToken = refreshToken;
@@ -1783,7 +2165,12 @@ var TiquoAuth = class {
1783
2165
  if (message.tabId === this.tabId) return;
1784
2166
  if (this.isProcessingTabSync) return;
1785
2167
  this.isProcessingTabSync = true;
1786
- this.log("Received tab sync message:", message.type, "from tab:", message.tabId);
2168
+ this.log(
2169
+ "Received tab sync message:",
2170
+ message.type,
2171
+ "from tab:",
2172
+ message.tabId
2173
+ );
1787
2174
  try {
1788
2175
  switch (message.type) {
1789
2176
  case "LOGIN":
@@ -1810,7 +2197,9 @@ var TiquoAuth = class {
1810
2197
  }
1811
2198
  try {
1812
2199
  localStorage.removeItem(`${this.config.storagePrefix}access_token`);
1813
- localStorage.removeItem(`${this.config.storagePrefix}refresh_token`);
2200
+ localStorage.removeItem(
2201
+ `${this.config.storagePrefix}refresh_token`
2202
+ );
1814
2203
  } catch {
1815
2204
  }
1816
2205
  this.notifyListeners();
@@ -1914,6 +2303,7 @@ TiquoPhone.buildPhone = buildPhone;
1914
2303
  var index_default = TiquoAuth;
1915
2304
  // Annotate the CommonJS export names for ESM import in node:
1916
2305
  0 && (module.exports = {
2306
+ TiquoAnalytics,
1917
2307
  TiquoAuth,
1918
2308
  TiquoAuthError,
1919
2309
  TiquoCMS,