@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 CHANGED
@@ -9,6 +9,7 @@ Tiquo SDK for third-party websites. Integrate authentication, customer profiles,
9
9
  - **Multi-Tab Sync** - Auth state automatically syncs across all browser tabs
10
10
  - **Native App Integration** - WebView token injection for iOS/Android hybrid apps
11
11
  - **Customer Flow Integration** - Embed authenticated customer flows with one line of code
12
+ - **First-Party Website Analytics** - Cookie-free pageview, session, attribution, and known-customer activity tracking
12
13
  - **Phone Number Utilities** - Validation, formatting, and country code support for 200+ countries
13
14
  - **Framework Agnostic** - Works with React, Vue, Svelte, or vanilla JavaScript
14
15
  - **TypeScript Support** - Full type definitions included
@@ -39,6 +40,19 @@ const auth = new TiquoAuth({
39
40
  });
40
41
  ```
41
42
 
43
+ Website analytics starts automatically when you initialize `TiquoAuth` or `TiquoCMS`.
44
+ The same public key is used across all websites in your organization; Tiquo records
45
+ the source domain for each event and rolls `www.example.com` into `example.com`.
46
+ Other subdomains are tracked as separate websites.
47
+
48
+ ```typescript
49
+ // Optional custom analytics events
50
+ await auth.analytics?.track('booking_started', {
51
+ eventName: 'Booking Started',
52
+ eventProperties: { serviceId: 'svc_123' }
53
+ });
54
+ ```
55
+
42
56
  ### 3. Authenticate Users
43
57
 
44
58
  ```typescript
@@ -65,6 +79,7 @@ const auth = new TiquoAuth({
65
79
  storagePrefix?: string; // Optional: localStorage key prefix
66
80
  debug?: boolean; // Optional: Enable debug logging
67
81
  enableTabSync?: boolean; // Optional: Multi-tab session sync (default: true)
82
+ analytics?: boolean; // Optional: Website analytics (default: true)
68
83
  });
69
84
  ```
70
85
 
@@ -137,12 +152,24 @@ const result = await auth.updateProfile({
137
152
  console.log(result.customer.firstName); // 'John'
138
153
  ```
139
154
 
155
+ Profile photos can be passed as a URL, a browser `File`/`Blob`, or a `data:image/...`/`blob:...` URI:
156
+
157
+ ```typescript
158
+ const file = fileInput.files?.[0];
159
+ if (file) {
160
+ await auth.updateProfile({ profilePhoto: file });
161
+ }
162
+
163
+ // Or upload just the photo:
164
+ await auth.uploadProfilePhoto(file);
165
+ ```
166
+
140
167
  **Available fields:**
141
168
  - `firstName` - Customer's first name
142
169
  - `lastName` - Customer's last name
143
170
  - `displayName` - Display name (nickname)
144
171
  - `phone` - Primary phone number (E.164 format recommended: `+[country code][number]`)
145
- - `profilePhoto` - URL to profile photo
172
+ - `profilePhoto` - URL, File/Blob, or `data:image/...`/`blob:...` URI for profile photo
146
173
  - `phones` - Full phone list (array of `{ number, isPrimary, order }`)
147
174
 
