@thefittingroom/sdk 1.5.2 → 2.0.0-alpha-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.
@@ -20,8 +20,14 @@ export declare class TfrShop {
20
20
  getStyle(styleId: number): Promise<types.FirestoreStyleCategory>;
21
21
  getMeasurementLocationName(location: string): string;
22
22
  getMeasurementLocationSortOrder(location: string): number;
23
+ tryOn(styleId: number, sizeId: number): Promise<types.TryOnFrames>;
24
+ private getColorwaySizeAssetSkuFromStyleIdAndSizeId;
23
25
  private getGetTaxonomy;
24
26
  private getMeasurementLocations;
25
27
  private fetchMeasurementLocations;
28
+ private requestThenGetColorwaySizeAssetFrames;
29
+ private awaitColorwaySizeAssetFrames;
30
+ private requestColorwaySizeAssetFrames;
31
+ private getColorwaySizeAssetFrames;
26
32
  }
27
33
  export declare const initShop: (brandId: number, env?: string) => TfrShop;
@@ -1,6 +1,6 @@
1
1
  import * as firebase from 'firebase/app';
2
2
  import * as firebaseAuth from 'firebase/auth';
3
- import { Firestore } from 'firebase/firestore';
3
+ import { DocumentData, Firestore, QuerySnapshot } from 'firebase/firestore';
4
4
  import { FirestoreUser } from '../types';
5
5
  export type BrandUserId = string | number;
