@tiquo/dom-package 1.5.0 → 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/README.md +28 -1
- package/dist/index.d.mts +154 -22
- package/dist/index.d.ts +154 -22
- package/dist/index.js +632 -59
- package/dist/index.mjs +630 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,8 +20,10 @@ 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,
|
|
26
|
+
TiquoCMS: () => TiquoCMS,
|
|
25
27
|
TiquoPhone: () => TiquoPhone,
|
|
26
28
|
addCustomerUserId: () => addCustomerUserId,
|
|
27
29
|
clearCachedEmail: () => clearCachedEmail,
|
|
@@ -677,6 +679,333 @@ function printTiquoBranding() {
|
|
|
677
679
|
}
|
|
678
680
|
}
|
|
679
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;
|
|
931
|
+
var TiquoCMS = class {
|
|
932
|
+
constructor(config) {
|
|
933
|
+
this.analytics = null;
|
|
934
|
+
if (!config.publicKey) {
|
|
935
|
+
throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
|
|
936
|
+
}
|
|
937
|
+
if (!config.publicKey.startsWith("pk_dom_")) {
|
|
938
|
+
throw new TiquoAuthError(
|
|
939
|
+
"Invalid public key format. Expected pk_dom_xxx",
|
|
940
|
+
"INVALID_PUBLIC_KEY"
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
this.config = {
|
|
944
|
+
publicKey: config.publicKey,
|
|
945
|
+
apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
|
|
946
|
+
debug: config.debug || false,
|
|
947
|
+
analytics: config.analytics !== false
|
|
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
|
+
}
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Fetch a published CMS page for the website attached to this public key.
|
|
959
|
+
*
|
|
960
|
+
* This intentionally goes through the Tiquo edge API rather than exposing
|
|
961
|
+
* Convex connection details to the consuming website.
|
|
962
|
+
*/
|
|
963
|
+
async getPage(request) {
|
|
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
|
+
);
|
|
980
|
+
if (response.status === 404) {
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
if (!response.ok) {
|
|
984
|
+
let message = "Failed to fetch CMS page";
|
|
985
|
+
try {
|
|
986
|
+
const error = await response.json();
|
|
987
|
+
if (typeof error?.error === "string") message = error.error;
|
|
988
|
+
} catch {
|
|
989
|
+
}
|
|
990
|
+
throw new TiquoAuthError(
|
|
991
|
+
message,
|
|
992
|
+
"CMS_PAGE_FETCH_FAILED",
|
|
993
|
+
response.status
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
const result = await response.json();
|
|
997
|
+
if (!result?.success || !result?.data) {
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
this.log("Fetched CMS page", request.siteSlug, request.pageSlug || "home");
|
|
1001
|
+
return result.data;
|
|
1002
|
+
}
|
|
1003
|
+
log(...args) {
|
|
1004
|
+
if (this.config.debug) {
|
|
1005
|
+
console.log("[TiquoCMS]", ...args);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
680
1009
|
var TiquoAuthError = class extends Error {
|
|
681
1010
|
constructor(message, code, statusCode) {
|
|
682
1011
|
super(message);
|
|
@@ -714,6 +1043,7 @@ var TiquoAuth = class {
|
|
|
714
1043
|
this.visibilityHandler = null;
|
|
715
1044
|
this.iframeObserver = null;
|
|
716
1045
|
this.injectedIframes = /* @__PURE__ */ new WeakSet();
|
|
1046
|
+
this.analytics = null;
|
|
717
1047
|
// Multi-tab sync
|
|
718
1048
|
this.broadcastChannel = null;
|
|
719
1049
|
this.isProcessingTabSync = false;
|
|
@@ -734,10 +1064,19 @@ var TiquoAuth = class {
|
|
|
734
1064
|
debug: config.debug || false,
|
|
735
1065
|
enableTabSync: config.enableTabSync !== false,
|
|
736
1066
|
// Default true
|
|
1067
|
+
analytics: config.analytics !== false,
|
|
737
1068
|
accessToken: config.accessToken,
|
|
738
1069
|
refreshToken: config.refreshToken
|
|
739
1070
|
};
|
|
740
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
|
+
}
|
|
741
1080
|
if (this.config.enableTabSync) {
|
|
742
1081
|
this.initTabSync();
|
|
743
1082
|
}
|
|
@@ -763,7 +1102,11 @@ var TiquoAuth = class {
|
|
|
763
1102
|
});
|
|
764
1103
|
if (!response.ok) {
|
|
765
1104
|
const error = await response.json().catch(() => ({ error: "Failed to send OTP" }));
|
|
766
|
-
throw new TiquoAuthError(
|
|
1105
|
+
throw new TiquoAuthError(
|
|
1106
|
+
error.error || "Failed to send OTP",
|
|
1107
|
+
"OTP_SEND_FAILED",
|
|
1108
|
+
response.status
|
|
1109
|
+
);
|
|
767
1110
|
}
|
|
768
1111
|
const result = await response.json();
|
|
769
1112
|
return {
|
|
@@ -786,7 +1129,11 @@ var TiquoAuth = class {
|
|
|
786
1129
|
});
|
|
787
1130
|
if (!response.ok) {
|
|
788
1131
|
const error = await response.json().catch(() => ({ error: "Invalid OTP" }));
|
|
789
|
-
throw new TiquoAuthError(
|
|
1132
|
+
throw new TiquoAuthError(
|
|
1133
|
+
error.error || "Invalid OTP",
|
|
1134
|
+
"OTP_VERIFY_FAILED",
|
|
1135
|
+
response.status
|
|
1136
|
+
);
|
|
790
1137
|
}
|
|
791
1138
|
const result = await response.json();
|
|
792
1139
|
this.accessToken = result.accessToken;
|
|
@@ -796,6 +1143,7 @@ var TiquoAuth = class {
|
|
|
796
1143
|
if (this.session?.user?.id) {
|
|
797
1144
|
addCustomerUserId(this.session.user.id);
|
|
798
1145
|
}
|
|
1146
|
+
this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
|
|
799
1147
|
this.broadcastTabSync("LOGIN");
|
|
800
1148
|
return {
|
|
801
1149
|
success: true,
|
|
@@ -843,11 +1191,22 @@ var TiquoAuth = class {
|
|
|
843
1191
|
async updateProfile(updates) {
|
|
844
1192
|
await this.ensureValidToken();
|
|
845
1193
|
const normalizedUpdates = { ...updates };
|
|
1194
|
+
const profilePhotoUpload = this.extractUploadableProfilePhoto(
|
|
1195
|
+
normalizedUpdates.profilePhoto
|
|
1196
|
+
);
|
|
1197
|
+
if (profilePhotoUpload) {
|
|
1198
|
+
delete normalizedUpdates.profilePhoto;
|
|
1199
|
+
}
|
|
846
1200
|
if (normalizedUpdates.phone !== void 0 && normalizedUpdates.phone !== "") {
|
|
847
1201
|
const normalized = normalizePhone(normalizedUpdates.phone);
|
|
848
1202
|
const validation = validatePhone(normalizedUpdates.phone);
|
|
849
1203
|
if (!validation.valid) {
|
|
850
|
-
this.log(
|
|
1204
|
+
this.log(
|
|
1205
|
+
"\u26A0\uFE0F Phone validation warning:",
|
|
1206
|
+
validation.reason,
|
|
1207
|
+
"- Original:",
|
|
1208
|
+
normalizedUpdates.phone
|
|
1209
|
+
);
|
|
851
1210
|
} else {
|
|
852
1211
|
this.log("Phone normalized:", normalizedUpdates.phone, "\u2192", normalized);
|
|
853
1212
|
}
|
|
@@ -859,32 +1218,146 @@ var TiquoAuth = class {
|
|
|
859
1218
|
const normalized = normalizePhone(p.number);
|
|
860
1219
|
const validation = validatePhone(p.number);
|
|
861
1220
|
if (!validation.valid) {
|
|
862
|
-
this.log(
|
|
1221
|
+
this.log(
|
|
1222
|
+
"\u26A0\uFE0F Phone validation warning:",
|
|
1223
|
+
validation.reason,
|
|
1224
|
+
"- Original:",
|
|
1225
|
+
p.number
|
|
1226
|
+
);
|
|
863
1227
|
}
|
|
864
1228
|
return { ...p, number: normalized || p.number };
|
|
865
1229
|
});
|
|
866
1230
|
}
|
|
867
1231
|
this.log("Updating customer profile:", normalizedUpdates);
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1232
|
+
let customer = this.session?.customer || void 0;
|
|
1233
|
+
if (Object.keys(normalizedUpdates).length > 0) {
|
|
1234
|
+
const response = await this.request("/api/client/v1/profile", {
|
|
1235
|
+
method: "PATCH",
|
|
1236
|
+
body: JSON.stringify(normalizedUpdates)
|
|
1237
|
+
});
|
|
1238
|
+
if (!response.ok) {
|
|
1239
|
+
const error = await response.json().catch(() => ({ error: "Failed to update profile" }));
|
|
1240
|
+
throw new TiquoAuthError(
|
|
1241
|
+
error.error || "Failed to update profile",
|
|
1242
|
+
"PROFILE_UPDATE_FAILED",
|
|
1243
|
+
response.status
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
const result = await response.json();
|
|
1247
|
+
if (this.session && result.data?.customer) {
|
|
1248
|
+
this.session = {
|
|
1249
|
+
...this.session,
|
|
1250
|
+
customer: result.data.customer
|
|
1251
|
+
};
|
|
1252
|
+
this.notifyListeners();
|
|
1253
|
+
this.broadcastTabSync("SESSION_UPDATE");
|
|
1254
|
+
}
|
|
1255
|
+
customer = result.data?.customer;
|
|
1256
|
+
}
|
|
1257
|
+
if (profilePhotoUpload) {
|
|
1258
|
+
return this.uploadProfilePhoto(profilePhotoUpload);
|
|
1259
|
+
}
|
|
1260
|
+
return {
|
|
1261
|
+
success: true,
|
|
1262
|
+
customer
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Upload and save the authenticated customer's profile photo.
|
|
1267
|
+
*
|
|
1268
|
+
* Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
|
|
1269
|
+
* image is uploaded to Tiquo storage first, and the customer profile is
|
|
1270
|
+
* updated with the URL.
|
|
1271
|
+
*/
|
|
1272
|
+
async uploadProfilePhoto(photo) {
|
|
1273
|
+
await this.ensureValidToken();
|
|
1274
|
+
const blob = await this.profilePhotoToBlob(photo);
|
|
1275
|
+
if (!blob.type.startsWith("image/")) {
|
|
1276
|
+
throw new TiquoAuthError(
|
|
1277
|
+
"Profile photo must be an image",
|
|
1278
|
+
"INVALID_PROFILE_PHOTO"
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
const uploadUrlResponse = await this.request(
|
|
1282
|
+
"/api/client/v1/profile/photo-upload-url",
|
|
1283
|
+
{
|
|
1284
|
+
method: "POST",
|
|
1285
|
+
body: JSON.stringify({})
|
|
1286
|
+
}
|
|
1287
|
+
);
|
|
1288
|
+
if (!uploadUrlResponse.ok) {
|
|
1289
|
+
const error = await uploadUrlResponse.json().catch(() => ({ error: "Failed to create profile photo upload URL" }));
|
|
1290
|
+
throw new TiquoAuthError(
|
|
1291
|
+
error.error || "Failed to create profile photo upload URL",
|
|
1292
|
+
"PROFILE_PHOTO_UPLOAD_URL_FAILED",
|
|
1293
|
+
uploadUrlResponse.status
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
const uploadUrlResult = await uploadUrlResponse.json();
|
|
1297
|
+
const uploadUrl = uploadUrlResult.data?.uploadUrl;
|
|
1298
|
+
if (!uploadUrl) {
|
|
1299
|
+
throw new TiquoAuthError(
|
|
1300
|
+
"Profile photo upload URL was missing",
|
|
1301
|
+
"PROFILE_PHOTO_UPLOAD_URL_FAILED"
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
1305
|
+
method: "POST",
|
|
1306
|
+
headers: { "Content-Type": blob.type },
|
|
1307
|
+
body: blob
|
|
871
1308
|
});
|
|
872
|
-
if (!
|
|
873
|
-
|
|
874
|
-
|
|
1309
|
+
if (!uploadResponse.ok) {
|
|
1310
|
+
throw new TiquoAuthError(
|
|
1311
|
+
"Failed to upload profile photo",
|
|
1312
|
+
"PROFILE_PHOTO_UPLOAD_FAILED",
|
|
1313
|
+
uploadResponse.status
|
|
1314
|
+
);
|
|
875
1315
|
}
|
|
876
|
-
const
|
|
877
|
-
|
|
1316
|
+
const uploadResult = await uploadResponse.json();
|
|
1317
|
+
const storageId = uploadResult.storageId;
|
|
1318
|
+
if (!storageId) {
|
|
1319
|
+
throw new TiquoAuthError(
|
|
1320
|
+
"Profile photo storage ID was missing",
|
|
1321
|
+
"PROFILE_PHOTO_UPLOAD_FAILED"
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
const finalizeResponse = await this.request(
|
|
1325
|
+
"/api/client/v1/profile/photo",
|
|
1326
|
+
{
|
|
1327
|
+
method: "POST",
|
|
1328
|
+
body: JSON.stringify({ storageId })
|
|
1329
|
+
}
|
|
1330
|
+
);
|
|
1331
|
+
if (!finalizeResponse.ok) {
|
|
1332
|
+
const error = await finalizeResponse.json().catch(() => ({ error: "Failed to update profile photo" }));
|
|
1333
|
+
throw new TiquoAuthError(
|
|
1334
|
+
error.error || "Failed to update profile photo",
|
|
1335
|
+
"PROFILE_PHOTO_UPDATE_FAILED",
|
|
1336
|
+
finalizeResponse.status
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
const finalizeResult = await finalizeResponse.json();
|
|
1340
|
+
const customer = finalizeResult.data?.customer;
|
|
1341
|
+
const profilePhoto = finalizeResult.data?.profilePhoto;
|
|
1342
|
+
if (!customer || !profilePhoto) {
|
|
1343
|
+
throw new TiquoAuthError(
|
|
1344
|
+
"Profile photo update response was incomplete",
|
|
1345
|
+
"PROFILE_PHOTO_UPDATE_FAILED"
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
if (this.session && customer) {
|
|
878
1349
|
this.session = {
|
|
879
1350
|
...this.session,
|
|
880
|
-
customer
|
|
1351
|
+
customer
|
|
881
1352
|
};
|
|
882
1353
|
this.notifyListeners();
|
|
883
1354
|
this.broadcastTabSync("SESSION_UPDATE");
|
|
884
1355
|
}
|
|
885
1356
|
return {
|
|
886
1357
|
success: true,
|
|
887
|
-
customer
|
|
1358
|
+
customer,
|
|
1359
|
+
profilePhoto,
|
|
1360
|
+
storageId
|
|
888
1361
|
};
|
|
889
1362
|
}
|
|
890
1363
|
/**
|
|
@@ -945,13 +1418,17 @@ var TiquoAuth = class {
|
|
|
945
1418
|
const response = await fetch(url.toString(), {
|
|
946
1419
|
method: "GET",
|
|
947
1420
|
headers: {
|
|
948
|
-
|
|
1421
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
949
1422
|
},
|
|
950
1423
|
credentials: "include"
|
|
951
1424
|
});
|
|
952
1425
|
if (!response.ok) {
|
|
953
1426
|
const error = await response.json().catch(() => ({ error: "Failed to get orders" }));
|
|
954
|
-
throw new TiquoAuthError(
|
|
1427
|
+
throw new TiquoAuthError(
|
|
1428
|
+
error.error || "Failed to get orders",
|
|
1429
|
+
"GET_ORDERS_FAILED",
|
|
1430
|
+
response.status
|
|
1431
|
+
);
|
|
955
1432
|
}
|
|
956
1433
|
const result = await response.json();
|
|
957
1434
|
return result.data || { orders: [], hasMore: false };
|
|
@@ -983,13 +1460,17 @@ var TiquoAuth = class {
|
|
|
983
1460
|
const response = await fetch(url.toString(), {
|
|
984
1461
|
method: "GET",
|
|
985
1462
|
headers: {
|
|
986
|
-
|
|
1463
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
987
1464
|
},
|
|
988
1465
|
credentials: "include"
|
|
989
1466
|
});
|
|
990
1467
|
if (!response.ok) {
|
|
991
1468
|
const error = await response.json().catch(() => ({ error: "Failed to get bookings" }));
|
|
992
|
-
throw new TiquoAuthError(
|
|
1469
|
+
throw new TiquoAuthError(
|
|
1470
|
+
error.error || "Failed to get bookings",
|
|
1471
|
+
"GET_BOOKINGS_FAILED",
|
|
1472
|
+
response.status
|
|
1473
|
+
);
|
|
993
1474
|
}
|
|
994
1475
|
const result = await response.json();
|
|
995
1476
|
return result.data || { bookings: [], hasMore: false };
|
|
@@ -1031,14 +1512,18 @@ var TiquoAuth = class {
|
|
|
1031
1512
|
const response = await fetch(url.toString(), {
|
|
1032
1513
|
method: "GET",
|
|
1033
1514
|
headers: {
|
|
1034
|
-
|
|
1515
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
1035
1516
|
},
|
|
1036
1517
|
credentials: "include"
|
|
1037
1518
|
});
|
|
1038
1519
|
if (!response.ok) {
|
|
1039
1520
|
const error = await response.json().catch(() => ({ error: "Failed to get receipt" }));
|
|
1040
1521
|
const code = response.status === 404 ? "RECEIPT_NOT_AVAILABLE" : "GET_RECEIPT_FAILED";
|
|
1041
|
-
throw new TiquoAuthError(
|
|
1522
|
+
throw new TiquoAuthError(
|
|
1523
|
+
error.error || "Failed to get receipt",
|
|
1524
|
+
code,
|
|
1525
|
+
response.status
|
|
1526
|
+
);
|
|
1042
1527
|
}
|
|
1043
1528
|
const result = await response.json();
|
|
1044
1529
|
return result.data;
|
|
@@ -1063,13 +1548,17 @@ var TiquoAuth = class {
|
|
|
1063
1548
|
const response = await fetch(url.toString(), {
|
|
1064
1549
|
method: "GET",
|
|
1065
1550
|
headers: {
|
|
1066
|
-
|
|
1551
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
1067
1552
|
},
|
|
1068
1553
|
credentials: "include"
|
|
1069
1554
|
});
|
|
1070
1555
|
if (!response.ok) {
|
|
1071
1556
|
const error = await response.json().catch(() => ({ error: "Failed to get enquiries" }));
|
|
1072
|
-
throw new TiquoAuthError(
|
|
1557
|
+
throw new TiquoAuthError(
|
|
1558
|
+
error.error || "Failed to get enquiries",
|
|
1559
|
+
"GET_ENQUIRIES_FAILED",
|
|
1560
|
+
response.status
|
|
1561
|
+
);
|
|
1073
1562
|
}
|
|
1074
1563
|
const result = await response.json();
|
|
1075
1564
|
return result.data || { enquiries: [], hasMore: false };
|
|
@@ -1087,16 +1576,23 @@ var TiquoAuth = class {
|
|
|
1087
1576
|
async getCompanies() {
|
|
1088
1577
|
await this.ensureValidToken();
|
|
1089
1578
|
this.log("Fetching customer companies");
|
|
1090
|
-
const response = await fetch(
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
"
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
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
|
+
);
|
|
1097
1589
|
if (!response.ok) {
|
|
1098
1590
|
const error = await response.json().catch(() => ({ error: "Failed to get companies" }));
|
|
1099
|
-
throw new TiquoAuthError(
|
|
1591
|
+
throw new TiquoAuthError(
|
|
1592
|
+
error.error || "Failed to get companies",
|
|
1593
|
+
"GET_COMPANIES_FAILED",
|
|
1594
|
+
response.status
|
|
1595
|
+
);
|
|
1100
1596
|
}
|
|
1101
1597
|
const result = await response.json();
|
|
1102
1598
|
return result.data || { companies: [] };
|
|
@@ -1118,19 +1614,25 @@ var TiquoAuth = class {
|
|
|
1118
1614
|
async getCompanyColleagues(companyId) {
|
|
1119
1615
|
await this.ensureValidToken();
|
|
1120
1616
|
this.log("Fetching company colleagues for:", companyId);
|
|
1121
|
-
const url = new URL(
|
|
1617
|
+
const url = new URL(
|
|
1618
|
+
`${this.config.apiEndpoint}/api/client/v1/companies/colleagues`
|
|
1619
|
+
);
|
|
1122
1620
|
url.searchParams.set("companyId", companyId);
|
|
1123
1621
|
const response = await fetch(url.toString(), {
|
|
1124
1622
|
method: "GET",
|
|
1125
1623
|
headers: {
|
|
1126
|
-
|
|
1624
|
+
Authorization: `Bearer ${this.accessToken}`
|
|
1127
1625
|
},
|
|
1128
1626
|
credentials: "include"
|
|
1129
1627
|
});
|
|
1130
1628
|
if (!response.ok) {
|
|
1131
1629
|
const error = await response.json().catch(() => ({ error: "Failed to get colleagues" }));
|
|
1132
1630
|
const code = response.status === 403 ? "NOT_COMPANY_ADMIN" : "GET_COLLEAGUES_FAILED";
|
|
1133
|
-
throw new TiquoAuthError(
|
|
1631
|
+
throw new TiquoAuthError(
|
|
1632
|
+
error.error || "Failed to get colleagues",
|
|
1633
|
+
code,
|
|
1634
|
+
response.status
|
|
1635
|
+
);
|
|
1134
1636
|
}
|
|
1135
1637
|
const result = await response.json();
|
|
1136
1638
|
return result.data;
|
|
@@ -1151,13 +1653,17 @@ var TiquoAuth = class {
|
|
|
1151
1653
|
});
|
|
1152
1654
|
if (!response.ok) {
|
|
1153
1655
|
const error = await response.json().catch(() => ({ error: "Failed to generate token" }));
|
|
1154
|
-
throw new TiquoAuthError(
|
|
1656
|
+
throw new TiquoAuthError(
|
|
1657
|
+
error.error || "Failed to generate token",
|
|
1658
|
+
"IFRAME_TOKEN_FAILED",
|
|
1659
|
+
response.status
|
|
1660
|
+
);
|
|
1155
1661
|
}
|
|
1156
1662
|
return response.json();
|
|
1157
1663
|
}
|
|
1158
1664
|
/**
|
|
1159
1665
|
* Embed a customer flow with automatic authentication
|
|
1160
|
-
*
|
|
1666
|
+
*
|
|
1161
1667
|
* @param flowUrl - The URL of the customer flow (book.tiquo.app/...)
|
|
1162
1668
|
* @param container - Container element or selector
|
|
1163
1669
|
* @param options - Optional iframe configuration
|
|
@@ -1165,7 +1671,10 @@ var TiquoAuth = class {
|
|
|
1165
1671
|
async embedCustomerFlow(flowUrl, container, options) {
|
|
1166
1672
|
const containerEl = typeof container === "string" ? document.querySelector(container) : container;
|
|
1167
1673
|
if (!containerEl) {
|
|
1168
|
-
throw new TiquoAuthError(
|
|
1674
|
+
throw new TiquoAuthError(
|
|
1675
|
+
"Container element not found",
|
|
1676
|
+
"CONTAINER_NOT_FOUND"
|
|
1677
|
+
);
|
|
1169
1678
|
}
|
|
1170
1679
|
let authToken;
|
|
1171
1680
|
if (this.accessToken) {
|
|
@@ -1191,7 +1700,10 @@ var TiquoAuth = class {
|
|
|
1191
1700
|
iframe.addEventListener("load", options.onLoad);
|
|
1192
1701
|
}
|
|
1193
1702
|
if (options?.onError) {
|
|
1194
|
-
iframe.addEventListener(
|
|
1703
|
+
iframe.addEventListener(
|
|
1704
|
+
"error",
|
|
1705
|
+
() => options.onError(new Error("Failed to load iframe"))
|
|
1706
|
+
);
|
|
1195
1707
|
}
|
|
1196
1708
|
containerEl.innerHTML = "";
|
|
1197
1709
|
containerEl.appendChild(iframe);
|
|
@@ -1320,12 +1832,50 @@ var TiquoAuth = class {
|
|
|
1320
1832
|
this.accessToken = accessToken;
|
|
1321
1833
|
this.refreshToken = params.get("refresh_token");
|
|
1322
1834
|
if (window.history?.replaceState) {
|
|
1323
|
-
window.history.replaceState(
|
|
1835
|
+
window.history.replaceState(
|
|
1836
|
+
null,
|
|
1837
|
+
"",
|
|
1838
|
+
window.location.pathname + window.location.search
|
|
1839
|
+
);
|
|
1324
1840
|
}
|
|
1325
1841
|
return;
|
|
1326
1842
|
}
|
|
1327
1843
|
}
|
|
1328
1844
|
}
|
|
1845
|
+
extractUploadableProfilePhoto(profilePhoto) {
|
|
1846
|
+
if (typeof Blob !== "undefined" && profilePhoto instanceof Blob) {
|
|
1847
|
+
return profilePhoto;
|
|
1848
|
+
}
|
|
1849
|
+
if (typeof profilePhoto === "string") {
|
|
1850
|
+
const trimmed = profilePhoto.trim();
|
|
1851
|
+
if (trimmed.startsWith("data:") || trimmed.startsWith("blob:")) {
|
|
1852
|
+
return trimmed;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return null;
|
|
1856
|
+
}
|
|
1857
|
+
isProfilePhotoBlobUrl(photo) {
|
|
1858
|
+
return photo.trim().startsWith("data:") || photo.trim().startsWith("blob:");
|
|
1859
|
+
}
|
|
1860
|
+
async profilePhotoToBlob(photo) {
|
|
1861
|
+
if (typeof Blob !== "undefined" && photo instanceof Blob) {
|
|
1862
|
+
return photo;
|
|
1863
|
+
}
|
|
1864
|
+
if (typeof photo === "string" && this.isProfilePhotoBlobUrl(photo)) {
|
|
1865
|
+
const response = await fetch(photo);
|
|
1866
|
+
if (!response.ok) {
|
|
1867
|
+
throw new TiquoAuthError(
|
|
1868
|
+
"Failed to read profile photo URI",
|
|
1869
|
+
"INVALID_PROFILE_PHOTO"
|
|
1870
|
+
);
|
|
1871
|
+
}
|
|
1872
|
+
return response.blob();
|
|
1873
|
+
}
|
|
1874
|
+
throw new TiquoAuthError(
|
|
1875
|
+
"uploadProfilePhoto expects a File, Blob, data URI, or blob URI. Use updateProfile({ profilePhoto: url }) for remote URLs.",
|
|
1876
|
+
"INVALID_PROFILE_PHOTO"
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1329
1879
|
async request(path, options) {
|
|
1330
1880
|
const url = `${this.config.apiEndpoint}${path}`;
|
|
1331
1881
|
const headers = {
|
|
@@ -1385,16 +1935,19 @@ var TiquoAuth = class {
|
|
|
1385
1935
|
this.isRefreshing = true;
|
|
1386
1936
|
this.log("Refreshing access token");
|
|
1387
1937
|
try {
|
|
1388
|
-
const response = await fetch(
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
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
|
+
);
|
|
1398
1951
|
if (!response.ok) {
|
|
1399
1952
|
this.log("Token refresh failed, clearing session");
|
|
1400
1953
|
this.clearTokens();
|
|
@@ -1431,13 +1984,16 @@ var TiquoAuth = class {
|
|
|
1431
1984
|
}
|
|
1432
1985
|
try {
|
|
1433
1986
|
await this.refreshTokenIfNeeded();
|
|
1434
|
-
const response = await fetch(
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
"
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
+
);
|
|
1441
1997
|
if (!response.ok) {
|
|
1442
1998
|
this.log("Session invalid, clearing");
|
|
1443
1999
|
this.clearTokens();
|
|
@@ -1455,6 +2011,9 @@ var TiquoAuth = class {
|
|
|
1455
2011
|
if (this.session.user?.id) {
|
|
1456
2012
|
addCustomerUserId(this.session.user.id);
|
|
1457
2013
|
}
|
|
2014
|
+
if (this.session.customer) {
|
|
2015
|
+
this.analytics?.identify({ identityLinkType: "auth_dom_login" }).catch(() => void 0);
|
|
2016
|
+
}
|
|
1458
2017
|
this.notifyListeners();
|
|
1459
2018
|
this.scheduleRefresh();
|
|
1460
2019
|
return this.session;
|
|
@@ -1489,8 +2048,12 @@ var TiquoAuth = class {
|
|
|
1489
2048
|
return;
|
|
1490
2049
|
}
|
|
1491
2050
|
try {
|
|
1492
|
-
const accessToken = localStorage.getItem(
|
|
1493
|
-
|
|
2051
|
+
const accessToken = localStorage.getItem(
|
|
2052
|
+
`${this.config.storagePrefix}access_token`
|
|
2053
|
+
);
|
|
2054
|
+
const refreshToken = localStorage.getItem(
|
|
2055
|
+
`${this.config.storagePrefix}refresh_token`
|
|
2056
|
+
);
|
|
1494
2057
|
if (accessToken) {
|
|
1495
2058
|
this.accessToken = accessToken;
|
|
1496
2059
|
this.refreshToken = refreshToken;
|
|
@@ -1602,7 +2165,12 @@ var TiquoAuth = class {
|
|
|
1602
2165
|
if (message.tabId === this.tabId) return;
|
|
1603
2166
|
if (this.isProcessingTabSync) return;
|
|
1604
2167
|
this.isProcessingTabSync = true;
|
|
1605
|
-
this.log(
|
|
2168
|
+
this.log(
|
|
2169
|
+
"Received tab sync message:",
|
|
2170
|
+
message.type,
|
|
2171
|
+
"from tab:",
|
|
2172
|
+
message.tabId
|
|
2173
|
+
);
|
|
1606
2174
|
try {
|
|
1607
2175
|
switch (message.type) {
|
|
1608
2176
|
case "LOGIN":
|
|
@@ -1629,7 +2197,9 @@ var TiquoAuth = class {
|
|
|
1629
2197
|
}
|
|
1630
2198
|
try {
|
|
1631
2199
|
localStorage.removeItem(`${this.config.storagePrefix}access_token`);
|
|
1632
|
-
localStorage.removeItem(
|
|
2200
|
+
localStorage.removeItem(
|
|
2201
|
+
`${this.config.storagePrefix}refresh_token`
|
|
2202
|
+
);
|
|
1633
2203
|
} catch {
|
|
1634
2204
|
}
|
|
1635
2205
|
this.notifyListeners();
|
|
@@ -1701,6 +2271,7 @@ function useTiquoAuth(auth) {
|
|
|
1701
2271
|
verifyOTP: (email, otp) => auth.verifyOTP(email, otp),
|
|
1702
2272
|
logout: () => auth.logout(),
|
|
1703
2273
|
updateProfile: (updates) => auth.updateProfile(updates),
|
|
2274
|
+
uploadProfilePhoto: (photo) => auth.uploadProfilePhoto(photo),
|
|
1704
2275
|
getOrders: (options) => auth.getOrders(options),
|
|
1705
2276
|
getBookings: (options) => auth.getBookings(options),
|
|
1706
2277
|
getUpcomingBookings: (options) => auth.getUpcomingBookings(options),
|
|
@@ -1732,8 +2303,10 @@ TiquoPhone.buildPhone = buildPhone;
|
|
|
1732
2303
|
var index_default = TiquoAuth;
|
|
1733
2304
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1734
2305
|
0 && (module.exports = {
|
|
2306
|
+
TiquoAnalytics,
|
|
1735
2307
|
TiquoAuth,
|
|
1736
2308
|
TiquoAuthError,
|
|
2309
|
+
TiquoCMS,
|
|
1737
2310
|
TiquoPhone,
|
|
1738
2311
|
addCustomerUserId,
|
|
1739
2312
|
clearCachedEmail,
|