148
175
  > **Important:** Phone numbers should include a country code (e.g., `+1` for US, `+44` for UK). Use `TiquoPhone.buildPhone()` to construct properly formatted numbers from a country selector + national number input. See [Phone Number Utilities](#phone-number-utilities) below.
package/dist/index.d.mts CHANGED
@@ -209,6 +209,37 @@ declare function buildPhone(countryCode: string, nationalNumber: string): string
209
209
  * ```
210
210
  */
211
211
 
212
+ declare class TiquoAnalytics {
213
+ private static activeInstances;
214
+ private config;
215
+ private clientSessionId;
216
+ private pageStartedAt;
217
+ private lastPath;
218
+ private started;
219
+ constructor(config: TiquoAnalyticsConfig);
220
+ start(): void;
221
+ trackPageview(options?: TiquoAnalyticsEventOptions): Promise<void>;
222
+ track(eventType: string, options?: TiquoAnalyticsEventOptions): Promise<void>;
223
+ identify(options?: TiquoAnalyticsEventOptions): Promise<void>;
224
+ private trackEngagement;
225
+ private send;
226
+ private getClientSessionId;
227
+ private log;
228
+ private adoptConfig;
229
+ }
230
+ declare class TiquoCMS {
231
+ private config;
232
+ analytics: TiquoAnalytics | null;
233
+ constructor(config: TiquoCMSConfig);
234
+ /**
235
+ * Fetch a published CMS page for the website attached to this public key.
236
+ *
237
+ * This intentionally goes through the Tiquo edge API rather than exposing
238
+ * Convex connection details to the consuming website.
239
+ */
240
+ getPage(request: TiquoCMSPageRequest): Promise<TiquoCMSPage | null>;
241
+ private log;
242
+ }
212
243
  interface TiquoAuthConfig {
213
244
  /** Public key from your Tiquo Auth DOM settings */
214
245
  publicKey: string;
@@ -224,6 +255,84 @@ interface TiquoAuthConfig {
224
255
  accessToken?: string;
225
256
  /** Pre-authenticated refresh token (for WebView injection from native apps) */
226
257
  refreshToken?: string;
258
+ /** Enable first-party website analytics (default: true) */
259
+ analytics?: boolean;
260
+ }
261
+ interface TiquoCMSConfig {
262
+ /** Public key from your Tiquo Auth DOM settings */
263
+ publicKey: string;
264
+ /** API endpoint (defaults to production) */
265
+ apiEndpoint?: string;
266
+ /** Enable debug logging */
267
+ debug?: boolean;
268
+ /** Enable first-party website analytics (default: true) */
269
+ analytics?: boolean;
270
+ }
271
+ interface TiquoAnalyticsConfig {
272
+ /** Public key from your Tiquo Auth DOM settings */
273
+ publicKey: string;
274
+ /** API endpoint (defaults to production) */
275
+ apiEndpoint?: string;
276
+ /** Enable debug logging */
277
+ debug?: boolean;
278
+ /** Optional CMS website slug */
279
+ siteSlug?: string;
280
+ /** Enable automatic pageview tracking (default: true) */
281
+ autoTrackPageviews?: boolean;
282
+ /** Optional access-token getter used to associate events with known customers */
283
+ getAccessToken?: () => string | null | undefined;
284
+ }
285
+ interface TiquoAnalyticsEventOptions {
286
+ eventName?: string;
287
+ eventProperties?: Record<string, unknown>;
288
+ siteSlug?: string;
289
+ pageSlug?: string;
290
+ path?: string;
291
+ url?: string;
292
+ title?: string;
293
+ referrer?: string;
294
+ durationMs?: number;
295
+ scrollDepth?: number;
296
+ identityLinkType?: "auth_dom_login" | "email_capture" | "booking" | "enquiry" | "order" | "customer_portal" | "manual";
297
+ }
298
+ interface TiquoCMSPageRequest {
299
+ /** CMS website slug */
300
+ siteSlug: string;
301
+ /** CMS page slug, defaults to "home" */
302
+ pageSlug?: string;
303
+ /** Optional template contract guard */
304
+ templateId?: string;
305
+ }
306
+ interface TiquoCMSBlock {
307
+ id: string;
308
+ type: string;
309
+ props: Record<string, unknown>;
310
+ locked?: boolean;
311
+ lockedBy?: string;
312
+ required?: boolean;
313
+ }
314
+ interface TiquoCMSPage {
315
+ id: string;
316
+ site: {
317
+ id: string;
318
+ name: string;
319
+ slug?: string;
320
+ templateId?: string;
321
+ templateVersion?: number;
322
+ globalConfig?: unknown;
323
+ };
324
+ page: {
325
+ id: string;
326
+ title: string;
327
+ slug: string;
328
+ path: string;
329
+ blocks: TiquoCMSBlock[];
330
+ settings?: unknown;
331
+ metaTitle?: string;
332
+ metaDescription?: string;
333
+ publishedAt?: number;
334
+ updatedAt: number;
335
+ };
227
336
  }
228
337
  declare global {
229
338
  interface Window {
@@ -305,7 +414,13 @@ interface ProfileUpdateData {
305
414
  * for country+national input, or TiquoPhone.validate() to pre-check.
306
415
  */
307
416
  phone?: string;
308
- profilePhoto?: string;
417
+ /**
418
+ * URL to a profile photo, a data/blob URI, or a browser File/Blob.
419
+ *
420
+ * File/Blob and data/blob URI values are uploaded to Tiquo storage before the
421
+ * profile is updated. Remote URLs are stored as-is.
422
+ */
423
+ profilePhoto?: string | Blob;
309
424
  emails?: TiquoCustomerEmail[];
310
425
  /**
311
426
  * Full phone list. Each number should be in E.164 format: +[country code][number].
@@ -317,13 +432,17 @@ interface ProfileUpdateResult {
317
432
  success: boolean;
318
433
  customer: TiquoCustomer;
319
434
  }
435
+ interface ProfilePhotoUploadResult extends ProfileUpdateResult {
436
+ profilePhoto: string;
437
+ storageId: string;
438
+ }
320
439
  interface TiquoOrderItem {
321
440
  id: string;
322
441
  name: string;
323
442
  quantity: number;
324
443
  unitPrice: number;
325
444
  total: number;
326
- type: 'product' | 'booking' | 'custom';
445
+ type: "product" | "booking" | "custom";
327
446
  }
328
447
  /**
329
448
  * An order belonging to the authenticated customer.
@@ -335,8 +454,8 @@ interface TiquoOrderItem {
335
454
  interface TiquoOrder {
336
455
  id: string;
337
456
  orderNumber: string;
338
- status: 'draft' | 'processing' | 'completed' | 'cancelled' | 'refunded' | 'open_tab';
339
- paymentStatus: 'pending' | 'paid' | 'partial' | 'refunded' | 'partially_refunded' | 'failed' | 'cancelled';
457
+ status: "draft" | "processing" | "completed" | "cancelled" | "refunded" | "open_tab";
458
+ paymentStatus: "pending" | "paid" | "partial" | "refunded" | "partially_refunded" | "failed" | "cancelled";
340
459
  total: number;
341
460
  subtotal: number;
342
461
  taxTotal: number;
@@ -344,12 +463,12 @@ interface TiquoOrder {
344
463
  items: TiquoOrderItem[];
345
464
  createdAt: number;
346
465
  completedAt?: number;
347
- customerRole: 'primary' | 'attendee' | 'billing' | 'referrer' | 'other';
466
+ customerRole: "primary" | "attendee" | "billing" | "referrer" | "other";
348
467
  }
349
468
  interface GetOrdersOptions {
350
469
  limit?: number;
351
470
  cursor?: string;
352
- status?: TiquoOrder['status'];
471
+ status?: TiquoOrder["status"];
353
472
  }
354
473
  interface GetOrdersResult {
355
474
  orders: TiquoOrder[];
@@ -365,7 +484,7 @@ interface TiquoReceiptItem {
365
484
  tax: number;
366
485
  discount: number;
367
486
  total: number;
368
- type: 'product' | 'booking' | 'custom' | 'membership';
487
+ type: "product" | "booking" | "custom" | "membership";
369
488
  specialInstructions?: string;
370
489
  }
371
490
  interface TiquoReceiptBusiness {
@@ -392,8 +511,8 @@ interface TiquoReceiptCustomer {
392
511
  interface TiquoReceiptOrder {
393
512
  id: string;
394
513
  orderNumber: string;
395
- status: TiquoOrder['status'];
396
- paymentStatus: TiquoOrder['paymentStatus'];
514
+ status: TiquoOrder["status"];
515
+ paymentStatus: TiquoOrder["paymentStatus"];
397
516
  currency: string;
398
517
  subtotal: number;
399
518
  taxTotal: number;
@@ -433,7 +552,7 @@ interface TiquoReceipt {
433
552
  interface TiquoBooking {
434
553
  id: string;
435
554
  bookingNumber: string;
436
- status: 'scheduled' | 'confirmed' | 'reminder_sent' | 'waiting_room' | 'waiting_list' | 'checked_in' | 'active' | 'in_progress' | 'completed' | 'cancelled' | 'no_show' | 'rescheduled';
555
+ status: "scheduled" | "confirmed" | "reminder_sent" | "waiting_room" | "waiting_list" | "checked_in" | "active" | "in_progress" | "completed" | "cancelled" | "no_show" | "rescheduled";
437
556
  date: number;
438
557
  startTime: string;
439
558
  endTime: string;
@@ -457,7 +576,7 @@ interface TiquoBooking {
457
576
  interface GetBookingsOptions {
458
577
  limit?: number;
459
578
  cursor?: string;
460
- status?: TiquoBooking['status'];
579
+ status?: TiquoBooking["status"];
461
580
  upcoming?: boolean;
462
581
  }
463
582
  interface GetBookingsResult {
@@ -472,27 +591,27 @@ interface TiquoEnquiry {
472
591
  subject: string;
473
592
  message: string;
474
593
  category: string;
475
- status: 'new' | 'in_progress' | 'waiting_customer' | 'waiting_internal' | 'won' | 'lost' | 'closed' | 'resolved' | 'archived';
476
- priority: 'low' | 'medium' | 'high' | 'urgent';
477
- source: 'online' | 'website' | 'phone' | 'email' | 'walk_in' | 'social' | 'referral' | 'pos' | 'admin';
594
+ status: "new" | "in_progress" | "waiting_customer" | "waiting_internal" | "won" | "lost" | "closed" | "resolved" | "archived";
595
+ priority: "low" | "medium" | "high" | "urgent";
596
+ source: "online" | "website" | "phone" | "email" | "walk_in" | "social" | "referral" | "pos" | "admin";
478
597
  responseCount: number;
479
598
  createdAt: string;
480
599
  updatedAt: string;
481
600
  firstResponseAt?: string;
482
601
  resolvedAt?: string;
483
- customerRole: 'primary' | 'attendee' | 'billing' | 'referrer' | 'other';
602
+ customerRole: "primary" | "attendee" | "billing" | "referrer" | "other";
484
603
  }
485
604
  interface GetEnquiriesOptions {
486
605
  limit?: number;
487
606
  cursor?: string;
488
- status?: TiquoEnquiry['status'];
607
+ status?: TiquoEnquiry["status"];
489
608
  }
490
609
  interface GetEnquiriesResult {
491
610
  enquiries: TiquoEnquiry[];
492
611
  hasMore: boolean;
493
612
  nextCursor?: string;
494
613
  }
495
- type TiquoCompanyRelationship = 'employee' | 'contractor' | 'manager' | 'executive' | 'owner' | 'contact' | 'other';
614
+ type TiquoCompanyRelationship = "employee" | "contractor" | "manager" | "executive" | "owner" | "contact" | "other";
496
615
  /**
497
616
  * The authenticated customer's membership in a company. Each company the
498
617
  * customer belongs to has its own membership record — a customer can be
@@ -530,9 +649,9 @@ interface TiquoCompany {
530
649
  postalCode?: string;
531
650
  country?: string;
532
651
  industry?: string;
533
- companySize?: '1-10' | '11-50' | '51-200' | '201-500' | '501-1000' | '1000+';
534
- status: 'active' | 'inactive' | 'archived';
535
- type?: 'client' | 'prospect' | 'vendor' | 'partner' | 'other';
652
+ companySize?: "1-10" | "11-50" | "51-200" | "201-500" | "501-1000" | "1000+";
653
+ status: "active" | "inactive" | "archived";
654
+ type?: "client" | "prospect" | "vendor" | "partner" | "other";
536
655
  membership: TiquoCompanyMembership;
537
656
  }
538
657
  interface GetCompaniesResult {
@@ -583,6 +702,7 @@ declare class TiquoAuth {
583
702
  private visibilityHandler;
584
703
  private iframeObserver;
585
704
  private injectedIframes;
705
+ analytics: TiquoAnalytics | null;
586
706
  private broadcastChannel;
587
707
  private tabId;
588
708
  private isProcessingTabSync;
@@ -615,6 +735,14 @@ declare class TiquoAuth {
615
735
  * to construct from a country selector and national number.
616
736
  */
617
737
  updateProfile(updates: ProfileUpdateData): Promise<ProfileUpdateResult>;
738
+ /**
739
+ * Upload and save the authenticated customer's profile photo.
740
+ *
741
+ * Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
742
+ * image is uploaded to Tiquo storage first, and the customer profile is
743
+ * updated with the URL.
744
+ */
745
+ uploadProfilePhoto(photo: Blob | string): Promise<ProfilePhotoUploadResult>;
618
746
  /**
619
747
  * Log out the current user
620
748
  */
@@ -654,7 +782,7 @@ declare class TiquoAuth {
654
782
  * future, since they're effectively history. Use `getBookings()` without
655
783
  * `upcoming: true` if you need those.
656
784
  */
657
- getUpcomingBookings(options?: Omit<GetBookingsOptions, 'upcoming'>): Promise<GetBookingsResult>;
785
+ getUpcomingBookings(options?: Omit<GetBookingsOptions, "upcoming">): Promise<GetBookingsResult>;
658
786
  /**
659
787
  * Get a printable receipt for a single order owned by the authenticated
660
788
  * customer. Only resolves for orders that are paid (full or partial),
@@ -747,6 +875,9 @@ declare class TiquoAuth {
747
875
  * Check for tokens injected by native apps (WebView integration)
748
876
  */
749
877
  private checkForInjectedTokens;
878
+ private extractUploadableProfilePhoto;
879
+ private isProfilePhotoBlobUrl;
880
+ private profilePhotoToBlob;
750
881
  private request;
751
882
  /**
752
883
  * Ensure we have a valid access token, refreshing if necessary
@@ -791,6 +922,7 @@ declare function useTiquoAuth(auth: TiquoAuth): {
791
922
  verifyOTP: (email: string, otp: string) => Promise<VerifyOTPResult>;
792
923
  logout: () => Promise<void>;
793
924
  updateProfile: (updates: ProfileUpdateData) => Promise<ProfileUpdateResult>;
925
+ uploadProfilePhoto: (photo: Blob | string) => Promise<ProfilePhotoUploadResult>;
794
926
  getOrders: (options?: GetOrdersOptions) => Promise<GetOrdersResult>;
795
927
  getBookings: (options?: GetBookingsOptions) => Promise<GetBookingsResult>;
796
928
  getUpcomingBookings: (options?: Omit<GetBookingsOptions, "upcoming">) => Promise<GetBookingsResult>;
@@ -860,4 +992,4 @@ declare class TiquoPhone {
860
992
  static buildPhone: typeof buildPhone;
861
993
  }
862
994
 
863
- export { type AuthStateChangeCallback, type CountryPhoneInfo, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };
995
+ export { type AuthStateChangeCallback, type CountryPhoneInfo, type GetBookingsOptions, type GetBookingsResult, type GetCompaniesResult, type GetCompanyColleaguesResult, type GetEnquiriesOptions, type GetEnquiriesResult, type GetOrdersOptions, type GetOrdersResult, type IframeTokenResult, type PhoneValidationResult, type ProfilePhotoUploadResult, type ProfileUpdateData, type ProfileUpdateResult, type SendOTPResult, TiquoAnalytics, type TiquoAnalyticsConfig, type TiquoAnalyticsEventOptions, TiquoAuth, type TiquoAuthConfig, TiquoAuthError, type TiquoBooking, TiquoCMS, type TiquoCMSBlock, type TiquoCMSConfig, type TiquoCMSPage, type TiquoCMSPageRequest, type TiquoCompany, type TiquoCompanyColleague, type TiquoCompanyMembership, type TiquoCompanyRelationship, type TiquoCustomer, type TiquoCustomerEmail, type TiquoCustomerPhone, type TiquoEnquiry, type TiquoOrder, type TiquoOrderItem, TiquoPhone, type TiquoReceipt, type TiquoReceiptBusiness, type TiquoReceiptCustomer, type TiquoReceiptItem, type TiquoReceiptOrder, type TiquoSession, type TiquoUser, type VerifyOTPResult, addCustomerUserId, clearCachedEmail, TiquoAuth as default, getCustomerUserIds, getPrefilledEmailFromCookie, isDashboardSession, trackCustomerPresence, useTiquoAuth };