@tiquo/dom-package 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +90 -6
- package/dist/index.d.ts +90 -6
- package/dist/index.js +157 -10
- package/dist/index.mjs +149 -10
- package/package.json +4 -2
- package/scripts/postinstall.js +14 -0
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customer User ID Cookie Utility
|
|
3
|
+
*
|
|
4
|
+
* This module handles setting a cross-subdomain cookie that stores customer user IDs.
|
|
5
|
+
* The cookie is shared across all *.tiquo.app subdomains and persists for 1 year.
|
|
6
|
+
*
|
|
7
|
+
* The cookie is NOT set if the user is logged in with Clerk (dashboard staff).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if the current user is authenticated via Clerk (dashboard staff).
|
|
11
|
+
* If they are, we should NOT set the customer cookie.
|
|
12
|
+
*/
|
|
13
|
+
declare function isClerkAuthenticated(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Get the list of customer user IDs from the cookie.
|
|
16
|
+
*/
|
|
17
|
+
declare function getCustomerUserIds(): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Add a customer user ID to the cookie.
|
|
20
|
+
* Does nothing if:
|
|
21
|
+
* - The user is authenticated via Clerk (dashboard staff)
|
|
22
|
+
* - The user ID is already in the cookie
|
|
23
|
+
* - Running in a non-browser environment
|
|
24
|
+
*
|
|
25
|
+
* @param userId - The user ID from the users table to add
|
|
26
|
+
*/
|
|
27
|
+
declare function addCustomerUserId(userId: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get the pre-filled email from the customer cookie.
|
|
30
|
+
* This fetches the user's email associated with the cookie user IDs.
|
|
31
|
+
* Results are cached for 5 minutes to avoid repeated API calls.
|
|
32
|
+
*
|
|
33
|
+
* @param organizationId - The Clerk organization ID
|
|
34
|
+
* @returns Promise with email and optional name fields, or null if not found
|
|
35
|
+
*/
|
|
36
|
+
declare function getPrefilledEmailFromCookie(organizationId: string): Promise<{
|
|
37
|
+
email: string;
|
|
38
|
+
firstName?: string;
|
|
39
|
+
lastName?: string;
|
|
40
|
+
} | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Clear the cached email data.
|
|
43
|
+
* Call this when the user logs out or clears cookies.
|
|
44
|
+
*/
|
|
45
|
+
declare function clearCachedEmail(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Track customer presence when the cookie is detected.
|
|
48
|
+
* This updates the customer's online status and logs activity.
|
|
49
|
+
*
|
|
50
|
+
* @param organizationId - The Clerk organization ID
|
|
51
|
+
* @returns Promise with tracking results
|
|
52
|
+
*/
|
|
53
|
+
declare function trackCustomerPresence(organizationId: string): Promise<{
|
|
54
|
+
success: boolean;
|
|
55
|
+
results?: Array<{
|
|
56
|
+
userId: string;
|
|
57
|
+
orgCustomerId?: string;
|
|
58
|
+
customerName?: string;
|
|
59
|
+
tracked: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
error?: string;
|
|
62
|
+
}>;
|
|
63
|
+
|
|
1
64
|
/**
|
|
2
65
|
* @tiquo/dom-package
|
|
3
66
|
*
|
|
@@ -42,6 +105,7 @@
|
|
|
42
105
|
* // https://yoursite.com/#access_token=eyJ...&refresh_token=rt_...
|
|
43
106
|
* ```
|
|
44
107
|
*/
|
|
108
|
+
|
|
45
109
|
interface TiquoAuthConfig {
|
|
46
110
|
/** Public key from your Tiquo Auth DOM settings */
|
|
47
111
|
publicKey: string;
|
|
@@ -70,14 +134,35 @@ interface TiquoUser {
|
|
|
70
134
|
id: string;
|
|
71
135
|
email: string;
|
|
72
136
|
}
|
|
137
|
+
interface TiquoCustomerEmail {
|
|
138
|
+
address: string;
|
|
139
|
+
isPrimary: boolean;
|
|
140
|
+
order: number;
|
|
141
|
+
}
|
|
142
|
+
interface TiquoCustomerPhone {
|
|
143
|
+
number: string;
|
|
144
|
+
isPrimary: boolean;
|
|
145
|
+
order: number;
|
|
146
|
+
}
|
|
73
147
|
interface TiquoCustomer {
|
|
74
148
|
id: string;
|
|
75
149
|
firstName?: string;
|
|
76
150
|
lastName?: string;
|
|
77
151
|
displayName?: string;
|
|
78
152
|
customerNumber: string;
|
|
153
|
+
/** Primary email address (convenience field derived from emails array) */
|
|
79
154
|
email?: string;
|
|
155
|
+
/** Primary phone number (convenience field derived from phones array) */
|
|
80
156
|
phone?: string;
|
|
157
|
+
profilePhoto?: string;
|
|
158
|
+
status?: string;
|
|
159
|
+
totalOrders?: number;
|
|
160
|
+
totalSpent?: number;
|
|
161
|
+
lifetimeValue?: number;
|
|
162
|
+
/** Full list of customer email addresses */
|
|
163
|
+
emails?: TiquoCustomerEmail[];
|
|
164
|
+
/** Full list of customer phone numbers */
|
|
165
|
+
phones?: TiquoCustomerPhone[];
|
|
81
166
|
}
|
|
82
167
|
interface TiquoSession {
|
|
83
168
|
user: TiquoUser;
|
|
@@ -107,12 +192,12 @@ interface ProfileUpdateData {
|
|
|
107
192
|
displayName?: string;
|
|
108
193
|
phone?: string;
|
|
109
194
|
profilePhoto?: string;
|
|
195
|
+
emails?: TiquoCustomerEmail[];
|
|
196
|
+
phones?: TiquoCustomerPhone[];
|
|
110
197
|
}
|
|
111
198
|
interface ProfileUpdateResult {
|
|
112
199
|
success: boolean;
|
|
113
|
-
customer: TiquoCustomer
|
|
114
|
-
profilePhoto?: string;
|
|
115
|
-
};
|
|
200
|
+
customer: TiquoCustomer;
|
|
116
201
|
}
|
|
117
202
|
interface TiquoOrderItem {
|
|
118
203
|
id: string;
|
|
@@ -126,7 +211,7 @@ interface TiquoOrder {
|
|
|
126
211
|
id: string;
|
|
127
212
|
orderNumber: string;
|
|
128
213
|
status: 'draft' | 'pending' | 'confirmed' | 'processing' | 'completed' | 'cancelled' | 'refunded' | 'open_tab';
|
|
129
|
-
paymentStatus: 'pending' | 'paid' | 'partial' | 'refunded' | 'failed' | 'cancelled';
|
|
214
|
+
paymentStatus: 'pending' | 'paid' | 'partial' | 'refunded' | 'partially_refunded' | 'failed' | 'cancelled';
|
|
130
215
|
total: number;
|
|
131
216
|
subtotal: number;
|
|
132
217
|
taxTotal: number;
|
|
@@ -149,7 +234,6 @@ interface GetOrdersResult {
|
|
|
149
234
|
interface TiquoBooking {
|
|
150
235
|
id: string;
|
|
151
236
|
bookingNumber: string;
|
|
152
|
-
confirmationCode: string;
|
|
153
237
|
status: 'draft' | 'scheduled' | 'confirmed' | 'reminder_sent' | 'waiting_room' | 'waiting_list' | 'checked_in' | 'active' | 'in_progress' | 'completed' | 'cancelled' | 'no_show' | 'rescheduled';
|
|
154
238
|
date: number;
|
|
155
239
|
startTime: string;
|
|
@@ -355,4 +439,4 @@ declare function useTiquoAuth(auth: TiquoAuth): {
|
|
|
355
439
|
onAuthStateChange: (cb: AuthStateChangeCallback) => () => void;
|
|
356
440
|
};
|
|
357
441
|
|
|
358
|
-
export { type AuthStateChangeCallback, type GetBookingsOptions, type GetBookingsResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, type TiquoCustomer, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, type TiquoSession, type TiquoUser, type VerifyOTPResult, TiquoAuth as default, useTiquoAuth };
|
|
442
|
+
export { type AuthStateChangeCallback, type GetBookingsOptions, type GetBookingsResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isClerkAuthenticated, trackCustomerPresence, useTiquoAuth };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customer User ID Cookie Utility
|
|
3
|
+
*
|
|
4
|
+
* This module handles setting a cross-subdomain cookie that stores customer user IDs.
|
|
5
|
+
* The cookie is shared across all *.tiquo.app subdomains and persists for 1 year.
|
|
6
|
+
*
|
|
7
|
+
* The cookie is NOT set if the user is logged in with Clerk (dashboard staff).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if the current user is authenticated via Clerk (dashboard staff).
|
|
11
|
+
* If they are, we should NOT set the customer cookie.
|
|
12
|
+
*/
|
|
13
|
+
declare function isClerkAuthenticated(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Get the list of customer user IDs from the cookie.
|
|
16
|
+
*/
|
|
17
|
+
declare function getCustomerUserIds(): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Add a customer user ID to the cookie.
|
|
20
|
+
* Does nothing if:
|
|
21
|
+
* - The user is authenticated via Clerk (dashboard staff)
|
|
22
|
+
* - The user ID is already in the cookie
|
|
23
|
+
* - Running in a non-browser environment
|
|
24
|
+
*
|
|
25
|
+
* @param userId - The user ID from the users table to add
|
|
26
|
+
*/
|
|
27
|
+
declare function addCustomerUserId(userId: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get the pre-filled email from the customer cookie.
|
|
30
|
+
* This fetches the user's email associated with the cookie user IDs.
|
|
31
|
+
* Results are cached for 5 minutes to avoid repeated API calls.
|
|
32
|
+
*
|
|
33
|
+
* @param organizationId - The Clerk organization ID
|
|
34
|
+
* @returns Promise with email and optional name fields, or null if not found
|
|
35
|
+
*/
|
|
36
|
+
declare function getPrefilledEmailFromCookie(organizationId: string): Promise<{
|
|
37
|
+
email: string;
|
|
38
|
+
firstName?: string;
|
|
39
|
+
lastName?: string;
|
|
40
|
+
} | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Clear the cached email data.
|
|
43
|
+
* Call this when the user logs out or clears cookies.
|
|
44
|
+
*/
|
|
45
|
+
declare function clearCachedEmail(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Track customer presence when the cookie is detected.
|
|
48
|
+
* This updates the customer's online status and logs activity.
|
|
49
|
+
*
|
|
50
|
+
* @param organizationId - The Clerk organization ID
|
|
51
|
+
* @returns Promise with tracking results
|
|
52
|
+
*/
|
|
53
|
+
declare function trackCustomerPresence(organizationId: string): Promise<{
|
|
54
|
+
success: boolean;
|
|
55
|
+
results?: Array<{
|
|
56
|
+
userId: string;
|
|
57
|
+
orgCustomerId?: string;
|
|
58
|
+
customerName?: string;
|
|
59
|
+
tracked: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
error?: string;
|
|
62
|
+
}>;
|
|
63
|
+
|
|
1
64
|
/**
|
|
2
65
|
* @tiquo/dom-package
|
|
3
66
|
*
|
|
@@ -42,6 +105,7 @@
|
|
|
42
105
|
* // https://yoursite.com/#access_token=eyJ...&refresh_token=rt_...
|
|
43
106
|
* ```
|
|
44
107
|
*/
|
|
108
|
+
|
|
45
109
|
interface TiquoAuthConfig {
|
|
46
110
|
/** Public key from your Tiquo Auth DOM settings */
|
|
47
111
|
publicKey: string;
|
|
@@ -70,14 +134,35 @@ interface TiquoUser {
|
|
|
70
134
|
id: string;
|
|
71
135
|
email: string;
|
|
72
136
|
}
|
|
137
|
+
interface TiquoCustomerEmail {
|
|
138
|
+
address: string;
|
|
139
|
+
isPrimary: boolean;
|
|
140
|
+
order: number;
|
|
141
|
+
}
|
|
142
|
+
interface TiquoCustomerPhone {
|
|
143
|
+
number: string;
|
|
144
|
+
isPrimary: boolean;
|
|
145
|
+
order: number;
|
|
146
|
+
}
|
|
73
147
|
interface TiquoCustomer {
|
|
74
148
|
id: string;
|
|
75
149
|
firstName?: string;
|
|
76
150
|
lastName?: string;
|
|
77
151
|
displayName?: string;
|
|
78
152
|
customerNumber: string;
|
|
153
|
+
/** Primary email address (convenience field derived from emails array) */
|
|
79
154
|
email?: string;
|
|
155
|
+
/** Primary phone number (convenience field derived from phones array) */
|
|
80
156
|
phone?: string;
|
|
157
|
+
profilePhoto?: string;
|
|
158
|
+
status?: string;
|
|
159
|
+
totalOrders?: number;
|
|
160
|
+
totalSpent?: number;
|
|
161
|
+
lifetimeValue?: number;
|
|
162
|
+
/** Full list of customer email addresses */
|
|
163
|
+
emails?: TiquoCustomerEmail[];
|
|
164
|
+
/** Full list of customer phone numbers */
|
|
165
|
+
phones?: TiquoCustomerPhone[];
|
|
81
166
|
}
|
|
82
167
|
interface TiquoSession {
|
|
83
168
|
user: TiquoUser;
|
|
@@ -107,12 +192,12 @@ interface ProfileUpdateData {
|
|
|
107
192
|
displayName?: string;
|
|
108
193
|
phone?: string;
|
|
109
194
|
profilePhoto?: string;
|
|
195
|
+
emails?: TiquoCustomerEmail[];
|
|
196
|
+
phones?: TiquoCustomerPhone[];
|
|
110
197
|
}
|
|
111
198
|
interface ProfileUpdateResult {
|
|
112
199
|
success: boolean;
|
|
113
|
-
customer: TiquoCustomer
|
|
114
|
-
profilePhoto?: string;
|
|
115
|
-
};
|
|
200
|
+
customer: TiquoCustomer;
|
|
116
201
|
}
|
|
117
202
|
interface TiquoOrderItem {
|
|
118
203
|
id: string;
|
|
@@ -126,7 +211,7 @@ interface TiquoOrder {
|
|
|
126
211
|
id: string;
|
|
127
212
|
orderNumber: string;
|
|
128
213
|
status: 'draft' | 'pending' | 'confirmed' | 'processing' | 'completed' | 'cancelled' | 'refunded' | 'open_tab';
|
|
129
|
-
paymentStatus: 'pending' | 'paid' | 'partial' | 'refunded' | 'failed' | 'cancelled';
|
|
214
|
+
paymentStatus: 'pending' | 'paid' | 'partial' | 'refunded' | 'partially_refunded' | 'failed' | 'cancelled';
|
|
130
215
|
total: number;
|
|
131
216
|
subtotal: number;
|
|
132
217
|
taxTotal: number;
|
|
@@ -149,7 +234,6 @@ interface GetOrdersResult {
|
|
|
149
234
|
interface TiquoBooking {
|
|
150
235
|
id: string;
|
|
151
236
|
bookingNumber: string;
|
|
152
|
-
confirmationCode: string;
|
|
153
237
|
status: 'draft' | 'scheduled' | 'confirmed' | 'reminder_sent' | 'waiting_room' | 'waiting_list' | 'checked_in' | 'active' | 'in_progress' | 'completed' | 'cancelled' | 'no_show' | 'rescheduled';
|
|
154
238
|
date: number;
|
|
155
239
|
startTime: string;
|
|
@@ -355,4 +439,4 @@ declare function useTiquoAuth(auth: TiquoAuth): {
|
|
|
355
439
|
onAuthStateChange: (cb: AuthStateChangeCallback) => () => void;
|
|
356
440
|
};
|
|
357
441
|
|
|
358
|
-
export { type AuthStateChangeCallback, type GetBookingsOptions, type GetBookingsResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, type TiquoCustomer, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, type TiquoSession, type TiquoUser, type VerifyOTPResult, TiquoAuth as default, useTiquoAuth };
|
|
442
|
+
export { type AuthStateChangeCallback, type GetBookingsOptions, type GetBookingsResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isClerkAuthenticated, trackCustomerPresence, useTiquoAuth };
|
package/dist/index.js
CHANGED
|
@@ -22,10 +22,154 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
TiquoAuth: () => TiquoAuth,
|
|
24
24
|
TiquoAuthError: () => TiquoAuthError,
|
|
25
|
+
addCustomerUserId: () => addCustomerUserId,
|
|
26
|
+
clearCachedEmail: () => clearCachedEmail,
|
|
25
27
|
default: () => index_default,
|
|
28
|
+
getCustomerUserIds: () => getCustomerUserIds,
|
|
29
|
+
getPrefilledEmailFromCookie: () => getPrefilledEmailFromCookie,
|
|
30
|
+
isClerkAuthenticated: () => isClerkAuthenticated,
|
|
31
|
+
trackCustomerPresence: () => trackCustomerPresence,
|
|
26
32
|
useTiquoAuth: () => useTiquoAuth
|
|
27
33
|
});
|
|
28
34
|
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/customer-cookie.ts
|
|
37
|
+
var COOKIE_NAME = "tiquo_customer_user_ids";
|
|
38
|
+
var COOKIE_MAX_AGE = 31536e3;
|
|
39
|
+
function isClerkAuthenticated() {
|
|
40
|
+
if (typeof document === "undefined") return false;
|
|
41
|
+
return document.cookie.includes("__clerk_db_jwt") || document.cookie.includes("__session");
|
|
42
|
+
}
|
|
43
|
+
function getCustomerUserIds() {
|
|
44
|
+
if (typeof document === "undefined") return [];
|
|
45
|
+
const match = document.cookie.match(new RegExp(`${COOKIE_NAME}=([^;]+)`));
|
|
46
|
+
if (match) {
|
|
47
|
+
try {
|
|
48
|
+
const decoded = decodeURIComponent(match[1]);
|
|
49
|
+
const parsed = JSON.parse(decoded);
|
|
50
|
+
if (Array.isArray(parsed)) {
|
|
51
|
+
return parsed.filter((id) => typeof id === "string");
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
function addCustomerUserId(userId) {
|
|
60
|
+
if (typeof document === "undefined") return;
|
|
61
|
+
if (typeof window === "undefined") return;
|
|
62
|
+
if (isClerkAuthenticated()) {
|
|
63
|
+
console.log("[Customer Cookie] Skipping - Clerk user detected");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!userId || typeof userId !== "string") {
|
|
67
|
+
console.warn("[Customer Cookie] Invalid userId provided");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const existing = getCustomerUserIds();
|
|
71
|
+
if (existing.includes(userId)) {
|
|
72
|
+
console.log("[Customer Cookie] User ID already in cookie");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
existing.push(userId);
|
|
76
|
+
const hostname = window.location.hostname;
|
|
77
|
+
const isProduction = hostname.endsWith(".tiquo.app") || hostname === "tiquo.app";
|
|
78
|
+
const cookieParts = [
|
|
79
|
+
`${COOKIE_NAME}=${encodeURIComponent(JSON.stringify(existing))}`,
|
|
80
|
+
"path=/",
|
|
81
|
+
`max-age=${COOKIE_MAX_AGE}`,
|
|
82
|
+
"SameSite=Lax"
|
|
83
|
+
];
|
|
84
|
+
if (isProduction) {
|
|
85
|
+
cookieParts.push("domain=.tiquo.app");
|
|
86
|
+
cookieParts.push("Secure");
|
|
87
|
+
}
|
|
88
|
+
document.cookie = cookieParts.join("; ");
|
|
89
|
+
console.log("[Customer Cookie] Added user ID to cookie:", userId);
|
|
90
|
+
}
|
|
91
|
+
var CONVEX_SITE_URL = "https://edge.tiquo.app";
|
|
92
|
+
var cachedEmailData = null;
|
|
93
|
+
var EMAIL_CACHE_TTL = 5 * 60 * 1e3;
|
|
94
|
+
async function getPrefilledEmailFromCookie(organizationId) {
|
|
95
|
+
if (typeof window === "undefined") {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (isClerkAuthenticated()) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const userIds = getCustomerUserIds();
|
|
102
|
+
if (userIds.length === 0) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (cachedEmailData && cachedEmailData.organizationId === organizationId && Date.now() - cachedEmailData.fetchedAt < EMAIL_CACHE_TTL) {
|
|
106
|
+
return {
|
|
107
|
+
email: cachedEmailData.email,
|
|
108
|
+
firstName: cachedEmailData.firstName,
|
|
109
|
+
lastName: cachedEmailData.lastName
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const response = await fetch(`${CONVEX_SITE_URL}/api/customer-cookie-email`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: { "Content-Type": "application/json" },
|
|
116
|
+
body: JSON.stringify({ userIds, organizationId })
|
|
117
|
+
});
|
|
118
|
+
if (response.ok) {
|
|
119
|
+
const data = await response.json();
|
|
120
|
+
if (data.success && data.email) {
|
|
121
|
+
cachedEmailData = {
|
|
122
|
+
organizationId,
|
|
123
|
+
email: data.email,
|
|
124
|
+
firstName: data.firstName,
|
|
125
|
+
lastName: data.lastName,
|
|
126
|
+
fetchedAt: Date.now()
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
email: data.email,
|
|
130
|
+
firstName: data.firstName,
|
|
131
|
+
lastName: data.lastName
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error("[Customer Cookie] Failed to get prefilled email:", error);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function clearCachedEmail() {
|
|
142
|
+
cachedEmailData = null;
|
|
143
|
+
}
|
|
144
|
+
async function trackCustomerPresence(organizationId) {
|
|
145
|
+
if (typeof window === "undefined") {
|
|
146
|
+
return { success: false, error: "Not in browser environment" };
|
|
147
|
+
}
|
|
148
|
+
if (isClerkAuthenticated()) {
|
|
149
|
+
return { success: false, error: "Clerk user detected" };
|
|
150
|
+
}
|
|
151
|
+
const userIds = getCustomerUserIds();
|
|
152
|
+
if (userIds.length === 0) {
|
|
153
|
+
return { success: false, error: "No user IDs in cookie" };
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const response = await fetch(`${CONVEX_SITE_URL}/api/customer-presence`, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: { "Content-Type": "application/json" },
|
|
159
|
+
body: JSON.stringify({ userIds, organizationId })
|
|
160
|
+
});
|
|
161
|
+
if (response.ok) {
|
|
162
|
+
const data = await response.json();
|
|
163
|
+
return data;
|
|
164
|
+
}
|
|
165
|
+
return { success: false, error: "Failed to track presence" };
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("[Customer Cookie] Failed to track presence:", error);
|
|
168
|
+
return { success: false, error: "Network error" };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/index.ts
|
|
29
173
|
var TiquoAuthError = class extends Error {
|
|
30
174
|
constructor(message, code, statusCode) {
|
|
31
175
|
super(message);
|
|
@@ -136,6 +280,9 @@ var TiquoAuth = class {
|
|
|
136
280
|
this.refreshToken = result.refreshToken;
|
|
137
281
|
this.saveTokens();
|
|
138
282
|
await this.refreshSession();
|
|
283
|
+
if (this.session?.user?.id) {
|
|
284
|
+
addCustomerUserId(this.session.user.id);
|
|
285
|
+
}
|
|
139
286
|
this.broadcastTabSync("LOGIN");
|
|
140
287
|
return {
|
|
141
288
|
success: true,
|
|
@@ -185,15 +332,7 @@ var TiquoAuth = class {
|
|
|
185
332
|
if (this.session && result.data?.customer) {
|
|
186
333
|
this.session = {
|
|
187
334
|
...this.session,
|
|
188
|
-
customer:
|
|
189
|
-
id: result.data.customer.id,
|
|
190
|
-
firstName: result.data.customer.firstName,
|
|
191
|
-
lastName: result.data.customer.lastName,
|
|
192
|
-
displayName: result.data.customer.displayName,
|
|
193
|
-
customerNumber: result.data.customer.customerNumber,
|
|
194
|
-
email: result.data.customer.email,
|
|
195
|
-
phone: result.data.customer.phone
|
|
196
|
-
}
|
|
335
|
+
customer: result.data.customer
|
|
197
336
|
};
|
|
198
337
|
this.notifyListeners();
|
|
199
338
|
this.broadcastTabSync("SESSION_UPDATE");
|
|
@@ -341,7 +480,6 @@ var TiquoAuth = class {
|
|
|
341
480
|
body: JSON.stringify({
|
|
342
481
|
publicKey: this.config.publicKey,
|
|
343
482
|
sessionToken: this.accessToken,
|
|
344
|
-
// Use access token for backward compatibility
|
|
345
483
|
customerFlowId
|
|
346
484
|
})
|
|
347
485
|
});
|
|
@@ -570,6 +708,9 @@ var TiquoAuth = class {
|
|
|
570
708
|
customer: result.data.customer,
|
|
571
709
|
expiresAt
|
|
572
710
|
};
|
|
711
|
+
if (this.session.user?.id) {
|
|
712
|
+
addCustomerUserId(this.session.user.id);
|
|
713
|
+
}
|
|
573
714
|
this.notifyListeners();
|
|
574
715
|
this.scheduleRefresh();
|
|
575
716
|
return this.session;
|
|
@@ -804,5 +945,11 @@ var index_default = TiquoAuth;
|
|
|
804
945
|
0 && (module.exports = {
|
|
805
946
|
TiquoAuth,
|
|
806
947
|
TiquoAuthError,
|
|
948
|
+
addCustomerUserId,
|
|
949
|
+
clearCachedEmail,
|
|
950
|
+
getCustomerUserIds,
|
|
951
|
+
getPrefilledEmailFromCookie,
|
|
952
|
+
isClerkAuthenticated,
|
|
953
|
+
trackCustomerPresence,
|
|
807
954
|
useTiquoAuth
|
|
808
955
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,139 @@
|
|
|
1
|
+
// src/customer-cookie.ts
|
|
2
|
+
var COOKIE_NAME = "tiquo_customer_user_ids";
|
|
3
|
+
var COOKIE_MAX_AGE = 31536e3;
|
|
4
|
+
function isClerkAuthenticated() {
|
|
5
|
+
if (typeof document === "undefined") return false;
|
|
6
|
+
return document.cookie.includes("__clerk_db_jwt") || document.cookie.includes("__session");
|
|
7
|
+
}
|
|
8
|
+
function getCustomerUserIds() {
|
|
9
|
+
if (typeof document === "undefined") return [];
|
|
10
|
+
const match = document.cookie.match(new RegExp(`${COOKIE_NAME}=([^;]+)`));
|
|
11
|
+
if (match) {
|
|
12
|
+
try {
|
|
13
|
+
const decoded = decodeURIComponent(match[1]);
|
|
14
|
+
const parsed = JSON.parse(decoded);
|
|
15
|
+
if (Array.isArray(parsed)) {
|
|
16
|
+
return parsed.filter((id) => typeof id === "string");
|
|
17
|
+
}
|
|
18
|
+
} catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
function addCustomerUserId(userId) {
|
|
25
|
+
if (typeof document === "undefined") return;
|
|
26
|
+
if (typeof window === "undefined") return;
|
|
27
|
+
if (isClerkAuthenticated()) {
|
|
28
|
+
console.log("[Customer Cookie] Skipping - Clerk user detected");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!userId || typeof userId !== "string") {
|
|
32
|
+
console.warn("[Customer Cookie] Invalid userId provided");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const existing = getCustomerUserIds();
|
|
36
|
+
if (existing.includes(userId)) {
|
|
37
|
+
console.log("[Customer Cookie] User ID already in cookie");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
existing.push(userId);
|
|
41
|
+
const hostname = window.location.hostname;
|
|
42
|
+
const isProduction = hostname.endsWith(".tiquo.app") || hostname === "tiquo.app";
|
|
43
|
+
const cookieParts = [
|
|
44
|
+
`${COOKIE_NAME}=${encodeURIComponent(JSON.stringify(existing))}`,
|
|
45
|
+
"path=/",
|
|
46
|
+
`max-age=${COOKIE_MAX_AGE}`,
|
|
47
|
+
"SameSite=Lax"
|
|
48
|
+
];
|
|
49
|
+
if (isProduction) {
|
|
50
|
+
cookieParts.push("domain=.tiquo.app");
|
|
51
|
+
cookieParts.push("Secure");
|
|
52
|
+
}
|
|
53
|
+
document.cookie = cookieParts.join("; ");
|
|
54
|
+
console.log("[Customer Cookie] Added user ID to cookie:", userId);
|
|
55
|
+
}
|
|
56
|
+
var CONVEX_SITE_URL = "https://edge.tiquo.app";
|
|
57
|
+
var cachedEmailData = null;
|
|
58
|
+
var EMAIL_CACHE_TTL = 5 * 60 * 1e3;
|
|
59
|
+
async function getPrefilledEmailFromCookie(organizationId) {
|
|
60
|
+
if (typeof window === "undefined") {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (isClerkAuthenticated()) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const userIds = getCustomerUserIds();
|
|
67
|
+
if (userIds.length === 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (cachedEmailData && cachedEmailData.organizationId === organizationId && Date.now() - cachedEmailData.fetchedAt < EMAIL_CACHE_TTL) {
|
|
71
|
+
return {
|
|
72
|
+
email: cachedEmailData.email,
|
|
73
|
+
firstName: cachedEmailData.firstName,
|
|
74
|
+
lastName: cachedEmailData.lastName
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(`${CONVEX_SITE_URL}/api/customer-cookie-email`, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: { "Content-Type": "application/json" },
|
|
81
|
+
body: JSON.stringify({ userIds, organizationId })
|
|
82
|
+
});
|
|
83
|
+
if (response.ok) {
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
if (data.success && data.email) {
|
|
86
|
+
cachedEmailData = {
|
|
87
|
+
organizationId,
|
|
88
|
+
email: data.email,
|
|
89
|
+
firstName: data.firstName,
|
|
90
|
+
lastName: data.lastName,
|
|
91
|
+
fetchedAt: Date.now()
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
email: data.email,
|
|
95
|
+
firstName: data.firstName,
|
|
96
|
+
lastName: data.lastName
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error("[Customer Cookie] Failed to get prefilled email:", error);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function clearCachedEmail() {
|
|
107
|
+
cachedEmailData = null;
|
|
108
|
+
}
|
|
109
|
+
async function trackCustomerPresence(organizationId) {
|
|
110
|
+
if (typeof window === "undefined") {
|
|
111
|
+
return { success: false, error: "Not in browser environment" };
|
|
112
|
+
}
|
|
113
|
+
if (isClerkAuthenticated()) {
|
|
114
|
+
return { success: false, error: "Clerk user detected" };
|
|
115
|
+
}
|
|
116
|
+
const userIds = getCustomerUserIds();
|
|
117
|
+
if (userIds.length === 0) {
|
|
118
|
+
return { success: false, error: "No user IDs in cookie" };
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const response = await fetch(`${CONVEX_SITE_URL}/api/customer-presence`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify({ userIds, organizationId })
|
|
125
|
+
});
|
|
126
|
+
if (response.ok) {
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
return { success: false, error: "Failed to track presence" };
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("[Customer Cookie] Failed to track presence:", error);
|
|
133
|
+
return { success: false, error: "Network error" };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
1
137
|
// src/index.ts
|
|
2
138
|
var TiquoAuthError = class extends Error {
|
|
3
139
|
constructor(message, code, statusCode) {
|
|
@@ -109,6 +245,9 @@ var TiquoAuth = class {
|
|
|
109
245
|
this.refreshToken = result.refreshToken;
|
|
110
246
|
this.saveTokens();
|
|
111
247
|
await this.refreshSession();
|
|
248
|
+
if (this.session?.user?.id) {
|
|
249
|
+
addCustomerUserId(this.session.user.id);
|
|
250
|
+
}
|
|
112
251
|
this.broadcastTabSync("LOGIN");
|
|
113
252
|
return {
|
|
114
253
|
success: true,
|
|
@@ -158,15 +297,7 @@ var TiquoAuth = class {
|
|
|
158
297
|
if (this.session && result.data?.customer) {
|
|
159
298
|
this.session = {
|
|
160
299
|
...this.session,
|
|
161
|
-
customer:
|
|
162
|
-
id: result.data.customer.id,
|
|
163
|
-
firstName: result.data.customer.firstName,
|
|
164
|
-
lastName: result.data.customer.lastName,
|
|
165
|
-
displayName: result.data.customer.displayName,
|
|
166
|
-
customerNumber: result.data.customer.customerNumber,
|
|
167
|
-
email: result.data.customer.email,
|
|
168
|
-
phone: result.data.customer.phone
|
|
169
|
-
}
|
|
300
|
+
customer: result.data.customer
|
|
170
301
|
};
|
|
171
302
|
this.notifyListeners();
|
|
172
303
|
this.broadcastTabSync("SESSION_UPDATE");
|
|
@@ -314,7 +445,6 @@ var TiquoAuth = class {
|
|
|
314
445
|
body: JSON.stringify({
|
|
315
446
|
publicKey: this.config.publicKey,
|
|
316
447
|
sessionToken: this.accessToken,
|
|
317
|
-
// Use access token for backward compatibility
|
|
318
448
|
customerFlowId
|
|
319
449
|
})
|
|
320
450
|
});
|
|
@@ -543,6 +673,9 @@ var TiquoAuth = class {
|
|
|
543
673
|
customer: result.data.customer,
|
|
544
674
|
expiresAt
|
|
545
675
|
};
|
|
676
|
+
if (this.session.user?.id) {
|
|
677
|
+
addCustomerUserId(this.session.user.id);
|
|
678
|
+
}
|
|
546
679
|
this.notifyListeners();
|
|
547
680
|
this.scheduleRefresh();
|
|
548
681
|
return this.session;
|
|
@@ -776,6 +909,12 @@ var index_default = TiquoAuth;
|
|
|
776
909
|
export {
|
|
777
910
|
TiquoAuth,
|
|
778
911
|
TiquoAuthError,
|
|
912
|
+
addCustomerUserId,
|
|
913
|
+
clearCachedEmail,
|
|
779
914
|
index_default as default,
|
|
915
|
+
getCustomerUserIds,
|
|
916
|
+
getPrefilledEmailFromCookie,
|
|
917
|
+
isClerkAuthenticated,
|
|
918
|
+
trackCustomerPresence,
|
|
780
919
|
useTiquoAuth
|
|
781
920
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiquo/dom-package",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Tiquo SDK for third-party websites - authentication, customer profiles, orders, bookings, and enquiries",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "restricted"
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
+
"scripts",
|
|
20
21
|
"README.md"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
25
26
|
"lint": "eslint src/",
|
|
26
27
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"prepublishOnly": "npm run build"
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"postinstall": "node scripts/postinstall.js"
|
|
28
30
|
},
|
|
29
31
|
"keywords": [
|
|
30
32
|
"tiquo",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const asciiArt = `
|
|
4
|
+
_ _
|
|
5
|
+
| |_(_) __ _ _ _ ___
|
|
6
|
+
| __| |/ _\` | | | |/ _ \\
|
|
7
|
+
| |_| | (_| | |_| | (_) |
|
|
8
|
+
\\__|_|\\__, |\\__,_|\\___/
|
|
9
|
+
|_|
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
console.log(asciiArt);
|
|
13
|
+
console.log('To find out more about Tiquo, visit \x1b[34mhttps://www.tiquo.co/\x1b[0m');
|
|
14
|
+
console.log('');
|