6
6
  export declare class FirebaseUser {
@@ -15,8 +15,10 @@ export declare class FirebaseUser {
15
15
  logUserLogin(brandId: number, user: firebaseAuth.User): Promise<void>;
16
16
  setBrandUserId(brandUserId: BrandUserId): void;
17
17
  getToken(): Promise<string>;
18
- getUserProfile(): Promise<import("@firebase/firestore").DocumentData>;
18
+ get userId(): string;
19
+ getUserProfile(): Promise<DocumentData>;
19
20
  watchUserProfileForChanges(callback: (data: FirestoreUser) => void): () => void;
21
+ watchUserProfileForFrames(predicate: (data: QuerySnapshot<DocumentData>) => Promise<boolean>): Promise<DocumentData>;
20
22
  login(username: string, password: string): Promise<void>;
21
23
  logout(): Promise<void>;
22
24
  sendPasswordResetEmail(email: string): Promise<void>;
@@ -10,4 +10,23 @@ export declare class UserNotLoggedInError extends Error {
10
10
  export declare class NoColorwaySizeAssetsFoundError extends Error {
11
11
  constructor();
12
12
  }
13
+ export declare class BrandUserIdNotSetError extends Error {
14
+ constructor();
15
+ }
16
+ export declare class NoFramesFoundError extends Error {
17
+ constructor();
18
+ }
19
+ export declare class RecommendedAvailableSizesError extends Error {
20
+ recommended_size: string;
21
+ available_sizes: string[];
22
+ constructor(recommended_size: string, available_sizes: string[]);
23
+ }
24
+ export interface ErrorOutsideRecommendedSizes {
25
+ error: string;
26
+ recommended_size_id: number;
27
+ available_size_ids: number[];
28
+ }
29
+ export declare class NoStylesFoundError extends Error {
30
+ constructor();
31
+ }
13
32
  export declare const AvatarNotCreated = "avatar not created";
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * thefittingroom v1.5.2 (2024-09-03T15:43:56.403Z)
2
+ * thefittingroom v2.0.0-alpha-0 (2025-01-17T19:54:05.370Z)
3
3
  * Copyright 2022-present, TheFittingRoom, Inc. All rights reserved.
4
4
  */
5
5
  // Code generated by tygo. DO NOT EDIT.
@@ -25657,6 +25657,32 @@ class NoColorwaySizeAssetsFoundError extends Error {
25657
25657
  this.name = 'NoColorwaySizeAssetsFoundError';
25658
25658
  }
25659
25659
  }
25660
+ class BrandUserIdNotSetError extends Error {
25661
+ constructor() {
25662
+ super('brand user id not set');
25663
+ this.name = 'BrandUserIdNotSetError';
25664
+ }
25665
+ }
25666
+ class NoFramesFoundError extends Error {
25667
+ constructor() {
25668
+ super('no frames found');
25669
+ this.name = 'NoFramesFoundError';
25670
+ }
25671
+ }
25672
+ class RecommendedAvailableSizesError extends Error {
25673
+ constructor(recommended_size, available_sizes) {
25674
+ super('recommended available sizes error');
25675
+ this.name = 'RecommendedAvailableSizesError';
25676
+ this.recommended_size = recommended_size;
25677
+ this.available_sizes = available_sizes;
25678
+ }
25679
+ }
25680
+ class NoStylesFoundError extends Error {
25681
+ constructor() {
25682
+ super('no styles found');
25683
+ this.name = 'NoStylesFoundError';
25684
+ }
25685
+ }
25660
25686
  // Backend responses
25661
25687
  const AvatarNotCreated = 'avatar not created';
25662
25688
 
@@ -25665,6 +25691,10 @@ var errors = /*#__PURE__*/Object.freeze({
25665
25691
  AvatarNotCreatedError: AvatarNotCreatedError,
25666
25692
  UserNotLoggedInError: UserNotLoggedInError,
25667
25693
  NoColorwaySizeAssetsFoundError: NoColorwaySizeAssetsFoundError,
25694
+ BrandUserIdNotSetError: BrandUserIdNotSetError,
25695
+ NoFramesFoundError: NoFramesFoundError,
25696
+ RecommendedAvailableSizesError: RecommendedAvailableSizesError,
25697
+ NoStylesFoundError: NoStylesFoundError,
25668
25698
  AvatarNotCreated: AvatarNotCreated
25669
25699
  });
25670
25700
 
@@ -25682,12 +25712,15 @@ class FirebaseUser {
25682
25712
  async onInit(brandId) {
25683
25713
  this.auth.onAuthStateChanged((user) => {
25684
25714
  this.setUser(user);
25685
- if (user)
25686
- this.logUserLogin(brandId, user);
25715
+ if (!user)
25716
+ return;
25717
+ this.logUserLogin(brandId, user);
25718
+ this.setBrandUserId(user.uid);
25687
25719
  });
25688
25720
  await this.auth.authStateReady();
25689
25721
  const user = this.auth.currentUser;
25690
25722
  this.setUser(user);
25723
+ this.setBrandUserId(user.uid);
25691
25724
  return Boolean(user);
25692
25725
  }
25693
25726
  setUser(user) {
@@ -25733,6 +25766,12 @@ class FirebaseUser {
25733
25766
  const token = await this.user.getIdToken();
25734
25767
  return token;
25735
25768
  }
25769
+ get userId() {
25770
+ var _a;
25771
+ if (!((_a = this.user) === null || _a === void 0 ? void 0 : _a.uid))
25772
+ throw new UserNotLoggedInError();
25773
+ return this.user.uid;
25774
+ }
25736
25775
  async getUserProfile() {
25737
25776
  var _a;
25738
25777
  if (!((_a = this.user) === null || _a === void 0 ? void 0 : _a.uid))
@@ -25746,6 +25785,18 @@ class FirebaseUser {
25746
25785
  unsub = jl(q, (snapshot) => callback(snapshot.docs[0].data()));
25747
25786
  return () => unsub();
25748
25787
  }
25788
+ watchUserProfileForFrames(predicate) {
25789
+ let unsub;
25790
+ const q = sl(Ta(this.firestore, 'users'), rl(Eh(), '==', this.id));
25791
+ return new Promise((resolve) => {
25792
+ unsub = jl(q, async (snapshot) => {
25793
+ if (!(await predicate(snapshot)))
25794
+ return;
25795
+ unsub();
25796
+ resolve(snapshot.docs[0].data());
25797
+ });
25798
+ });
25799
+ }
25749
25800
  async login(username, password) {
25750
25801
  if (this.auth.currentUser)
25751
25802
  await this.auth.signOut();
@@ -25809,6 +25860,8 @@ const getFirebaseError = (e) => {
25809
25860
  }
25810
25861
  };
25811
25862
 
25863
+ const asyncTry = (promise) => promise.then((data) => [null, data]).catch((error) => [error]);
25864
+
25812
25865
  class Fetcher {
25813
25866
  static get endpoint() {
25814
25867
  const api = Config.getInstance().api;
@@ -25857,6 +25910,15 @@ class Fetcher {
25857
25910
  }
25858
25911
  }
25859
25912
 
25913
+ const testImage = (url) => {
25914
+ const img = new Image();
25915
+ img.src = url;
25916
+ return new Promise((resolve) => {
25917
+ img.onerror = () => resolve(false);
25918
+ img.onload = () => resolve(true);
25919
+ });
25920
+ };
25921
+
25860
25922
  class TfrShop {
25861
25923
  constructor(brandId, firebase) {
25862
25924
  this.brandId = brandId;
@@ -25908,6 +25970,7 @@ class TfrShop {
25908
25970
  return Array.from(assets.values())[0];
25909
25971
  }
25910
25972
  async getMeasurementLocationsFromSku(sku, filledLocations = []) {
25973
+ console.log({ sku });
25911
25974
  const asset = await this.getColorwaySizeAssetFromSku(sku);
25912
25975
  if (!asset)
25913
25976
  throw new Error('No colorway size asset found for sku');
@@ -25997,6 +26060,33 @@ class TfrShop {
25997
26060
  getMeasurementLocationSortOrder(location) {
25998
26061
  return this.measurementLocations.has(location) ? this.measurementLocations.get(location).sort_order : Infinity;
25999
26062
  }
26063
+ async tryOn(styleId, sizeId) {
26064
+ if (!this.isLoggedIn)
26065
+ throw new UserNotLoggedInError();
26066
+ const colorwaySizeAssetSku = await this.getColorwaySizeAssetSkuFromStyleIdAndSizeId(styleId, sizeId);
26067
+ try {
26068
+ const frames = await this.getColorwaySizeAssetFrames(colorwaySizeAssetSku);
26069
+ return frames;
26070
+ }
26071
+ catch (error) {
26072
+ if (!(error instanceof NoFramesFoundError))
26073
+ throw error;
26074
+ return this.requestThenGetColorwaySizeAssetFrames(colorwaySizeAssetSku);
26075
+ }
26076
+ }
26077
+ async getColorwaySizeAssetSkuFromStyleIdAndSizeId(styleId, sizeId) {
26078
+ var _a, _b, _c;
26079
+ try {
26080
+ const constraints = [rl('brand_id', '==', this.brandId)];
26081
+ constraints.push(rl('style_id', '==', styleId));
26082
+ constraints.push(rl('size_id', '==', sizeId));
26083
+ const querySnapshot = await this.firebase.getDocs('colorway_size_assets', constraints);
26084
+ return (_c = (_b = (_a = querySnapshot.docs) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.data()) === null || _c === void 0 ? void 0 : _c.sku;
26085
+ }
26086
+ catch (error) {
26087
+ return getFirebaseError(error);
26088
+ }
26089
+ }
26000
26090
  async getGetTaxonomy(styleId) {
26001
26091
  try {
26002
26092
  const doc = await this.firebase.getDoc('style_garment_categories', String(styleId));
@@ -26021,6 +26111,56 @@ class TfrShop {
26021
26111
  return getFirebaseError(error);
26022
26112
  }
26023
26113
  }
26114
+ async requestThenGetColorwaySizeAssetFrames(colorwaySizeAssetSku) {
26115
+ const [error, colorwaySizeAsset] = await asyncTry(this.getColorwaySizeAssetFromSku(colorwaySizeAssetSku));
26116
+ if (error)
26117
+ throw error;
26118
+ try {
26119
+ await this.requestColorwaySizeAssetFrames(colorwaySizeAsset.id);
26120
+ return this.awaitColorwaySizeAssetFrames(colorwaySizeAssetSku);
26121
+ }
26122
+ catch (error) {
26123
+ if ((error === null || error === void 0 ? void 0 : error.error) === AvatarNotCreated)
26124
+ throw new AvatarNotCreatedError();
26125
+ throw new NoStylesFoundError();
26126
+ }
26127
+ }
26128
+ async awaitColorwaySizeAssetFrames(colorwaySizeAssetSKU) {
26129
+ var _a, _b, _c, _d;
26130
+ if (!this.isLoggedIn)
26131
+ throw new UserNotLoggedInError();
26132
+ const callback = async (data) => {
26133
+ var _a, _b, _c, _d;
26134
+ const frames = (_d = (_c = (_b = (_a = data.docs[0].data()) === null || _a === void 0 ? void 0 : _a.vto) === null || _b === void 0 ? void 0 : _b[this.brandId]) === null || _c === void 0 ? void 0 : _c[colorwaySizeAssetSKU]) === null || _d === void 0 ? void 0 : _d.frames;
26135
+ if (!(frames === null || frames === void 0 ? void 0 : frames.length))
26136
+ return false;
26137
+ return testImage(frames[0]);
26138
+ };
26139
+ const userProfile = (await this.user.watchUserProfileForFrames(callback));
26140
+ if (!((_d = (_c = (_b = (_a = userProfile === null || userProfile === void 0 ? void 0 : userProfile.vto) === null || _a === void 0 ? void 0 : _a[this.brandId]) === null || _b === void 0 ? void 0 : _b[colorwaySizeAssetSKU]) === null || _c === void 0 ? void 0 : _c.frames) === null || _d === void 0 ? void 0 : _d.length))
26141
+ throw new NoFramesFoundError();
26142
+ return userProfile.vto[this.brandId][colorwaySizeAssetSKU].frames;
26143
+ }
26144
+ async requestColorwaySizeAssetFrames(colorwaySizeAssetId) {
26145
+ if (!this.isLoggedIn)
26146
+ throw new UserNotLoggedInError();
26147
+ if (!this.user.brandUserId)
26148
+ throw new BrandUserIdNotSetError();
26149
+ await Fetcher.Post(this.user, `/colorway-size-assets/${colorwaySizeAssetId}/frames`, {
26150
+ brand_user_id: String(this.user.brandUserId),
26151
+ });
26152
+ }
26153
+ async getColorwaySizeAssetFrames(colorwaySizeAssetSKU) {
26154
+ var _a, _b, _c;
26155
+ const userProfile = await this.user.getUserProfile();
26156
+ const frames = ((_c = (_b = (_a = userProfile === null || userProfile === void 0 ? void 0 : userProfile.vto) === null || _a === void 0 ? void 0 : _a[this.brandId]) === null || _b === void 0 ? void 0 : _b[colorwaySizeAssetSKU]) === null || _c === void 0 ? void 0 : _c.frames) || [];
26157
+ if (!frames.length)
26158
+ throw new NoFramesFoundError();
26159
+ const testedImage = await testImage(frames[0]);
26160
+ if (!testedImage)
26161
+ throw new NoFramesFoundError();
26162
+ return frames;
26163
+ }
26024
26164
  }
26025
26165
  const initShop = (brandId, env = 'dev') => {
26026
26166
  if (env === 'dev' || env === 'development')