@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.mjs CHANGED
@@ -641,8 +641,258 @@ function printTiquoBranding() {
641
641
  }
642
642
  }
643
643
  printTiquoBranding();
644
+ var ANALYTICS_LOCATION_EVENT = "tiquo:locationchange";
645
+ var analyticsHistoryPatched = false;
646
+ function randomId() {
647
+ try {
648
+ if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
649
+ return crypto.randomUUID();
650
+ }
651
+ } catch {
652
+ }
653
+ return `ev_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
654
+ }
655
+ function normalizeHostname(hostname) {
656
+ if (!hostname) return void 0;
657
+ const clean = hostname.trim().toLowerCase().split(":")[0];
658
+ return clean.startsWith("www.") ? clean.slice(4) : clean;
659
+ }
660
+ function getBrowser() {
661
+ if (typeof navigator === "undefined") return "Other";
662
+ const ua = navigator.userAgent;
663
+ if (/Edg(e|A|iOS)?\//i.test(ua)) return "Edge";
664
+ if (/Firefox\//i.test(ua)) return "Firefox";
665
+ if (/Chrome\/|CriOS\//i.test(ua)) return "Chrome";
666
+ if (/Safari\//i.test(ua) && !/Chrome/i.test(ua)) return "Safari";
667
+ return "Other";
668
+ }
669
+ function getDevice() {
670
+ if (typeof navigator === "undefined") return "Desktop";
671
+ const ua = navigator.userAgent;
672
+ if (/iPad|tablet|PlayBook|Silk/i.test(ua)) return "Tablet";
673
+ if (/Android(?!.*Mobile)/i.test(ua) && /Android/i.test(ua) && !/Mobile/i.test(ua))
674
+ return "Tablet";
675
+ if (/Mobile|iPhone|iPod|Android.*Mobile|webOS|BlackBerry|Opera Mini|IEMobile/i.test(
676
+ ua
677
+ ))
678
+ return "Mobile";
679
+ return "Desktop";
680
+ }
681
+ function getOperatingSystem() {
682
+ if (typeof navigator === "undefined") return "Other";
683
+ const ua = navigator.userAgent;
684
+ if (/iPhone|iPad|iPod/i.test(ua)) return "iOS";
685
+ if (/Android/i.test(ua)) return "Android";
686
+ if (/CrOS/i.test(ua)) return "Chrome OS";
687
+ if (/Windows/i.test(ua)) return "Windows";
688
+ if (/Macintosh|Mac OS X/i.test(ua)) return "macOS";
689
+ if (/Linux/i.test(ua)) return "Linux";
690
+ return "Other";
691
+ }
692
+ function getUtmParams() {
693
+ if (typeof window === "undefined") return {};
694
+ const params = new URLSearchParams(window.location.search);
695
+ return {
696
+ source: params.get("utm_source") || void 0,
697
+ medium: params.get("utm_medium") || void 0,
698
+ campaign: params.get("utm_campaign") || void 0,
699
+ content: params.get("utm_content") || void 0,
700
+ term: params.get("utm_term") || void 0
701
+ };
702
+ }
703
+ function patchHistoryForAnalytics() {
704
+ if (analyticsHistoryPatched || typeof window === "undefined") return;
705
+ analyticsHistoryPatched = true;
706
+ const notify = () => {
707
+ window.dispatchEvent(
708
+ new Event(ANALYTICS_LOCATION_EVENT)
709
+ );
710
+ };
711
+ const pushState = history.pushState;
712
+ history.pushState = function patchedPushState(...args) {
713
+ const result = pushState.apply(this, args);
714
+ notify();
715
+ return result;
716
+ };
717
+ const replaceState = history.replaceState;
718
+ history.replaceState = function patchedReplaceState(...args) {
719
+ const result = replaceState.apply(this, args);
720
+ notify();
721
+ return result;
722
+ };
723
+ window.addEventListener("popstate", notify);
724
+ }
725
+ var _TiquoAnalytics = class _TiquoAnalytics {
726
+ constructor(config) {
727
+ this.pageStartedAt = Date.now();
728
+ this.lastPath = null;
729
+ this.started = false;
730
+ if (!config.publicKey) {
731
+ throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
732
+ }
733
+ if (!config.publicKey.startsWith("pk_dom_")) {
734
+ throw new TiquoAuthError(
735
+ "Invalid public key format. Expected pk_dom_xxx",
736
+ "INVALID_PUBLIC_KEY"
737
+ );
738
+ }
739
+ this.config = {
740
+ publicKey: config.publicKey,
741
+ apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
742
+ debug: config.debug || false,
743
+ autoTrackPageviews: config.autoTrackPageviews !== false,
744
+ getAccessToken: config.getAccessToken,
745
+ siteSlug: config.siteSlug
746
+ };
747
+ this.clientSessionId = this.getClientSessionId();
748
+ if (this.config.autoTrackPageviews) {
749
+ this.start();
750
+ }
751
+ }
752
+ start() {
753
+ if (this.started || typeof window === "undefined") return;
754
+ const activeKey = `${this.config.publicKey}:${this.config.siteSlug || ""}`;
755
+ const existing = _TiquoAnalytics.activeInstances.get(activeKey);
756
+ if (existing && existing !== this) {
757
+ existing.adoptConfig(this.config);
758
+ return;
759
+ }
760
+ _TiquoAnalytics.activeInstances.set(activeKey, this);
761
+ this.started = true;
762
+ patchHistoryForAnalytics();
763
+ this.trackPageview();
764
+ window.addEventListener(
765
+ ANALYTICS_LOCATION_EVENT,
766
+ () => this.trackPageview()
767
+ );
768
+ window.addEventListener("pagehide", () => this.trackEngagement());
769
+ document.addEventListener("visibilitychange", () => {
770
+ if (document.visibilityState === "hidden") this.trackEngagement();
771
+ });
772
+ }
773
+ async trackPageview(options = {}) {
774
+ if (typeof window === "undefined") return;
775
+ const path = options.path || `${window.location.pathname}${window.location.search}`;
776
+ if (path === this.lastPath) return;
777
+ if (this.lastPath) {
778
+ this.trackEngagement().catch(() => void 0);
779
+ }
780
+ this.lastPath = path;
781
+ this.pageStartedAt = Date.now();
782
+ await this.track("pageview", {
783
+ ...options,
784
+ path,
785
+ url: options.url || window.location.href,
786
+ title: options.title || document.title,
787
+ referrer: options.referrer || document.referrer || void 0
788
+ });
789
+ }
790
+ async track(eventType, options = {}) {
791
+ if (typeof window === "undefined") return;
792
+ const utm = getUtmParams();
793
+ const payload = {
794
+ publicKey: this.config.publicKey,
795
+ eventId: randomId(),
796
+ eventType,
797
+ eventName: options.eventName,
798
+ eventProperties: options.eventProperties,
799
+ clientSessionId: this.clientSessionId,
800
+ siteSlug: options.siteSlug || this.config.siteSlug,
801
+ pageSlug: options.pageSlug,
802
+ hostname: normalizeHostname(window.location.hostname),
803
+ path: options.path || `${window.location.pathname}${window.location.search}`,
804
+ url: options.url || window.location.href,
805
+ title: options.title || document.title,
806
+ referrer: options.referrer || document.referrer || void 0,
807
+ timestamp: Date.now(),
808
+ browser: getBrowser(),
809
+ device: getDevice(),
810
+ operatingSystem: getOperatingSystem(),
811
+ language: navigator.language,
812
+ screenWidth: window.screen?.width,
813
+ screenHeight: window.screen?.height,
814
+ viewportWidth: window.innerWidth,
815
+ viewportHeight: window.innerHeight,
816
+ durationMs: options.durationMs,
817
+ scrollDepth: options.scrollDepth,
818
+ identityLinkType: options.identityLinkType,
819
+ ...utm
820
+ };
821
+ await this.send(payload);
822
+ }
823
+ async identify(options = {}) {
824
+ await this.track("identify", {
825
+ ...options,
826
+ identityLinkType: options.identityLinkType || "auth_dom_login"
827
+ });
828
+ }
829
+ async trackEngagement() {
830
+ if (typeof window === "undefined" || !this.lastPath) return;
831
+ const durationMs = Date.now() - this.pageStartedAt;
832
+ const scrollHeight = Math.max(
833
+ document.documentElement.scrollHeight,
834
+ document.body?.scrollHeight || 0,
835
+ window.innerHeight
836
+ );
837
+ const scrollDepth = scrollHeight > 0 ? Math.min(1, (window.scrollY + window.innerHeight) / scrollHeight) : void 0;
838
+ await this.track("engagement", {
839
+ path: this.lastPath,
840
+ durationMs,
841
+ scrollDepth
842
+ });
843
+ }
844
+ async send(payload) {
845
+ const headers = {
846
+ "Content-Type": "text/plain;charset=UTF-8",
847
+ "X-Public-Key": this.config.publicKey
848
+ };
849
+ const accessToken = this.config.getAccessToken?.();
850
+ if (accessToken) {
851
+ headers.Authorization = `Bearer ${accessToken}`;
852
+ }
853
+ try {
854
+ await fetch(`${this.config.apiEndpoint}/api/dom-analytics/event`, {
855
+ method: "POST",
856
+ headers,
857
+ credentials: "include",
858
+ keepalive: true,
859
+ body: JSON.stringify(payload)
860
+ });
861
+ } catch (error) {
862
+ this.log("Analytics event failed:", error);
863
+ }
864
+ }
865
+ getClientSessionId() {
866
+ const key = `tiquo_analytics_session_${this.config.publicKey}`;
867
+ try {
868
+ const existing = sessionStorage.getItem(key);
869
+ if (existing) return existing;
870
+ const next = randomId();
871
+ sessionStorage.setItem(key, next);
872
+ return next;
873
+ } catch {
874
+ return randomId();
875
+ }
876
+ }
877
+ log(...args) {
878
+ if (this.config.debug) {
879
+ console.log("[TiquoAnalytics]", ...args);
880
+ }
881
+ }
882
+ adoptConfig(nextConfig) {
883
+ if (nextConfig.getAccessToken) {
884
+ this.config.getAccessToken = nextConfig.getAccessToken;
885
+ }
886
+ if (nextConfig.siteSlug && !this.config.siteSlug) {
887
+ this.config.siteSlug = nextConfig.siteSlug;
888
+ }
889
+ }
890
+ };
891
+ _TiquoAnalytics.activeInstances = /* @__PURE__ */ new Map();
892
+ var TiquoAnalytics = _TiquoAnalytics;
644
893
  var TiquoCMS = class {
645
894
  constructor(config) {
895
+ this.analytics = null;
646
896
  if (!config.publicKey) {
647
897
  throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
648
898
  }
@@ -655,8 +905,16 @@ var TiquoCMS = class {
655
905
  this.config = {
656
906
  publicKey: config.publicKey,
657
907
  apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
658
- debug: config.debug || false
908
+ debug: config.debug || false,
909
+ analytics: config.analytics !== false
659
910
  };
911
+ if (this.config.analytics) {
912
+ this.analytics = new TiquoAnalytics({
913
+ publicKey: this.config.publicKey,
914
+ apiEndpoint: this.config.apiEndpoint,
915
+ debug: this.config.debug
916
+ });
917
+ }
660
918
  }
661
919
  /**
662
920
  * Fetch a published CMS page for the website attached to this public key.
@@ -665,19 +923,22 @@ var TiquoCMS = class {
665
923
  * Convex connection details to the consuming website.
666
924
  */
667
925
  async getPage(request) {
668
- const response = await fetch(`${this.config.apiEndpoint}/api/dom-cms/page`, {
669
- method: "POST",
670
- headers: {
671
- "Content-Type": "text/plain;charset=UTF-8"
672
- },
673
- credentials: "include",
674
- body: JSON.stringify({
675
- publicKey: this.config.publicKey,
676
- siteSlug: request.siteSlug,
677
- pageSlug: request.pageSlug || "home",
678
- templateId: request.templateId
679
- })
680
- });
926
+ const response = await fetch(
927
+ `${this.config.apiEndpoint}/api/dom-cms/page`,
928
+ {
929
+ method: "POST",
930
+ headers: {
931
+ "Content-Type": "text/plain;charset=UTF-8"
932
+ },
933
+ credentials: "include",
934
+ body: JSON.stringify({
935
+ publicKey: this.config.publicKey,
936
+ siteSlug: request.siteSlug,
937
+ pageSlug: request.pageSlug || "home",
938
+ templateId: request.templateId
939
+ })
940
+ }
941
+ );
681
942
  if (response.status === 404) {
682
943
  return null;
683
944
  }
@@ -688,7 +949,11 @@ var TiquoCMS = class {
688
949
  if (typeof error?.error === "string") message = error.error;
689
950
  } catch {
690
951
  }
691
- throw new TiquoAuthError(message, "CMS_PAGE_FETCH_FAILED", response.status);
952
+ throw new TiquoAuthError(
953
+ message,
954
+ "CMS_PAGE_FETCH_FAILED",
955
+ response.status
956
+ );
692
957
  }
693
958
  const result = await response.json();
694
959
  if (!result?.success || !result?.data) {
@@ -740,6 +1005,7 @@ var TiquoAuth = class {
740
1005
  this.visibilityHandler = null;
741
1006
  this.iframeObserver = null;
742
1007
  this.injectedIframes = /* @__PURE__ */ new WeakSet();
1008
+ this.analytics = null;
743
1009
  // Multi-tab sync
744
1010
  this.broadcastChannel = null;
745
1011
  this.isProcessingTabSync = false;
@@ -760,10 +1026,19 @@ var TiquoAuth = class {
760
1026
  debug: config.debug || false,
761
1027
  enableTabSync: config.enableTabSync !== false,
762
1028
  // Default true
1029
+ analytics: config.analytics !== false,
763
1030
  accessToken: config.accessToken,
764
1031
  refreshToken: config.refreshToken
765
1032
  };
766
1033
  this.tabId = this.generateTabId();
1034
+ if (this.config.analytics) {
1035
+ this.analytics = new TiquoAnalytics({
1036
+ publicKey: this.config.publicKey,
1037
+ apiEndpoint: this.config.apiEndpoint,
1038
+ debug: this.config.debug,
1039
+ getAccessToken: () => this.accessToken
1040
+ });
1041
+ }
767
1042
  if (this.config.enableTabSync) {
768
1043
  this.initTabSync();
769
1044
  }
@@ -789,7 +1064,11 @@ var TiquoAuth = class {
789
1064
  });
790
1065
  if (!response.ok) {
791
1066
  const error = await response.json().catch(() => ({ error: "Failed to send OTP" }));
792
- throw new TiquoAuthError(error.error || "Failed to send OTP", "OTP_SEND_FAILED", response.status);
1067
+ throw new TiquoAuthError(
1068
+ error.error || "Failed to send OTP",
1069
+ "OTP_SEND_FAILED",
1070
+ response.status
1071
+ );
793
1072
  }
794
1073
  const result = await response.json();
795
1074
  return {
@@ -812,7 +1091,11 @@ var TiquoAuth = class {
812
1091
  });
813
1092
  if (!response.ok) {
814
1093
  const error = await response.json().catch(() => ({ error: "Invalid OTP" }));
815
- throw new TiquoAuthError(error.error || "Invalid OTP", "OTP_VERIFY_FAILED", response.status);
1094
+ throw new TiquoAuthError(
1095
+ error.error || "Invalid OTP",
1096
+ "OTP_VERIFY_FAILED",
1097
+ response.status
1098
+ );
816
1099
  }
817
1100
  const result = await response.json();
818
1101
  this.accessToken = result.accessToken;
@@ -822,6 +1105,7 @@ var TiquoAuth = class {
822
1105
  if (this.session?.user?.id) {
823
1106
  addCustomerUserId(this.session.user.id);
824
1107
  }
1108
+ this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
825
1109
  this.broadcastTabSync("LOGIN");
826
1110
  return {
827
1111
  success: true,
@@ -869,7 +1153,9 @@ var TiquoAuth = class {
869
1153
  async updateProfile(updates) {
870
1154
  await this.ensureValidToken();
871
1155
  const normalizedUpdates = { ...updates };
872
- const profilePhotoUpload = this.extractUploadableProfilePhoto(normalizedUpdates.profilePhoto);
1156
+ const profilePhotoUpload = this.extractUploadableProfilePhoto(
1157
+ normalizedUpdates.profilePhoto
1158
+ );
873
1159
  if (profilePhotoUpload) {
874
1160
  delete normalizedUpdates.profilePhoto;
875
1161
  }
@@ -877,7 +1163,12 @@ var TiquoAuth = class {
877
1163
  const normalized = normalizePhone(normalizedUpdates.phone);
878
1164
  const validation = validatePhone(normalizedUpdates.phone);
879
1165
  if (!validation.valid) {
880
- this.log("\u26A0\uFE0F Phone validation warning:", validation.reason, "- Original:", normalizedUpdates.phone);
1166
+ this.log(
1167
+ "\u26A0\uFE0F Phone validation warning:",
1168
+ validation.reason,
1169
+ "- Original:",
1170
+ normalizedUpdates.phone
1171
+ );
881
1172
  } else {
882
1173
  this.log("Phone normalized:", normalizedUpdates.phone, "\u2192", normalized);
883
1174
  }
@@ -889,7 +1180,12 @@ var TiquoAuth = class {
889
1180
  const normalized = normalizePhone(p.number);
890
1181
  const validation = validatePhone(p.number);
891
1182
  if (!validation.valid) {
892
- this.log("\u26A0\uFE0F Phone validation warning:", validation.reason, "- Original:", p.number);
1183
+ this.log(
1184
+ "\u26A0\uFE0F Phone validation warning:",
1185
+ validation.reason,
1186
+ "- Original:",
1187
+ p.number
1188
+ );
893
1189
  }
894
1190
  return { ...p, number: normalized || p.number };
895
1191
  });
@@ -903,7 +1199,11 @@ var TiquoAuth = class {
903
1199
  });
904
1200
  if (!response.ok) {
905
1201
  const error = await response.json().catch(() => ({ error: "Failed to update profile" }));
906
- throw new TiquoAuthError(error.error || "Failed to update profile", "PROFILE_UPDATE_FAILED", response.status);
1202
+ throw new TiquoAuthError(
1203
+ error.error || "Failed to update profile",
1204
+ "PROFILE_UPDATE_FAILED",
1205
+ response.status
1206
+ );
907
1207
  }
908
1208
  const result = await response.json();
909
1209
  if (this.session && result.data?.customer) {
@@ -935,12 +1235,18 @@ var TiquoAuth = class {
935
1235
  await this.ensureValidToken();
936
1236
  const blob = await this.profilePhotoToBlob(photo);
937
1237
  if (!blob.type.startsWith("image/")) {
938
- throw new TiquoAuthError("Profile photo must be an image", "INVALID_PROFILE_PHOTO");
1238
+ throw new TiquoAuthError(
1239
+ "Profile photo must be an image",
1240
+ "INVALID_PROFILE_PHOTO"
1241
+ );
939
1242
  }
940
- const uploadUrlResponse = await this.request("/api/client/v1/profile/photo-upload-url", {
941
- method: "POST",
942
- body: JSON.stringify({})
943
- });
1243
+ const uploadUrlResponse = await this.request(
1244
+ "/api/client/v1/profile/photo-upload-url",
1245
+ {
1246
+ method: "POST",
1247
+ body: JSON.stringify({})
1248
+ }
1249
+ );
944
1250
  if (!uploadUrlResponse.ok) {
945
1251
  const error = await uploadUrlResponse.json().catch(() => ({ error: "Failed to create profile photo upload URL" }));
946
1252
  throw new TiquoAuthError(
@@ -952,7 +1258,10 @@ var TiquoAuth = class {
952
1258
  const uploadUrlResult = await uploadUrlResponse.json();
953
1259
  const uploadUrl = uploadUrlResult.data?.uploadUrl;
954
1260
  if (!uploadUrl) {
955
- throw new TiquoAuthError("Profile photo upload URL was missing", "PROFILE_PHOTO_UPLOAD_URL_FAILED");
1261
+ throw new TiquoAuthError(
1262
+ "Profile photo upload URL was missing",
1263
+ "PROFILE_PHOTO_UPLOAD_URL_FAILED"
1264
+ );
956
1265
  }
957
1266
  const uploadResponse = await fetch(uploadUrl, {
958
1267
  method: "POST",
@@ -960,17 +1269,27 @@ var TiquoAuth = class {
960
1269
  body: blob
961
1270
  });
962
1271
  if (!uploadResponse.ok) {
963
- throw new TiquoAuthError("Failed to upload profile photo", "PROFILE_PHOTO_UPLOAD_FAILED", uploadResponse.status);
1272
+ throw new TiquoAuthError(
1273
+ "Failed to upload profile photo",
1274
+ "PROFILE_PHOTO_UPLOAD_FAILED",
1275
+ uploadResponse.status
1276
+ );
964
1277
  }
965
1278
  const uploadResult = await uploadResponse.json();
966
1279
  const storageId = uploadResult.storageId;
967
1280
  if (!storageId) {
968
- throw new TiquoAuthError("Profile photo storage ID was missing", "PROFILE_PHOTO_UPLOAD_FAILED");
1281
+ throw new TiquoAuthError(
1282
+ "Profile photo storage ID was missing",
1283
+ "PROFILE_PHOTO_UPLOAD_FAILED"
1284
+ );
969
1285
  }
970
- const finalizeResponse = await this.request("/api/client/v1/profile/photo", {
971
- method: "POST",
972
- body: JSON.stringify({ storageId })
973
- });
1286
+ const finalizeResponse = await this.request(
1287
+ "/api/client/v1/profile/photo",
1288
+ {
1289
+ method: "POST",
1290
+ body: JSON.stringify({ storageId })
1291
+ }
1292
+ );
974
1293
  if (!finalizeResponse.ok) {
975
1294
  const error = await finalizeResponse.json().catch(() => ({ error: "Failed to update profile photo" }));
976
1295
  throw new TiquoAuthError(
@@ -983,7 +1302,10 @@ var TiquoAuth = class {
983
1302
  const customer = finalizeResult.data?.customer;
984
1303
  const profilePhoto = finalizeResult.data?.profilePhoto;
985
1304
  if (!customer || !profilePhoto) {
986
- throw new TiquoAuthError("Profile photo update response was incomplete", "PROFILE_PHOTO_UPDATE_FAILED");
1305
+ throw new TiquoAuthError(
1306
+ "Profile photo update response was incomplete",
1307
+ "PROFILE_PHOTO_UPDATE_FAILED"
1308
+ );
987
1309
  }
988
1310
  if (this.session && customer) {
989
1311
  this.session = {
@@ -1058,13 +1380,17 @@ var TiquoAuth = class {
1058
1380
  const response = await fetch(url.toString(), {
1059
1381
  method: "GET",
1060
1382
  headers: {
1061
- "Authorization": `Bearer ${this.accessToken}`
1383
+ Authorization: `Bearer ${this.accessToken}`
1062
1384
  },
1063
1385
  credentials: "include"
1064
1386
  });
1065
1387
  if (!response.ok) {
1066
1388
  const error = await response.json().catch(() => ({ error: "Failed to get orders" }));
1067
- throw new TiquoAuthError(error.error || "Failed to get orders", "GET_ORDERS_FAILED", response.status);
1389
+ throw new TiquoAuthError(
1390
+ error.error || "Failed to get orders",
1391
+ "GET_ORDERS_FAILED",
1392
+ response.status
1393
+ );
1068
1394
  }
1069
1395
  const result = await response.json();
1070
1396
  return result.data || { orders: [], hasMore: false };
@@ -1096,13 +1422,17 @@ var TiquoAuth = class {
1096
1422
  const response = await fetch(url.toString(), {
1097
1423
  method: "GET",
1098
1424
  headers: {
1099
- "Authorization": `Bearer ${this.accessToken}`
1425
+ Authorization: `Bearer ${this.accessToken}`
1100
1426
  },
1101
1427
  credentials: "include"
1102
1428
  });
1103
1429
  if (!response.ok) {
1104
1430
  const error = await response.json().catch(() => ({ error: "Failed to get bookings" }));
1105
- throw new TiquoAuthError(error.error || "Failed to get bookings", "GET_BOOKINGS_FAILED", response.status);
1431
+ throw new TiquoAuthError(
1432
+ error.error || "Failed to get bookings",
1433
+ "GET_BOOKINGS_FAILED",
1434
+ response.status
1435
+ );
1106
1436
  }
1107
1437
  const result = await response.json();
1108
1438
  return result.data || { bookings: [], hasMore: false };
@@ -1144,14 +1474,18 @@ var TiquoAuth = class {
1144
1474
  const response = await fetch(url.toString(), {
1145
1475
  method: "GET",
1146
1476
  headers: {
1147
- "Authorization": `Bearer ${this.accessToken}`
1477
+ Authorization: `Bearer ${this.accessToken}`
1148
1478
  },
1149
1479
  credentials: "include"
1150
1480
  });
1151
1481
  if (!response.ok) {
1152
1482
  const error = await response.json().catch(() => ({ error: "Failed to get receipt" }));
1153
1483
  const code = response.status === 404 ? "RECEIPT_NOT_AVAILABLE" : "GET_RECEIPT_FAILED";
1154
- throw new TiquoAuthError(error.error || "Failed to get receipt", code, response.status);
1484
+ throw new TiquoAuthError(
1485
+ error.error || "Failed to get receipt",
1486
+ code,
1487
+ response.status
1488
+ );
1155
1489
  }
1156
1490
  const result = await response.json();
1157
1491
  return result.data;
@@ -1176,13 +1510,17 @@ var TiquoAuth = class {
1176
1510
  const response = await fetch(url.toString(), {
1177
1511
  method: "GET",
1178
1512
  headers: {
1179
- "Authorization": `Bearer ${this.accessToken}`
1513
+ Authorization: `Bearer ${this.accessToken}`
1180
1514
  },
1181
1515
  credentials: "include"
1182
1516
  });
1183
1517
  if (!response.ok) {
1184
1518
  const error = await response.json().catch(() => ({ error: "Failed to get enquiries" }));
1185
- throw new TiquoAuthError(error.error || "Failed to get enquiries", "GET_ENQUIRIES_FAILED", response.status);
1519
+ throw new TiquoAuthError(
1520
+ error.error || "Failed to get enquiries",
1521
+ "GET_ENQUIRIES_FAILED",
1522
+ response.status
1523
+ );
1186
1524
  }
1187
1525
  const result = await response.json();
1188
1526
  return result.data || { enquiries: [], hasMore: false };
@@ -1200,16 +1538,23 @@ var TiquoAuth = class {
1200
1538
  async getCompanies() {
1201
1539
  await this.ensureValidToken();
1202
1540
  this.log("Fetching customer companies");
1203
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/companies`, {
1204
- method: "GET",
1205
- headers: {
1206
- "Authorization": `Bearer ${this.accessToken}`
1207
- },
1208
- credentials: "include"
1209
- });
1541
+ const response = await fetch(
1542
+ `${this.config.apiEndpoint}/api/client/v1/companies`,
1543
+ {
1544
+ method: "GET",
1545
+ headers: {
1546
+ Authorization: `Bearer ${this.accessToken}`
1547
+ },
1548
+ credentials: "include"
1549
+ }
1550
+ );
1210
1551
  if (!response.ok) {
1211
1552
  const error = await response.json().catch(() => ({ error: "Failed to get companies" }));
1212
- throw new TiquoAuthError(error.error || "Failed to get companies", "GET_COMPANIES_FAILED", response.status);
1553
+ throw new TiquoAuthError(
1554
+ error.error || "Failed to get companies",
1555
+ "GET_COMPANIES_FAILED",
1556
+ response.status
1557
+ );
1213
1558
  }
