@tiquo/dom-package 1.5.0 → 1.5.1
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 +13 -1
- package/dist/index.d.mts +83 -2
- package/dist/index.d.ts +83 -2
- package/dist/index.js +193 -10
- package/dist/index.mjs +192 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,12 +137,24 @@ const result = await auth.updateProfile({
|
|
|
137
137
|
console.log(result.customer.firstName); // 'John'
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
Profile photos can be passed as a URL, a browser `File`/`Blob`, or a `data:image/...`/`blob:...` URI:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const file = fileInput.files?.[0];
|
|
144
|
+
if (file) {
|
|
145
|
+
await auth.updateProfile({ profilePhoto: file });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Or upload just the photo:
|
|
149
|
+
await auth.uploadProfilePhoto(file);
|
|
150
|
+
```
|
|
151
|
+
|
|
140
152
|
**Available fields:**
|
|
141
153
|
- `firstName` - Customer's first name
|
|
142
154
|
- `lastName` - Customer's last name
|
|
143
155
|
- `displayName` - Display name (nickname)
|
|
144
156
|
- `phone` - Primary phone number (E.164 format recommended: `+[country code][number]`)
|
|
145
|
-
- `profilePhoto` - URL
|
|
157
|
+
- `profilePhoto` - URL, File/Blob, or `data:image/...`/`blob:...` URI for profile photo
|
|
146
158
|
- `phones` - Full phone list (array of `{ number, isPrimary, order }`)
|
|
147
159
|
|
|
148
160
|
> **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,18 @@ declare function buildPhone(countryCode: string, nationalNumber: string): string
|
|
|
209
209
|
* ```
|
|
210
210
|
*/
|
|
211
211
|
|
|
212
|
+
declare class TiquoCMS {
|
|
213
|
+
private config;
|
|
214
|
+
constructor(config: TiquoCMSConfig);
|
|
215
|
+
/**
|
|
216
|
+
* Fetch a published CMS page for the website attached to this public key.
|
|
217
|
+
*
|
|
218
|
+
* This intentionally goes through the Tiquo edge API rather than exposing
|
|
219
|
+
* Convex connection details to the consuming website.
|
|
220
|
+
*/
|
|
221
|
+
getPage(request: TiquoCMSPageRequest): Promise<TiquoCMSPage | null>;
|
|
222
|
+
private log;
|
|
223
|
+
}
|
|
212
224
|
interface TiquoAuthConfig {
|
|
213
225
|
/** Public key from your Tiquo Auth DOM settings */
|
|
214
226
|
publicKey: string;
|
|
@@ -225,6 +237,53 @@ interface TiquoAuthConfig {
|
|
|
225
237
|
/** Pre-authenticated refresh token (for WebView injection from native apps) */
|
|
226
238
|
refreshToken?: string;
|
|
227
239
|
}
|
|
240
|
+
interface TiquoCMSConfig {
|
|
241
|
+
/** Public key from your Tiquo Auth DOM settings */
|
|
242
|
+
publicKey: string;
|
|
243
|
+
/** API endpoint (defaults to production) */
|
|
244
|
+
apiEndpoint?: string;
|
|
245
|
+
/** Enable debug logging */
|
|
246
|
+
debug?: boolean;
|
|
247
|
+
}
|
|
248
|
+
interface TiquoCMSPageRequest {
|
|
249
|
+
/** CMS website slug */
|
|
250
|
+
siteSlug: string;
|
|
251
|
+
/** CMS page slug, defaults to "home" */
|
|
252
|
+
pageSlug?: string;
|
|
253
|
+
/** Optional template contract guard */
|
|
254
|
+
templateId?: string;
|
|
255
|
+
}
|
|
256
|
+
interface TiquoCMSBlock {
|
|
257
|
+
id: string;
|
|
258
|
+
type: string;
|
|
259
|
+
props: Record<string, unknown>;
|
|
260
|
+
locked?: boolean;
|
|
261
|
+
lockedBy?: string;
|
|
262
|
+
required?: boolean;
|
|
263
|
+
}
|
|
264
|
+
interface TiquoCMSPage {
|
|
265
|
+
id: string;
|
|
266
|
+
site: {
|
|
267
|
+
id: string;
|
|
268
|
+
name: string;
|
|
269
|
+
slug?: string;
|
|
270
|
+
templateId?: string;
|
|
271
|
+
templateVersion?: number;
|
|
272
|
+
globalConfig?: unknown;
|
|
273
|
+
};
|
|
274
|
+
page: {
|
|
275
|
+
id: string;
|
|
276
|
+
title: string;
|
|
277
|
+
slug: string;
|
|
278
|
+
path: string;
|
|
279
|
+
blocks: TiquoCMSBlock[];
|
|
280
|
+
settings?: unknown;
|
|
281
|
+
metaTitle?: string;
|
|
282
|
+
metaDescription?: string;
|
|
283
|
+
publishedAt?: number;
|
|
284
|
+
updatedAt: number;
|
|
285
|
+
};
|
|
286
|
+
}
|
|
228
287
|
declare global {
|
|
229
288
|
interface Window {
|
|
230
289
|
__TIQUO_INIT_TOKEN__?: {
|
|
@@ -305,7 +364,13 @@ interface ProfileUpdateData {
|
|
|
305
364
|
* for country+national input, or TiquoPhone.validate() to pre-check.
|
|
306
365
|
*/
|
|
307
366
|
phone?: string;
|
|
308
|
-
|
|
367
|
+
/**
|
|
368
|
+
* URL to a profile photo, a data/blob URI, or a browser File/Blob.
|
|
369
|
+
*
|
|
370
|
+
* File/Blob and data/blob URI values are uploaded to Tiquo storage before the
|
|
371
|
+
* profile is updated. Remote URLs are stored as-is.
|
|
372
|
+
*/
|
|
373
|
+
profilePhoto?: string | Blob;
|
|
309
374
|
emails?: TiquoCustomerEmail[];
|
|
310
375
|
/**
|
|
311
376
|
* Full phone list. Each number should be in E.164 format: +[country code][number].
|
|
@@ -317,6 +382,10 @@ interface ProfileUpdateResult {
|
|
|
317
382
|
success: boolean;
|
|
318
383
|
customer: TiquoCustomer;
|
|
319
384
|
}
|
|
385
|
+
interface ProfilePhotoUploadResult extends ProfileUpdateResult {
|
|
386
|
+
profilePhoto: string;
|
|
387
|
+
storageId: string;
|
|
388
|
+
}
|
|
320
389
|
interface TiquoOrderItem {
|
|
321
390
|
id: string;
|
|
322
391
|
name: string;
|
|
@@ -615,6 +684,14 @@ declare class TiquoAuth {
|
|
|
615
684
|
* to construct from a country selector and national number.
|
|
616
685
|
*/
|
|
617
686
|
updateProfile(updates: ProfileUpdateData): Promise<ProfileUpdateResult>;
|
|
687
|
+
/**
|
|
688
|
+
* Upload and save the authenticated customer's profile photo.
|
|
689
|
+
*
|
|
690
|
+
* Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
|
|
691
|
+
* image is uploaded to Tiquo storage first, and the customer profile is
|
|
692
|
+
* updated with the URL.
|
|
693
|
+
*/
|
|
694
|
+
uploadProfilePhoto(photo: Blob | string): Promise<ProfilePhotoUploadResult>;
|
|
618
695
|
/**
|
|
619
696
|
* Log out the current user
|
|
620
697
|
*/
|
|
@@ -747,6 +824,9 @@ declare class TiquoAuth {
|
|
|
747
824
|
* Check for tokens injected by native apps (WebView integration)
|
|
748
825
|
*/
|
|
749
826
|
private checkForInjectedTokens;
|
|
827
|
+
private extractUploadableProfilePhoto;
|
|
828
|
+
private isProfilePhotoBlobUrl;
|
|
829
|
+
private profilePhotoToBlob;
|
|
750
830
|
private request;
|
|
751
831
|
/**
|
|
752
832
|
* Ensure we have a valid access token, refreshing if necessary
|
|
@@ -791,6 +871,7 @@ declare function useTiquoAuth(auth: TiquoAuth): {
|
|
|
791
871
|
verifyOTP: (email: string, otp: string) => Promise<VerifyOTPResult>;
|
|
792
872
|
logout: () => Promise<void>;
|
|
793
873
|
updateProfile: (updates: ProfileUpdateData) => Promise<ProfileUpdateResult>;
|
|
874
|
+
uploadProfilePhoto: (photo: Blob | string) => Promise<ProfilePhotoUploadResult>;
|
|
794
875
|
getOrders: (options?: GetOrdersOptions) => Promise<GetOrdersResult>;
|
|
795
876
|
getBookings: (options?: GetBookingsOptions) => Promise<GetBookingsResult>;
|
|
796
877
|
getUpcomingBookings: (options?: Omit<GetBookingsOptions, "upcoming">) => Promise<GetBookingsResult>;
|
|
@@ -860,4 +941,4 @@ declare class TiquoPhone {
|
|
|
860
941
|
static buildPhone: typeof buildPhone;
|
|
861
942
|
}
|
|
862
943
|
|
|
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 };
|
|
944
|
+
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, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -209,6 +209,18 @@ declare function buildPhone(countryCode: string, nationalNumber: string): string
|
|
|
209
209
|
* ```
|
|
210
210
|
*/
|
|
211
211
|
|
|
212
|
+
declare class TiquoCMS {
|
|
213
|
+
private config;
|
|
214
|
+
constructor(config: TiquoCMSConfig);
|
|
215
|
+
/**
|
|
216
|
+
* Fetch a published CMS page for the website attached to this public key.
|
|
217
|
+
*
|
|
218
|
+
* This intentionally goes through the Tiquo edge API rather than exposing
|
|
219
|
+
* Convex connection details to the consuming website.
|
|
220
|
+
*/
|
|
221
|
+
getPage(request: TiquoCMSPageRequest): Promise<TiquoCMSPage | null>;
|
|
222
|
+
private log;
|
|
223
|
+
}
|
|
212
224
|
interface TiquoAuthConfig {
|
|
213
225
|
/** Public key from your Tiquo Auth DOM settings */
|
|
214
226
|
publicKey: string;
|
|
@@ -225,6 +237,53 @@ interface TiquoAuthConfig {
|
|
|
225
237
|
/** Pre-authenticated refresh token (for WebView injection from native apps) */
|
|
226
238
|
refreshToken?: string;
|
|
227
239
|
}
|
|
240
|
+
interface TiquoCMSConfig {
|
|
241
|
+
/** Public key from your Tiquo Auth DOM settings */
|
|
242
|
+
publicKey: string;
|
|
243
|
+
/** API endpoint (defaults to production) */
|
|
244
|
+
apiEndpoint?: string;
|
|
245
|
+
/** Enable debug logging */
|
|
246
|
+
debug?: boolean;
|
|
247
|
+
}
|
|
248
|
+
interface TiquoCMSPageRequest {
|
|
249
|
+
/** CMS website slug */
|
|
250
|
+
siteSlug: string;
|
|
251
|
+
/** CMS page slug, defaults to "home" */
|
|
252
|
+
pageSlug?: string;
|
|
253
|
+
/** Optional template contract guard */
|
|
254
|
+
templateId?: string;
|
|
255
|
+
}
|
|
256
|
+
interface TiquoCMSBlock {
|
|
257
|
+
id: string;
|
|
258
|
+
type: string;
|
|
259
|
+
props: Record<string, unknown>;
|
|
260
|
+
locked?: boolean;
|
|
261
|
+
lockedBy?: string;
|
|
262
|
+
required?: boolean;
|
|
263
|
+
}
|
|
264
|
+
interface TiquoCMSPage {
|
|
265
|
+
id: string;
|
|
266
|
+
site: {
|
|
267
|
+
id: string;
|
|
268
|
+
name: string;
|
|
269
|
+
slug?: string;
|
|
270
|
+
templateId?: string;
|
|
271
|
+
templateVersion?: number;
|
|
272
|
+
globalConfig?: unknown;
|
|
273
|
+
};
|
|
274
|
+
page: {
|
|
275
|
+
id: string;
|
|
276
|
+
title: string;
|
|
277
|
+
slug: string;
|
|
278
|
+
path: string;
|
|
279
|
+
blocks: TiquoCMSBlock[];
|
|
280
|
+
settings?: unknown;
|
|
281
|
+
metaTitle?: string;
|
|
282
|
+
metaDescription?: string;
|
|
283
|
+
publishedAt?: number;
|
|
284
|
+
updatedAt: number;
|
|
285
|
+
};
|
|
286
|
+
}
|
|
228
287
|
declare global {
|
|
229
288
|
interface Window {
|
|
230
289
|
__TIQUO_INIT_TOKEN__?: {
|
|
@@ -305,7 +364,13 @@ interface ProfileUpdateData {
|
|
|
305
364
|
* for country+national input, or TiquoPhone.validate() to pre-check.
|
|
306
365
|
*/
|
|
307
366
|
phone?: string;
|
|
308
|
-
|
|
367
|
+
/**
|
|
368
|
+
* URL to a profile photo, a data/blob URI, or a browser File/Blob.
|
|
369
|
+
*
|
|
370
|
+
* File/Blob and data/blob URI values are uploaded to Tiquo storage before the
|
|
371
|
+
* profile is updated. Remote URLs are stored as-is.
|
|
372
|
+
*/
|
|
373
|
+
profilePhoto?: string | Blob;
|
|
309
374
|
emails?: TiquoCustomerEmail[];
|
|
310
375
|
/**
|
|
311
376
|
* Full phone list. Each number should be in E.164 format: +[country code][number].
|
|
@@ -317,6 +382,10 @@ interface ProfileUpdateResult {
|
|
|
317
382
|
success: boolean;
|
|
318
383
|
customer: TiquoCustomer;
|
|
319
384
|
}
|
|
385
|
+
interface ProfilePhotoUploadResult extends ProfileUpdateResult {
|
|
386
|
+
profilePhoto: string;
|
|
387
|
+
storageId: string;
|
|
388
|
+
}
|
|
320
389
|
interface TiquoOrderItem {
|
|
321
390
|
id: string;
|
|
322
391
|
name: string;
|
|
@@ -615,6 +684,14 @@ declare class TiquoAuth {
|
|
|
615
684
|
* to construct from a country selector and national number.
|
|
616
685
|
*/
|
|
617
686
|
updateProfile(updates: ProfileUpdateData): Promise<ProfileUpdateResult>;
|
|
687
|
+
/**
|
|
688
|
+
* Upload and save the authenticated customer's profile photo.
|
|
689
|
+
*
|
|
690
|
+
* Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
|
|
691
|
+
* image is uploaded to Tiquo storage first, and the customer profile is
|
|
692
|
+
* updated with the URL.
|
|
693
|
+
*/
|
|
694
|
+
uploadProfilePhoto(photo: Blob | string): Promise<ProfilePhotoUploadResult>;
|
|
618
695
|
/**
|
|
619
696
|
* Log out the current user
|
|
620
697
|
*/
|
|
@@ -747,6 +824,9 @@ declare class TiquoAuth {
|
|
|
747
824
|
* Check for tokens injected by native apps (WebView integration)
|
|
748
825
|
*/
|
|
749
826
|
private checkForInjectedTokens;
|
|
827
|
+
private extractUploadableProfilePhoto;
|
|
828
|
+
private isProfilePhotoBlobUrl;
|
|
829
|
+
private profilePhotoToBlob;
|
|
750
830
|
private request;
|
|
751
831
|
/**
|
|
752
832
|
* Ensure we have a valid access token, refreshing if necessary
|
|
@@ -791,6 +871,7 @@ declare function useTiquoAuth(auth: TiquoAuth): {
|
|
|
791
871
|
verifyOTP: (email: string, otp: string) => Promise<VerifyOTPResult>;
|
|
792
872
|
logout: () => Promise<void>;
|
|
793
873
|
updateProfile: (updates: ProfileUpdateData) => Promise<ProfileUpdateResult>;
|
|
874
|
+
uploadProfilePhoto: (photo: Blob | string) => Promise<ProfilePhotoUploadResult>;
|
|
794
875
|
getOrders: (options?: GetOrdersOptions) => Promise<GetOrdersResult>;
|
|
795
876
|
getBookings: (options?: GetBookingsOptions) => Promise<GetBookingsResult>;
|
|
796
877
|
getUpcomingBookings: (options?: Omit<GetBookingsOptions, "upcoming">) => Promise<GetBookingsResult>;
|
|
@@ -860,4 +941,4 @@ declare class TiquoPhone {
|
|
|
860
941
|
static buildPhone: typeof buildPhone;
|
|
861
942
|
}
|
|
862
943
|
|
|
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 };
|
|
944
|
+
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, 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 };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
TiquoAuth: () => TiquoAuth,
|
|
24
24
|
TiquoAuthError: () => TiquoAuthError,
|
|
25
|
+
TiquoCMS: () => TiquoCMS,
|
|
25
26
|
TiquoPhone: () => TiquoPhone,
|
|
26
27
|
addCustomerUserId: () => addCustomerUserId,
|
|
27
28
|
clearCachedEmail: () => clearCachedEmail,
|
|
@@ -677,6 +678,68 @@ function printTiquoBranding() {
|
|
|
677
678
|
}
|
|
678
679
|
}
|
|
679
680
|
printTiquoBranding();
|
|
681
|
+
var TiquoCMS = class {
|
|
682
|
+
constructor(config) {
|
|
683
|
+
if (!config.publicKey) {
|
|
684
|
+
throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
|
|
685
|
+
}
|
|
686
|
+
if (!config.publicKey.startsWith("pk_dom_")) {
|
|
687
|
+
throw new TiquoAuthError(
|
|
688
|
+
"Invalid public key format. Expected pk_dom_xxx",
|
|
689
|
+
"INVALID_PUBLIC_KEY"
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
this.config = {
|
|
693
|
+
publicKey: config.publicKey,
|
|
694
|
+
apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
|
|
695
|
+
debug: config.debug || false
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Fetch a published CMS page for the website attached to this public key.
|
|
700
|
+
*
|
|
701
|
+
* This intentionally goes through the Tiquo edge API rather than exposing
|
|
702
|
+
* Convex connection details to the consuming website.
|
|
703
|
+
*/
|
|
704
|
+
async getPage(request) {
|
|
705
|
+
const response = await fetch(`${this.config.apiEndpoint}/api/dom-cms/page`, {
|
|
706
|
+
method: "POST",
|
|
707
|
+
headers: {
|
|
708
|
+
"Content-Type": "text/plain;charset=UTF-8"
|
|
709
|
+
},
|
|
710
|
+
credentials: "include",
|
|
711
|
+
body: JSON.stringify({
|
|
712
|
+
publicKey: this.config.publicKey,
|
|
713
|
+
siteSlug: request.siteSlug,
|
|
714
|
+
pageSlug: request.pageSlug || "home",
|
|
715
|
+
templateId: request.templateId
|
|
716
|
+
})
|
|
717
|
+
});
|
|
718
|
+
if (response.status === 404) {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
if (!response.ok) {
|
|
722
|
+
let message = "Failed to fetch CMS page";
|
|
723
|
+
try {
|
|
724
|
+
const error = await response.json();
|
|
725
|
+
if (typeof error?.error === "string") message = error.error;
|
|
726
|
+
} catch {
|
|
727
|
+
}
|
|
728
|
+
throw new TiquoAuthError(message, "CMS_PAGE_FETCH_FAILED", response.status);
|
|
729
|
+
}
|
|
730
|
+
const result = await response.json();
|
|
731
|
+
if (!result?.success || !result?.data) {
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
this.log("Fetched CMS page", request.siteSlug, request.pageSlug || "home");
|
|
735
|
+
return result.data;
|
|
736
|
+
}
|
|
737
|
+
log(...args) {
|
|
738
|
+
if (this.config.debug) {
|
|
739
|
+
console.log("[TiquoCMS]", ...args);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
};
|
|
680
743
|
var TiquoAuthError = class extends Error {
|
|
681
744
|
constructor(message, code, statusCode) {
|
|
682
745
|
super(message);
|
|
@@ -843,6 +906,10 @@ var TiquoAuth = class {
|
|
|
843
906
|
async updateProfile(updates) {
|
|
844
907
|
await this.ensureValidToken();
|
|
845
908
|
const normalizedUpdates = { ...updates };
|
|
909
|
+
const profilePhotoUpload = this.extractUploadableProfilePhoto(normalizedUpdates.profilePhoto);
|
|
910
|
+
if (profilePhotoUpload) {
|
|
911
|
+
delete normalizedUpdates.profilePhoto;
|
|
912
|
+
}
|
|
846
913
|
if (normalizedUpdates.phone !== void 0 && normalizedUpdates.phone !== "") {
|
|
847
914
|
const normalized = normalizePhone(normalizedUpdates.phone);
|
|
848
915
|
const validation = validatePhone(normalizedUpdates.phone);
|
|
@@ -865,26 +932,109 @@ var TiquoAuth = class {
|
|
|
865
932
|
});
|
|
866
933
|
}
|
|
867
934
|
this.log("Updating customer profile:", normalizedUpdates);
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
935
|
+
let customer = this.session?.customer || void 0;
|
|
936
|
+
if (Object.keys(normalizedUpdates).length > 0) {
|
|
937
|
+
const response = await this.request("/api/client/v1/profile", {
|
|
938
|
+
method: "PATCH",
|
|
939
|
+
body: JSON.stringify(normalizedUpdates)
|
|
940
|
+
});
|
|
941
|
+
if (!response.ok) {
|
|
942
|
+
const error = await response.json().catch(() => ({ error: "Failed to update profile" }));
|
|
943
|
+
throw new TiquoAuthError(error.error || "Failed to update profile", "PROFILE_UPDATE_FAILED", response.status);
|
|
944
|
+
}
|
|
945
|
+
const result = await response.json();
|
|
946
|
+
if (this.session && result.data?.customer) {
|
|
947
|
+
this.session = {
|
|
948
|
+
...this.session,
|
|
949
|
+
customer: result.data.customer
|
|
950
|
+
};
|
|
951
|
+
this.notifyListeners();
|
|
952
|
+
this.broadcastTabSync("SESSION_UPDATE");
|
|
953
|
+
}
|
|
954
|
+
customer = result.data?.customer;
|
|
955
|
+
}
|
|
956
|
+
if (profilePhotoUpload) {
|
|
957
|
+
return this.uploadProfilePhoto(profilePhotoUpload);
|
|
958
|
+
}
|
|
959
|
+
return {
|
|
960
|
+
success: true,
|
|
961
|
+
customer
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Upload and save the authenticated customer's profile photo.
|
|
966
|
+
*
|
|
967
|
+
* Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
|
|
968
|
+
* image is uploaded to Tiquo storage first, and the customer profile is
|
|
969
|
+
* updated with the URL.
|
|
970
|
+
*/
|
|
971
|
+
async uploadProfilePhoto(photo) {
|
|
972
|
+
await this.ensureValidToken();
|
|
973
|
+
const blob = await this.profilePhotoToBlob(photo);
|
|
974
|
+
if (!blob.type.startsWith("image/")) {
|
|
975
|
+
throw new TiquoAuthError("Profile photo must be an image", "INVALID_PROFILE_PHOTO");
|
|
976
|
+
}
|
|
977
|
+
const uploadUrlResponse = await this.request("/api/client/v1/profile/photo-upload-url", {
|
|
978
|
+
method: "POST",
|
|
979
|
+
body: JSON.stringify({})
|
|
871
980
|
});
|
|
872
|
-
if (!
|
|
873
|
-
const error = await
|
|
874
|
-
throw new TiquoAuthError(
|
|
981
|
+
if (!uploadUrlResponse.ok) {
|
|
982
|
+
const error = await uploadUrlResponse.json().catch(() => ({ error: "Failed to create profile photo upload URL" }));
|
|
983
|
+
throw new TiquoAuthError(
|
|
984
|
+
error.error || "Failed to create profile photo upload URL",
|
|
985
|
+
"PROFILE_PHOTO_UPLOAD_URL_FAILED",
|
|
986
|
+
uploadUrlResponse.status
|
|
987
|
+
);
|
|
875
988
|
}
|
|
876
|
-
const
|
|
877
|
-
|
|
989
|
+
const uploadUrlResult = await uploadUrlResponse.json();
|
|
990
|
+
const uploadUrl = uploadUrlResult.data?.uploadUrl;
|
|
991
|
+
if (!uploadUrl) {
|
|
992
|
+
throw new TiquoAuthError("Profile photo upload URL was missing", "PROFILE_PHOTO_UPLOAD_URL_FAILED");
|
|
993
|
+
}
|
|
994
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
995
|
+
method: "POST",
|
|
996
|
+
headers: { "Content-Type": blob.type },
|
|
997
|
+
body: blob
|
|
998
|
+
});
|
|
999
|
+
if (!uploadResponse.ok) {
|
|
1000
|
+
throw new TiquoAuthError("Failed to upload profile photo", "PROFILE_PHOTO_UPLOAD_FAILED", uploadResponse.status);
|
|
1001
|
+
}
|
|
1002
|
+
const uploadResult = await uploadResponse.json();
|
|
1003
|
+
const storageId = uploadResult.storageId;
|
|
1004
|
+
if (!storageId) {
|
|
1005
|
+
throw new TiquoAuthError("Profile photo storage ID was missing", "PROFILE_PHOTO_UPLOAD_FAILED");
|
|
1006
|
+
}
|
|
1007
|
+
const finalizeResponse = await this.request("/api/client/v1/profile/photo", {
|
|
1008
|
+
method: "POST",
|
|
1009
|
+
body: JSON.stringify({ storageId })
|
|
1010
|
+
});
|
|
1011
|
+
if (!finalizeResponse.ok) {
|
|
1012
|
+
const error = await finalizeResponse.json().catch(() => ({ error: "Failed to update profile photo" }));
|
|
1013
|
+
throw new TiquoAuthError(
|
|
1014
|
+
error.error || "Failed to update profile photo",
|
|
1015
|
+
"PROFILE_PHOTO_UPDATE_FAILED",
|
|
1016
|
+
finalizeResponse.status
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
const finalizeResult = await finalizeResponse.json();
|
|
1020
|
+
const customer = finalizeResult.data?.customer;
|
|
1021
|
+
const profilePhoto = finalizeResult.data?.profilePhoto;
|
|
1022
|
+
if (!customer || !profilePhoto) {
|
|
1023
|
+
throw new TiquoAuthError("Profile photo update response was incomplete", "PROFILE_PHOTO_UPDATE_FAILED");
|
|
1024
|
+
}
|
|
1025
|
+
if (this.session && customer) {
|
|
878
1026
|
this.session = {
|
|
879
1027
|
...this.session,
|
|
880
|
-
customer
|
|
1028
|
+
customer
|
|
881
1029
|
};
|
|
882
1030
|
this.notifyListeners();
|
|
883
1031
|
this.broadcastTabSync("SESSION_UPDATE");
|
|
884
1032
|
}
|
|
885
1033
|
return {
|
|
886
1034
|
success: true,
|
|
887
|
-
customer
|
|
1035
|
+
customer,
|
|
1036
|
+
profilePhoto,
|
|
1037
|
+
storageId
|
|
888
1038
|
};
|
|
889
1039
|
}
|
|
890
1040
|
/**
|
|
@@ -1326,6 +1476,37 @@ var TiquoAuth = class {
|
|
|
1326
1476
|
}
|
|
1327
1477
|
}
|
|
1328
1478
|
}
|
|
1479
|
+
extractUploadableProfilePhoto(profilePhoto) {
|
|
1480
|
+
if (typeof Blob !== "undefined" && profilePhoto instanceof Blob) {
|
|
1481
|
+
return profilePhoto;
|
|
1482
|
+
}
|
|
1483
|
+
if (typeof profilePhoto === "string") {
|
|
1484
|
+
const trimmed = profilePhoto.trim();
|
|
1485
|
+
if (trimmed.startsWith("data:") || trimmed.startsWith("blob:")) {
|
|
1486
|
+
return trimmed;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return null;
|
|
1490
|
+
}
|
|
1491
|
+
isProfilePhotoBlobUrl(photo) {
|
|
1492
|
+
return photo.trim().startsWith("data:") || photo.trim().startsWith("blob:");
|
|
1493
|
+
}
|
|
1494
|
+
async profilePhotoToBlob(photo) {
|
|
1495
|
+
if (typeof Blob !== "undefined" && photo instanceof Blob) {
|
|
1496
|
+
return photo;
|
|
1497
|
+
}
|
|
1498
|
+
if (typeof photo === "string" && this.isProfilePhotoBlobUrl(photo)) {
|
|
1499
|
+
const response = await fetch(photo);
|
|
1500
|
+
if (!response.ok) {
|
|
1501
|
+
throw new TiquoAuthError("Failed to read profile photo URI", "INVALID_PROFILE_PHOTO");
|
|
1502
|
+
}
|
|
1503
|
+
return response.blob();
|
|
1504
|
+
}
|
|
1505
|
+
throw new TiquoAuthError(
|
|
1506
|
+
"uploadProfilePhoto expects a File, Blob, data URI, or blob URI. Use updateProfile({ profilePhoto: url }) for remote URLs.",
|
|
1507
|
+
"INVALID_PROFILE_PHOTO"
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1329
1510
|
async request(path, options) {
|
|
1330
1511
|
const url = `${this.config.apiEndpoint}${path}`;
|
|
1331
1512
|
const headers = {
|
|
@@ -1701,6 +1882,7 @@ function useTiquoAuth(auth) {
|
|
|
1701
1882
|
verifyOTP: (email, otp) => auth.verifyOTP(email, otp),
|
|
1702
1883
|
logout: () => auth.logout(),
|
|
1703
1884
|
updateProfile: (updates) => auth.updateProfile(updates),
|
|
1885
|
+
uploadProfilePhoto: (photo) => auth.uploadProfilePhoto(photo),
|
|
1704
1886
|
getOrders: (options) => auth.getOrders(options),
|
|
1705
1887
|
getBookings: (options) => auth.getBookings(options),
|
|
1706
1888
|
getUpcomingBookings: (options) => auth.getUpcomingBookings(options),
|
|
@@ -1734,6 +1916,7 @@ var index_default = TiquoAuth;
|
|
|
1734
1916
|
0 && (module.exports = {
|
|
1735
1917
|
TiquoAuth,
|
|
1736
1918
|
TiquoAuthError,
|
|
1919
|
+
TiquoCMS,
|
|
1737
1920
|
TiquoPhone,
|
|
1738
1921
|
addCustomerUserId,
|
|
1739
1922
|
clearCachedEmail,
|
package/dist/index.mjs
CHANGED
|
@@ -641,6 +641,68 @@ function printTiquoBranding() {
|
|
|
641
641
|
}
|
|
642
642
|
}
|
|
643
643
|
printTiquoBranding();
|
|
644
|
+
var TiquoCMS = class {
|
|
645
|
+
constructor(config) {
|
|
646
|
+
if (!config.publicKey) {
|
|
647
|
+
throw new TiquoAuthError("publicKey is required", "MISSING_PUBLIC_KEY");
|
|
648
|
+
}
|
|
649
|
+
if (!config.publicKey.startsWith("pk_dom_")) {
|
|
650
|
+
throw new TiquoAuthError(
|
|
651
|
+
"Invalid public key format. Expected pk_dom_xxx",
|
|
652
|
+
"INVALID_PUBLIC_KEY"
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
this.config = {
|
|
656
|
+
publicKey: config.publicKey,
|
|
657
|
+
apiEndpoint: config.apiEndpoint || "https://edge.tiquo.app",
|
|
658
|
+
debug: config.debug || false
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Fetch a published CMS page for the website attached to this public key.
|
|
663
|
+
*
|
|
664
|
+
* This intentionally goes through the Tiquo edge API rather than exposing
|
|
665
|
+
* Convex connection details to the consuming website.
|
|
666
|
+
*/
|
|
667
|
+
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
|
+
});
|
|
681
|
+
if (response.status === 404) {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
if (!response.ok) {
|
|
685
|
+
let message = "Failed to fetch CMS page";
|
|
686
|
+
try {
|
|
687
|
+
const error = await response.json();
|
|
688
|
+
if (typeof error?.error === "string") message = error.error;
|
|
689
|
+
} catch {
|
|
690
|
+
}
|
|
691
|
+
throw new TiquoAuthError(message, "CMS_PAGE_FETCH_FAILED", response.status);
|
|
692
|
+
}
|
|
693
|
+
const result = await response.json();
|
|
694
|
+
if (!result?.success || !result?.data) {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
this.log("Fetched CMS page", request.siteSlug, request.pageSlug || "home");
|
|
698
|
+
return result.data;
|
|
699
|
+
}
|
|
700
|
+
log(...args) {
|
|
701
|
+
if (this.config.debug) {
|
|
702
|
+
console.log("[TiquoCMS]", ...args);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
};
|
|
644
706
|
var TiquoAuthError = class extends Error {
|
|
645
707
|
constructor(message, code, statusCode) {
|
|
646
708
|
super(message);
|
|
@@ -807,6 +869,10 @@ var TiquoAuth = class {
|
|
|
807
869
|
async updateProfile(updates) {
|
|
808
870
|
await this.ensureValidToken();
|
|
809
871
|
const normalizedUpdates = { ...updates };
|
|
872
|
+
const profilePhotoUpload = this.extractUploadableProfilePhoto(normalizedUpdates.profilePhoto);
|
|
873
|
+
if (profilePhotoUpload) {
|
|
874
|
+
delete normalizedUpdates.profilePhoto;
|
|
875
|
+
}
|
|
810
876
|
if (normalizedUpdates.phone !== void 0 && normalizedUpdates.phone !== "") {
|
|
811
877
|
const normalized = normalizePhone(normalizedUpdates.phone);
|
|
812
878
|
const validation = validatePhone(normalizedUpdates.phone);
|
|
@@ -829,26 +895,109 @@ var TiquoAuth = class {
|
|
|
829
895
|
});
|
|
830
896
|
}
|
|
831
897
|
this.log("Updating customer profile:", normalizedUpdates);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
898
|
+
let customer = this.session?.customer || void 0;
|
|
899
|
+
if (Object.keys(normalizedUpdates).length > 0) {
|
|
900
|
+
const response = await this.request("/api/client/v1/profile", {
|
|
901
|
+
method: "PATCH",
|
|
902
|
+
body: JSON.stringify(normalizedUpdates)
|
|
903
|
+
});
|
|
904
|
+
if (!response.ok) {
|
|
905
|
+
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);
|
|
907
|
+
}
|
|
908
|
+
const result = await response.json();
|
|
909
|
+
if (this.session && result.data?.customer) {
|
|
910
|
+
this.session = {
|
|
911
|
+
...this.session,
|
|
912
|
+
customer: result.data.customer
|
|
913
|
+
};
|
|
914
|
+
this.notifyListeners();
|
|
915
|
+
this.broadcastTabSync("SESSION_UPDATE");
|
|
916
|
+
}
|
|
917
|
+
customer = result.data?.customer;
|
|
918
|
+
}
|
|
919
|
+
if (profilePhotoUpload) {
|
|
920
|
+
return this.uploadProfilePhoto(profilePhotoUpload);
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
success: true,
|
|
924
|
+
customer
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Upload and save the authenticated customer's profile photo.
|
|
929
|
+
*
|
|
930
|
+
* Accepts a browser File/Blob, `data:image/...` URI, or `blob:...` URI. The
|
|
931
|
+
* image is uploaded to Tiquo storage first, and the customer profile is
|
|
932
|
+
* updated with the URL.
|
|
933
|
+
*/
|
|
934
|
+
async uploadProfilePhoto(photo) {
|
|
935
|
+
await this.ensureValidToken();
|
|
936
|
+
const blob = await this.profilePhotoToBlob(photo);
|
|
937
|
+
if (!blob.type.startsWith("image/")) {
|
|
938
|
+
throw new TiquoAuthError("Profile photo must be an image", "INVALID_PROFILE_PHOTO");
|
|
939
|
+
}
|
|
940
|
+
const uploadUrlResponse = await this.request("/api/client/v1/profile/photo-upload-url", {
|
|
941
|
+
method: "POST",
|
|
942
|
+
body: JSON.stringify({})
|
|
835
943
|
});
|
|
836
|
-
if (!
|
|
837
|
-
const error = await
|
|
838
|
-
throw new TiquoAuthError(
|
|
944
|
+
if (!uploadUrlResponse.ok) {
|
|
945
|
+
const error = await uploadUrlResponse.json().catch(() => ({ error: "Failed to create profile photo upload URL" }));
|
|
946
|
+
throw new TiquoAuthError(
|
|
947
|
+
error.error || "Failed to create profile photo upload URL",
|
|
948
|
+
"PROFILE_PHOTO_UPLOAD_URL_FAILED",
|
|
949
|
+
uploadUrlResponse.status
|
|
950
|
+
);
|
|
839
951
|
}
|
|
840
|
-
const
|
|
841
|
-
|
|
952
|
+
const uploadUrlResult = await uploadUrlResponse.json();
|
|
953
|
+
const uploadUrl = uploadUrlResult.data?.uploadUrl;
|
|
954
|
+
if (!uploadUrl) {
|
|
955
|
+
throw new TiquoAuthError("Profile photo upload URL was missing", "PROFILE_PHOTO_UPLOAD_URL_FAILED");
|
|
956
|
+
}
|
|
957
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
958
|
+
method: "POST",
|
|
959
|
+
headers: { "Content-Type": blob.type },
|
|
960
|
+
body: blob
|
|
961
|
+
});
|
|
962
|
+
if (!uploadResponse.ok) {
|
|
963
|
+
throw new TiquoAuthError("Failed to upload profile photo", "PROFILE_PHOTO_UPLOAD_FAILED", uploadResponse.status);
|
|
964
|
+
}
|
|
965
|
+
const uploadResult = await uploadResponse.json();
|
|
966
|
+
const storageId = uploadResult.storageId;
|
|
967
|
+
if (!storageId) {
|
|
968
|
+
throw new TiquoAuthError("Profile photo storage ID was missing", "PROFILE_PHOTO_UPLOAD_FAILED");
|
|
969
|
+
}
|
|
970
|
+
const finalizeResponse = await this.request("/api/client/v1/profile/photo", {
|
|
971
|
+
method: "POST",
|
|
972
|
+
body: JSON.stringify({ storageId })
|
|
973
|
+
});
|
|
974
|
+
if (!finalizeResponse.ok) {
|
|
975
|
+
const error = await finalizeResponse.json().catch(() => ({ error: "Failed to update profile photo" }));
|
|
976
|
+
throw new TiquoAuthError(
|
|
977
|
+
error.error || "Failed to update profile photo",
|
|
978
|
+
"PROFILE_PHOTO_UPDATE_FAILED",
|
|
979
|
+
finalizeResponse.status
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
const finalizeResult = await finalizeResponse.json();
|
|
983
|
+
const customer = finalizeResult.data?.customer;
|
|
984
|
+
const profilePhoto = finalizeResult.data?.profilePhoto;
|
|
985
|
+
if (!customer || !profilePhoto) {
|
|
986
|
+
throw new TiquoAuthError("Profile photo update response was incomplete", "PROFILE_PHOTO_UPDATE_FAILED");
|
|
987
|
+
}
|
|
988
|
+
if (this.session && customer) {
|
|
842
989
|
this.session = {
|
|
843
990
|
...this.session,
|
|
844
|
-
customer
|
|
991
|
+
customer
|
|
845
992
|
};
|
|
846
993
|
this.notifyListeners();
|
|
847
994
|
this.broadcastTabSync("SESSION_UPDATE");
|
|
848
995
|
}
|
|
849
996
|
return {
|
|
850
997
|
success: true,
|
|
851
|
-
customer
|
|
998
|
+
customer,
|
|
999
|
+
profilePhoto,
|
|
1000
|
+
storageId
|
|
852
1001
|
};
|
|
853
1002
|
}
|
|
854
1003
|
/**
|
|
@@ -1290,6 +1439,37 @@ var TiquoAuth = class {
|
|
|
1290
1439
|
}
|
|
1291
1440
|
}
|
|
1292
1441
|
}
|
|
1442
|
+
extractUploadableProfilePhoto(profilePhoto) {
|
|
1443
|
+
if (typeof Blob !== "undefined" && profilePhoto instanceof Blob) {
|
|
1444
|
+
return profilePhoto;
|
|
1445
|
+
}
|
|
1446
|
+
if (typeof profilePhoto === "string") {
|
|
1447
|
+
const trimmed = profilePhoto.trim();
|
|
1448
|
+
if (trimmed.startsWith("data:") || trimmed.startsWith("blob:")) {
|
|
1449
|
+
return trimmed;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
return null;
|
|
1453
|
+
}
|
|
1454
|
+
isProfilePhotoBlobUrl(photo) {
|
|
1455
|
+
return photo.trim().startsWith("data:") || photo.trim().startsWith("blob:");
|
|
1456
|
+
}
|
|
1457
|
+
async profilePhotoToBlob(photo) {
|
|
1458
|
+
if (typeof Blob !== "undefined" && photo instanceof Blob) {
|
|
1459
|
+
return photo;
|
|
1460
|
+
}
|
|
1461
|
+
if (typeof photo === "string" && this.isProfilePhotoBlobUrl(photo)) {
|
|
1462
|
+
const response = await fetch(photo);
|
|
1463
|
+
if (!response.ok) {
|
|
1464
|
+
throw new TiquoAuthError("Failed to read profile photo URI", "INVALID_PROFILE_PHOTO");
|
|
1465
|
+
}
|
|
1466
|
+
return response.blob();
|
|
1467
|
+
}
|
|
1468
|
+
throw new TiquoAuthError(
|
|
1469
|
+
"uploadProfilePhoto expects a File, Blob, data URI, or blob URI. Use updateProfile({ profilePhoto: url }) for remote URLs.",
|
|
1470
|
+
"INVALID_PROFILE_PHOTO"
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1293
1473
|
async request(path, options) {
|
|
1294
1474
|
const url = `${this.config.apiEndpoint}${path}`;
|
|
1295
1475
|
const headers = {
|
|
@@ -1665,6 +1845,7 @@ function useTiquoAuth(auth) {
|
|
|
1665
1845
|
verifyOTP: (email, otp) => auth.verifyOTP(email, otp),
|
|
1666
1846
|
logout: () => auth.logout(),
|
|
1667
1847
|
updateProfile: (updates) => auth.updateProfile(updates),
|
|
1848
|
+
uploadProfilePhoto: (photo) => auth.uploadProfilePhoto(photo),
|
|
1668
1849
|
getOrders: (options) => auth.getOrders(options),
|
|
1669
1850
|
getBookings: (options) => auth.getBookings(options),
|
|
1670
1851
|
getUpcomingBookings: (options) => auth.getUpcomingBookings(options),
|
|
@@ -1697,6 +1878,7 @@ var index_default = TiquoAuth;
|
|
|
1697
1878
|
export {
|
|
1698
1879
|
TiquoAuth,
|
|
1699
1880
|
TiquoAuthError,
|
|
1881
|
+
TiquoCMS,
|
|
1700
1882
|
TiquoPhone,
|
|
1701
1883
|
addCustomerUserId,
|
|
1702
1884
|
clearCachedEmail,
|
package/package.json
CHANGED