1214
1559
  const result = await response.json();
1215
1560
  return result.data || { companies: [] };
@@ -1231,19 +1576,25 @@ var TiquoAuth = class {
1231
1576
  async getCompanyColleagues(companyId) {
1232
1577
  await this.ensureValidToken();
1233
1578
  this.log("Fetching company colleagues for:", companyId);
1234
- const url = new URL(`${this.config.apiEndpoint}/api/client/v1/companies/colleagues`);
1579
+ const url = new URL(
1580
+ `${this.config.apiEndpoint}/api/client/v1/companies/colleagues`
1581
+ );
1235
1582
  url.searchParams.set("companyId", companyId);
1236
1583
  const response = await fetch(url.toString(), {
1237
1584
  method: "GET",
1238
1585
  headers: {
1239
- "Authorization": `Bearer ${this.accessToken}`
1586
+ Authorization: `Bearer ${this.accessToken}`
1240
1587
  },
1241
1588
  credentials: "include"
1242
1589
  });
1243
1590
  if (!response.ok) {
1244
1591
  const error = await response.json().catch(() => ({ error: "Failed to get colleagues" }));
1245
1592
  const code = response.status === 403 ? "NOT_COMPANY_ADMIN" : "GET_COLLEAGUES_FAILED";
1246
- throw new TiquoAuthError(error.error || "Failed to get colleagues", code, response.status);
1593
+ throw new TiquoAuthError(
1594
+ error.error || "Failed to get colleagues",
1595
+ code,
1596
+ response.status
1597
+ );
1247
1598
  }
1248
1599
  const result = await response.json();
1249
1600
  return result.data;
@@ -1264,13 +1615,17 @@ var TiquoAuth = class {
1264
1615
  });
1265
1616
  if (!response.ok) {
1266
1617
  const error = await response.json().catch(() => ({ error: "Failed to generate token" }));
1267
- throw new TiquoAuthError(error.error || "Failed to generate token", "IFRAME_TOKEN_FAILED", response.status);
1618
+ throw new TiquoAuthError(
1619
+ error.error || "Failed to generate token",
1620
+ "IFRAME_TOKEN_FAILED",
1621
+ response.status
1622
+ );
1268
1623
  }
1269
1624
  return response.json();
1270
1625
  }
1271
1626
  /**
1272
1627
  * Embed a customer flow with automatic authentication
1273
- *
1628
+ *
1274
1629
  * @param flowUrl - The URL of the customer flow (book.tiquo.app/...)
1275
1630
  * @param container - Container element or selector
1276
1631
  * @param options - Optional iframe configuration
@@ -1278,7 +1633,10 @@ var TiquoAuth = class {
1278
1633
  async embedCustomerFlow(flowUrl, container, options) {
1279
1634
  const containerEl = typeof container === "string" ? document.querySelector(container) : container;
1280
1635
  if (!containerEl) {
1281
- throw new TiquoAuthError("Container element not found", "CONTAINER_NOT_FOUND");
1636
+ throw new TiquoAuthError(
1637
+ "Container element not found",
1638
+ "CONTAINER_NOT_FOUND"
1639
+ );
1282
1640
  }
1283
1641
  let authToken;
1284
1642
  if (this.accessToken) {
@@ -1304,7 +1662,10 @@ var TiquoAuth = class {
1304
1662
  iframe.addEventListener("load", options.onLoad);
1305
1663
  }
1306
1664
  if (options?.onError) {
1307
- iframe.addEventListener("error", () => options.onError(new Error("Failed to load iframe")));
1665
+ iframe.addEventListener(
1666
+ "error",
1667
+ () => options.onError(new Error("Failed to load iframe"))
1668
+ );
1308
1669
  }
1309
1670
  containerEl.innerHTML = "";
1310
1671
  containerEl.appendChild(iframe);
@@ -1433,7 +1794,11 @@ var TiquoAuth = class {
1433
1794
  this.accessToken = accessToken;
1434
1795
  this.refreshToken = params.get("refresh_token");
1435
1796
  if (window.history?.replaceState) {
1436
- window.history.replaceState(null, "", window.location.pathname + window.location.search);
1797
+ window.history.replaceState(
1798
+ null,
1799
+ "",
1800
+ window.location.pathname + window.location.search
1801
+ );
1437
1802
  }
1438
1803
  return;
1439
1804
  }
@@ -1461,7 +1826,10 @@ var TiquoAuth = class {
1461
1826
  if (typeof photo === "string" && this.isProfilePhotoBlobUrl(photo)) {
1462
1827
  const response = await fetch(photo);
1463
1828
  if (!response.ok) {
1464
- throw new TiquoAuthError("Failed to read profile photo URI", "INVALID_PROFILE_PHOTO");
1829
+ throw new TiquoAuthError(
1830
+ "Failed to read profile photo URI",
1831
+ "INVALID_PROFILE_PHOTO"
1832
+ );
1465
1833
  }
1466
1834
  return response.blob();
1467
1835
  }
@@ -1529,16 +1897,19 @@ var TiquoAuth = class {
1529
1897
  this.isRefreshing = true;
1530
1898
  this.log("Refreshing access token");
1531
1899
  try {
1532
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/refresh`, {
1533
- method: "POST",
1534
- headers: {
1535
- "Content-Type": "application/json"
1536
- },
1537
- body: JSON.stringify({
1538
- refresh_token: this.refreshToken
1539
- }),
1540
- credentials: "include"
1541
- });
1900
+ const response = await fetch(
1901
+ `${this.config.apiEndpoint}/api/client/v1/refresh`,
1902
+ {
1903
+ method: "POST",
1904
+ headers: {
1905
+ "Content-Type": "application/json"
1906
+ },
1907
+ body: JSON.stringify({
1908
+ refresh_token: this.refreshToken
1909
+ }),
1910
+ credentials: "include"
1911
+ }
1912
+ );
1542
1913
  if (!response.ok) {
1543
1914
  this.log("Token refresh failed, clearing session");
1544
1915
  this.clearTokens();
@@ -1575,13 +1946,16 @@ var TiquoAuth = class {
1575
1946
  }
1576
1947
  try {
1577
1948
  await this.refreshTokenIfNeeded();
1578
- const response = await fetch(`${this.config.apiEndpoint}/api/client/v1/profile`, {
1579
- method: "GET",
1580
- headers: {
1581
- "Authorization": `Bearer ${this.accessToken}`
1582
- },
1583
- credentials: "include"
1584
- });
1949
+ const response = await fetch(
1950
+ `${this.config.apiEndpoint}/api/client/v1/profile`,
1951
+ {
1952
+ method: "GET",
1953
+ headers: {
1954
+ Authorization: `Bearer ${this.accessToken}`
1955
+ },
1956
+ credentials: "include"
1957
+ }
1958
+ );
1585
1959
  if (!response.ok) {
1586
1960
  this.log("Session invalid, clearing");
1587
1961
  this.clearTokens();
@@ -1599,6 +1973,9 @@ var TiquoAuth = class {
1599
1973
  if (this.session.user?.id) {
1600
1974
  addCustomerUserId(this.session.user.id);
1601
1975
  }
1976
+ if (this.session.customer) {
1977
+ this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
1978
+ }
1602
1979
  this.notifyListeners();
1603
1980
  this.scheduleRefresh();
1604
1981
  return this.session;
@@ -1633,8 +2010,12 @@ var TiquoAuth = class {
1633
2010
  return;
1634
2011
  }
1635
2012
  try {
1636
- const accessToken = localStorage.getItem(`${this.config.storagePrefix}access_token`);
1637
- const refreshToken = localStorage.getItem(`${this.config.storagePrefix}refresh_token`);
2013
+ const accessToken = localStorage.getItem(
2014
+ `${this.config.storagePrefix}access_token`
2015
+ );
2016
+ const refreshToken = localStorage.getItem(
2017
+ `${this.config.storagePrefix}refresh_token`
2018
+ );
1638
2019
  if (accessToken) {
1639
2020
  this.accessToken = accessToken;
1640
2021
  this.refreshToken = refreshToken;
@@ -1746,7 +2127,12 @@ var TiquoAuth = class {
1746
2127
  if (message.tabId === this.tabId) return;
1747
2128
  if (this.isProcessingTabSync) return;
1748
2129
  this.isProcessingTabSync = true;
1749
- this.log("Received tab sync message:", message.type, "from tab:", message.tabId);
2130
+ this.log(
2131
+ "Received tab sync message:",
2132
+ message.type,
2133
+ "from tab:",
2134
+ message.tabId
2135
+ );
1750
2136
  try {
1751
2137
  switch (message.type) {
1752
2138
  case "LOGIN":
@@ -1773,7 +2159,9 @@ var TiquoAuth = class {
1773
2159
  }
1774
2160
  try {
1775
2161
  localStorage.removeItem(`${this.config.storagePrefix}access_token`);
1776
- localStorage.removeItem(`${this.config.storagePrefix}refresh_token`);
2162
+ localStorage.removeItem(
2163
+ `${this.config.storagePrefix}refresh_token`
2164
+ );
1777
2165
  } catch {
1778
2166
  }
1779
2167
  this.notifyListeners();
@@ -1876,6 +2264,7 @@ TiquoPhone.getDialCode = getDialCode;
1876
2264
  TiquoPhone.buildPhone = buildPhone;
1877
2265
  var index_default = TiquoAuth;
1878
2266
  export {
2267
+ TiquoAnalytics,
1879
2268
  TiquoAuth,
1880
2269
  TiquoAuthError,
1881
2270
  TiquoCMS,