@swan-admin/swan-ai-measurements 1.1.46 → 1.1.48

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.
@@ -28,4 +28,5 @@ export declare const requiredMetaData: RequiredMetaDataKeys[];
28
28
  export declare const REQUIRED_MESSAGE: string;
29
29
  export declare const REQUIRED_MESSAGE_FOR_META_DATA: string;
30
30
  export declare const REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = "Invalid Email";
31
+ export declare const CHUNK_SIZE: number;
31
32
  export {};
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = exports.REQUIRED_MESSAGE_FOR_META_DATA = exports.REQUIRED_MESSAGE = exports.requiredMetaData = exports.API_ENDPOINTS = exports.APP_POSE_DETECTION_WEBSOCKET_URL = exports.APP_BASE_WEBSOCKET_URL = exports.APP_AUTH_BASE_URL = exports.FILE_UPLOAD_ENDPOINT = exports.PROD_URL = exports.STAGING_URL = void 0;
3
+ exports.CHUNK_SIZE = exports.REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = exports.REQUIRED_MESSAGE_FOR_META_DATA = exports.REQUIRED_MESSAGE = exports.requiredMetaData = exports.API_ENDPOINTS = exports.APP_POSE_DETECTION_WEBSOCKET_URL = exports.APP_BASE_WEBSOCKET_URL = exports.APP_AUTH_BASE_URL = exports.FILE_UPLOAD_ENDPOINT = exports.PROD_URL = exports.STAGING_URL = void 0;
4
4
  exports.STAGING_URL = {
5
5
  APP_AUTH_BASE_URL: "https://staging.api.getswan.co",
6
6
  APP_BASE_WEBSOCKET_URL: "wss://staging.wsnotify.api.getswan.co",
@@ -44,3 +44,4 @@ exports.requiredMetaData = ["gender", "focal_length", "height", "customer_store_
44
44
  exports.REQUIRED_MESSAGE = "Please verify required parameters";
45
45
  exports.REQUIRED_MESSAGE_FOR_META_DATA = "Please verify required parameters in meta data";
46
46
  exports.REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = "Invalid Email";
47
+ exports.CHUNK_SIZE = 5 * 1024 * 1024;
@@ -28,4 +28,5 @@ export declare const requiredMetaData: RequiredMetaDataKeys[];
28
28
  export declare const REQUIRED_MESSAGE: string;
29
29
  export declare const REQUIRED_MESSAGE_FOR_META_DATA: string;
30
30
  export declare const REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = "Invalid Email";
31
+ export declare const CHUNK_SIZE: number;
31
32
  export {};
@@ -41,3 +41,4 @@ export const requiredMetaData = ["gender", "focal_length", "height", "customer_s
41
41
  export const REQUIRED_MESSAGE = "Please verify required parameters";
42
42
  export const REQUIRED_MESSAGE_FOR_META_DATA = "Please verify required parameters in meta data";
43
43
  export const REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = "Invalid Email";
44
+ export const CHUNK_SIZE = 5 * 1024 * 1024;
@@ -25,11 +25,15 @@ interface UploadOptions {
25
25
  arrayMetaData: Partial<ObjMetaData>[];
26
26
  scanId: string;
27
27
  email: string;
28
+ callBack?: (a: {
29
+ eventName: string;
30
+ message: string;
31
+ }) => void;
28
32
  }
29
33
  export default class FileUpload {
30
34
  #private;
31
35
  constructor(accessKey: string, stagingUrl?: boolean);
32
- uploadFileFrontend({ file, arrayMetaData, scanId, email }: UploadOptions): Promise<unknown>;
36
+ uploadFileFrontend({ file, arrayMetaData, scanId, email, callBack }: UploadOptions): Promise<unknown>;
33
37
  uploadFile({ file, arrayMetaData, scanId, email }: UploadOptions): Promise<unknown>;
34
38
  setDeviceInfo(data: SetDeviceInfo): Promise<import("axios").AxiosResponse<any, any>>;
35
39
  }
@@ -31,7 +31,7 @@ var __rest = (this && this.__rest) || function (s, e) {
31
31
  };
32
32
  var _FileUpload_uppyIns, _FileUpload_accessKey, _FileUpload_stagingUrl;
33
33
  import axios from "axios";
34
- import { REQUIRED_MESSAGE, REQUIRED_MESSAGE_FOR_META_DATA, FILE_UPLOAD_ENDPOINT, APP_AUTH_BASE_URL, REQUIRED_ERROR_MESSAGE_INVALID_EMAIL, API_ENDPOINTS, } from "./constants.js";
34
+ import { REQUIRED_MESSAGE, REQUIRED_MESSAGE_FOR_META_DATA, FILE_UPLOAD_ENDPOINT, APP_AUTH_BASE_URL, REQUIRED_ERROR_MESSAGE_INVALID_EMAIL, API_ENDPOINTS, CHUNK_SIZE } from "./constants.js";
35
35
  import { addScanType, checkMetaDataValue, checkParameters, fetchData, getFileChunks, getUrl, isValidEmail } from "./utils.js";
36
36
  import Uppy from "@uppy/core";
37
37
  import AwsS3Multipart from "@uppy/aws-s3-multipart";
@@ -44,7 +44,7 @@ class FileUpload {
44
44
  __classPrivateFieldSet(this, _FileUpload_stagingUrl, stagingUrl, "f");
45
45
  }
46
46
  uploadFileFrontend(_a) {
47
- return __awaiter(this, arguments, void 0, function* ({ file, arrayMetaData, scanId, email }) {
47
+ return __awaiter(this, arguments, void 0, function* ({ file, arrayMetaData, scanId, email, callBack }) {
48
48
  if (!checkParameters(file, arrayMetaData, scanId, email)) {
49
49
  throw new Error(REQUIRED_MESSAGE);
50
50
  }
@@ -64,8 +64,10 @@ class FileUpload {
64
64
  limit: 10,
65
65
  retryDelays: [0, 1000, 3000, 5000],
66
66
  companionUrl: getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: __classPrivateFieldGet(this, _FileUpload_stagingUrl, "f") }),
67
- getChunkSize: () => 5 * 1024 * 1024,
67
+ getChunkSize: () => CHUNK_SIZE,
68
68
  createMultipartUpload: (file) => {
69
+ const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
70
+ callBack === null || callBack === void 0 ? void 0 : callBack({ eventName: "uploading_start", message: `File ${file.name} will be divided into ${totalChunks} chunks` });
69
71
  const objectKey = `${scanId}.${file.extension}`;
70
72
  return fetchData({
71
73
  path: FILE_UPLOAD_ENDPOINT.UPLOAD_START,
@@ -78,17 +80,23 @@ class FileUpload {
78
80
  },
79
81
  });
80
82
  },
81
- completeMultipartUpload: (file, { uploadId, key, parts }) => fetchData({
82
- path: FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
83
- apiKey: __classPrivateFieldGet(this, _FileUpload_accessKey, "f"),
84
- stagingUrl: __classPrivateFieldGet(this, _FileUpload_stagingUrl, "f"),
85
- body: {
86
- uploadId,
87
- objectKey: key,
88
- parts,
89
- originalFileName: file.name,
90
- },
91
- }),
83
+ completeMultipartUpload: (file, { uploadId, key, parts }) => {
84
+ callBack === null || callBack === void 0 ? void 0 : callBack({ eventName: "uploading_complete_start", message: `${parts.length} chunks of file, uploaded` });
85
+ return fetchData({
86
+ path: FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
87
+ apiKey: __classPrivateFieldGet(this, _FileUpload_accessKey, "f"),
88
+ stagingUrl: __classPrivateFieldGet(this, _FileUpload_stagingUrl, "f"),
89
+ body: {
90
+ uploadId,
91
+ objectKey: key,
92
+ parts,
93
+ originalFileName: file.name,
94
+ },
95
+ }).then((response) => {
96
+ callBack === null || callBack === void 0 ? void 0 : callBack({ eventName: "uploading_complete_end", message: `Multipart upload completed successfully` });
97
+ return response;
98
+ });
99
+ },
92
100
  signPart: (file, partData) => fetchData({
93
101
  path: FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
94
102
  stagingUrl: __classPrivateFieldGet(this, _FileUpload_stagingUrl, "f"),
@@ -107,7 +115,12 @@ class FileUpload {
107
115
  data: file,
108
116
  });
109
117
  __classPrivateFieldGet(this, _FileUpload_uppyIns, "f").on("upload-error", (file, error, response) => {
110
- reject(error);
118
+ if (error.isNetworkError) {
119
+ __classPrivateFieldGet(this, _FileUpload_uppyIns, "f").retryUpload(file.id);
120
+ }
121
+ else {
122
+ reject(error);
123
+ }
111
124
  });
112
125
  __classPrivateFieldGet(this, _FileUpload_uppyIns, "f").on("upload-success", () => {
113
126
  resolve({ message: "file uploaded successfully" });
@@ -1,13 +1,4 @@
1
1
  import { AxiosResponse } from "axios";
2
- interface TryOnSocketOptions {
3
- shopDomain: string;
4
- scanId: string;
5
- productName: string;
6
- onError?: (error: any) => void;
7
- onSuccess?: (data: any) => void;
8
- onClose?: () => void;
9
- onOpen?: () => void;
10
- }
11
2
  interface MeasurementRecommendation {
12
3
  shopDomain: string;
13
4
  scanId: string;
@@ -25,8 +16,6 @@ declare class Measurement {
25
16
  constructor(accessKey: string, stagingUrl?: boolean);
26
17
  getMeasurementResult(scanId: string): Promise<AxiosResponse<any>>;
27
18
  getMeasurementRecommendation({ scanId, shopDomain, productName }: MeasurementRecommendation): Promise<AxiosResponse<any>>;
28
- getTryOnMeasurements({ scanId, shopDomain, productName }: TryOnSocketOptions): Promise<AxiosResponse<any>>;
29
- handleTryOnSocket(options: TryOnSocketOptions): void;
30
19
  handleMeasurementSocket(options: MeasurementSocketOptions): void;
31
20
  }
32
21
  export default Measurement;
@@ -18,14 +18,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
18
18
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
19
19
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
20
20
  };
21
- var _Measurement_instances, _Measurement_tryOnSocketRef, _Measurement_measurementSocketRef, _Measurement_timerPollingRef, _Measurement_timerWaitingRef, _Measurement_count, _Measurement_accessKey, _Measurement_stagingUrl, _Measurement_getMeasurementsCheck, _Measurement_handlePolling, _Measurement_disconnectSocket, _Measurement_handleTimeOut;
21
+ var _Measurement_instances, _Measurement_measurementSocketRef, _Measurement_timerPollingRef, _Measurement_timerWaitingRef, _Measurement_count, _Measurement_accessKey, _Measurement_stagingUrl, _Measurement_getMeasurementsCheck, _Measurement_handlePolling, _Measurement_disconnectSocket, _Measurement_handleTimeOut;
22
22
  import axios from "axios";
23
23
  import { API_ENDPOINTS, APP_AUTH_BASE_URL, APP_BASE_WEBSOCKET_URL, REQUIRED_MESSAGE } from "./constants.js";
24
24
  import { checkParameters, getUrl } from "./utils.js";
25
25
  class Measurement {
26
26
  constructor(accessKey, stagingUrl = false) {
27
27
  _Measurement_instances.add(this);
28
- _Measurement_tryOnSocketRef.set(this, null);
29
28
  _Measurement_measurementSocketRef.set(this, null);
30
29
  _Measurement_timerPollingRef.set(this, null);
31
30
  _Measurement_timerWaitingRef.set(this, null);
@@ -50,53 +49,6 @@ class Measurement {
50
49
  }
51
50
  return axios.get(`${getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: __classPrivateFieldGet(this, _Measurement_stagingUrl, "f") })}${API_ENDPOINTS.RECOMMENDATION}/scan/${scanId}/shop/${shopDomain}/product/${productName}`, { headers: { "X-Api-Key": __classPrivateFieldGet(this, _Measurement_accessKey, "f") } });
52
51
  }
53
- getTryOnMeasurements({ scanId, shopDomain, productName }) {
54
- if (!checkParameters(scanId, shopDomain, productName)) {
55
- throw new Error(REQUIRED_MESSAGE);
56
- }
57
- const tryOnUrl = `${getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: __classPrivateFieldGet(this, _Measurement_stagingUrl, "f") })}${API_ENDPOINTS.TRY_ON_SCAN}/${scanId}/shop/${shopDomain}/product/${productName}`;
58
- return axios.get(tryOnUrl, { headers: { "X-Api-Key": __classPrivateFieldGet(this, _Measurement_accessKey, "f") } });
59
- }
60
- handleTryOnSocket(options) {
61
- var _a;
62
- const { shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen } = options;
63
- if (!checkParameters(shopDomain, scanId, productName)) {
64
- throw new Error(REQUIRED_MESSAGE);
65
- }
66
- (_a = __classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f")) === null || _a === void 0 ? void 0 : _a.close();
67
- const url = `${getUrl({
68
- urlName: APP_BASE_WEBSOCKET_URL,
69
- stagingUrl: __classPrivateFieldGet(this, _Measurement_stagingUrl, "f"),
70
- })}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
71
- __classPrivateFieldSet(this, _Measurement_tryOnSocketRef, new WebSocket(url), "f");
72
- if (__classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f")) {
73
- __classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f").onopen = () => {
74
- onOpen === null || onOpen === void 0 ? void 0 : onOpen();
75
- };
76
- __classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f").onmessage = (event) => {
77
- let data;
78
- try {
79
- data = JSON.parse(event.data);
80
- }
81
- catch (error) {
82
- console.log(data, error, "noy correct format for data");
83
- return;
84
- }
85
- if ((data === null || data === void 0 ? void 0 : data.tryOnProcessStatus) === "available") {
86
- onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(data);
87
- }
88
- else {
89
- onError === null || onError === void 0 ? void 0 : onError({ message: "failed to get image urls" });
90
- }
91
- };
92
- __classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f").onclose = () => {
93
- onClose === null || onClose === void 0 ? void 0 : onClose();
94
- };
95
- __classPrivateFieldGet(this, _Measurement_tryOnSocketRef, "f").onerror = (event) => {
96
- onError === null || onError === void 0 ? void 0 : onError(event);
97
- };
98
- }
99
- }
100
52
  handleMeasurementSocket(options) {
101
53
  const { scanId, onError, onSuccess, onClose, onOpen } = options;
102
54
  if (!checkParameters(scanId)) {
@@ -131,7 +83,7 @@ class Measurement {
131
83
  }, 5000);
132
84
  }
133
85
  }
134
- _Measurement_tryOnSocketRef = new WeakMap(), _Measurement_measurementSocketRef = new WeakMap(), _Measurement_timerPollingRef = new WeakMap(), _Measurement_timerWaitingRef = new WeakMap(), _Measurement_count = new WeakMap(), _Measurement_accessKey = new WeakMap(), _Measurement_stagingUrl = new WeakMap(), _Measurement_instances = new WeakSet(), _Measurement_getMeasurementsCheck = function _Measurement_getMeasurementsCheck(options) {
86
+ _Measurement_measurementSocketRef = new WeakMap(), _Measurement_timerPollingRef = new WeakMap(), _Measurement_timerWaitingRef = new WeakMap(), _Measurement_count = new WeakMap(), _Measurement_accessKey = new WeakMap(), _Measurement_stagingUrl = new WeakMap(), _Measurement_instances = new WeakSet(), _Measurement_getMeasurementsCheck = function _Measurement_getMeasurementsCheck(options) {
135
87
  return __awaiter(this, void 0, void 0, function* () {
136
88
  var _a;
137
89
  var _b;
@@ -25,11 +25,15 @@ interface UploadOptions {
25
25
  arrayMetaData: Partial<ObjMetaData>[];
26
26
  scanId: string;
27
27
  email: string;
28
+ callBack?: (a: {
29
+ eventName: string;
30
+ message: string;
31
+ }) => void;
28
32
  }
29
33
  export default class FileUpload {
30
34
  #private;
31
35
  constructor(accessKey: string, stagingUrl?: boolean);
32
- uploadFileFrontend({ file, arrayMetaData, scanId, email }: UploadOptions): Promise<unknown>;
36
+ uploadFileFrontend({ file, arrayMetaData, scanId, email, callBack }: UploadOptions): Promise<unknown>;
33
37
  uploadFile({ file, arrayMetaData, scanId, email }: UploadOptions): Promise<unknown>;
34
38
  setDeviceInfo(data: SetDeviceInfo): Promise<import("axios").AxiosResponse<any, any>>;
35
39
  }
@@ -16,7 +16,7 @@ class FileUpload {
16
16
  this.#accessKey = accessKey;
17
17
  this.#stagingUrl = stagingUrl;
18
18
  }
19
- async uploadFileFrontend({ file, arrayMetaData, scanId, email }) {
19
+ async uploadFileFrontend({ file, arrayMetaData, scanId, email, callBack }) {
20
20
  if (!(0, utils_js_1.checkParameters)(file, arrayMetaData, scanId, email)) {
21
21
  throw new Error(constants_js_1.REQUIRED_MESSAGE);
22
22
  }
@@ -36,8 +36,10 @@ class FileUpload {
36
36
  limit: 10,
37
37
  retryDelays: [0, 1000, 3000, 5000],
38
38
  companionUrl: (0, utils_js_1.getUrl)({ urlName: constants_js_1.APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl }),
39
- getChunkSize: () => 5 * 1024 * 1024,
39
+ getChunkSize: () => constants_js_1.CHUNK_SIZE,
40
40
  createMultipartUpload: (file) => {
41
+ const totalChunks = Math.ceil(file.size / constants_js_1.CHUNK_SIZE);
42
+ callBack?.({ eventName: "uploading_start", message: `File ${file.name} will be divided into ${totalChunks} chunks` });
41
43
  const objectKey = `${scanId}.${file.extension}`;
42
44
  return (0, utils_js_1.fetchData)({
43
45
  path: constants_js_1.FILE_UPLOAD_ENDPOINT.UPLOAD_START,
@@ -50,17 +52,23 @@ class FileUpload {
50
52
  },
51
53
  });
52
54
  },
53
- completeMultipartUpload: (file, { uploadId, key, parts }) => (0, utils_js_1.fetchData)({
54
- path: constants_js_1.FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
55
- apiKey: this.#accessKey,
56
- stagingUrl: this.#stagingUrl,
57
- body: {
58
- uploadId,
59
- objectKey: key,
60
- parts,
61
- originalFileName: file.name,
62
- },
63
- }),
55
+ completeMultipartUpload: (file, { uploadId, key, parts }) => {
56
+ callBack?.({ eventName: "uploading_complete_start", message: `${parts.length} chunks of file, uploaded` });
57
+ return (0, utils_js_1.fetchData)({
58
+ path: constants_js_1.FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
59
+ apiKey: this.#accessKey,
60
+ stagingUrl: this.#stagingUrl,
61
+ body: {
62
+ uploadId,
63
+ objectKey: key,
64
+ parts,
65
+ originalFileName: file.name,
66
+ },
67
+ }).then((response) => {
68
+ callBack?.({ eventName: "uploading_complete_end", message: `Multipart upload completed successfully` });
69
+ return response;
70
+ });
71
+ },
64
72
  signPart: (file, partData) => (0, utils_js_1.fetchData)({
65
73
  path: constants_js_1.FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
66
74
  stagingUrl: this.#stagingUrl,
@@ -79,7 +87,12 @@ class FileUpload {
79
87
  data: file,
80
88
  });
81
89
  this.#uppyIns.on("upload-error", (file, error, response) => {
82
- reject(error);
90
+ if (error.isNetworkError) {
91
+ this.#uppyIns.retryUpload(file.id);
92
+ }
93
+ else {
94
+ reject(error);
95
+ }
83
96
  });
84
97
  this.#uppyIns.on("upload-success", () => {
85
98
  resolve({ message: "file uploaded successfully" });
@@ -1,13 +1,4 @@
1
1
  import { AxiosResponse } from "axios";
2
- interface TryOnSocketOptions {
3
- shopDomain: string;
4
- scanId: string;
5
- productName: string;
6
- onError?: (error: any) => void;
7
- onSuccess?: (data: any) => void;
8
- onClose?: () => void;
9
- onOpen?: () => void;
10
- }
11
2
  interface MeasurementRecommendation {
12
3
  shopDomain: string;
13
4
  scanId: string;
@@ -25,8 +16,6 @@ declare class Measurement {
25
16
  constructor(accessKey: string, stagingUrl?: boolean);
26
17
  getMeasurementResult(scanId: string): Promise<AxiosResponse<any>>;
27
18
  getMeasurementRecommendation({ scanId, shopDomain, productName }: MeasurementRecommendation): Promise<AxiosResponse<any>>;
28
- getTryOnMeasurements({ scanId, shopDomain, productName }: TryOnSocketOptions): Promise<AxiosResponse<any>>;
29
- handleTryOnSocket(options: TryOnSocketOptions): void;
30
19
  handleMeasurementSocket(options: MeasurementSocketOptions): void;
31
20
  }
32
21
  export default Measurement;
@@ -7,7 +7,6 @@ const axios_1 = __importDefault(require("axios"));
7
7
  const constants_js_1 = require("./constants.js");
8
8
  const utils_js_1 = require("./utils.js");
9
9
  class Measurement {
10
- #tryOnSocketRef = null;
11
10
  #measurementSocketRef = null;
12
11
  #timerPollingRef = null;
13
12
  #timerWaitingRef = null;
@@ -33,52 +32,6 @@ class Measurement {
33
32
  }
34
33
  return axios_1.default.get(`${(0, utils_js_1.getUrl)({ urlName: constants_js_1.APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl })}${constants_js_1.API_ENDPOINTS.RECOMMENDATION}/scan/${scanId}/shop/${shopDomain}/product/${productName}`, { headers: { "X-Api-Key": this.#accessKey } });
35
34
  }
36
- getTryOnMeasurements({ scanId, shopDomain, productName }) {
37
- if (!(0, utils_js_1.checkParameters)(scanId, shopDomain, productName)) {
38
- throw new Error(constants_js_1.REQUIRED_MESSAGE);
39
- }
40
- const tryOnUrl = `${(0, utils_js_1.getUrl)({ urlName: constants_js_1.APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl })}${constants_js_1.API_ENDPOINTS.TRY_ON_SCAN}/${scanId}/shop/${shopDomain}/product/${productName}`;
41
- return axios_1.default.get(tryOnUrl, { headers: { "X-Api-Key": this.#accessKey } });
42
- }
43
- handleTryOnSocket(options) {
44
- const { shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen } = options;
45
- if (!(0, utils_js_1.checkParameters)(shopDomain, scanId, productName)) {
46
- throw new Error(constants_js_1.REQUIRED_MESSAGE);
47
- }
48
- this.#tryOnSocketRef?.close();
49
- const url = `${(0, utils_js_1.getUrl)({
50
- urlName: constants_js_1.APP_BASE_WEBSOCKET_URL,
51
- stagingUrl: this.#stagingUrl,
52
- })}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
53
- this.#tryOnSocketRef = new WebSocket(url);
54
- if (this.#tryOnSocketRef) {
55
- this.#tryOnSocketRef.onopen = () => {
56
- onOpen?.();
57
- };
58
- this.#tryOnSocketRef.onmessage = (event) => {
59
- let data;
60
- try {
61
- data = JSON.parse(event.data);
62
- }
63
- catch (error) {
64
- console.log(data, error, "noy correct format for data");
65
- return;
66
- }
67
- if (data?.tryOnProcessStatus === "available") {
68
- onSuccess?.(data);
69
- }
70
- else {
71
- onError?.({ message: "failed to get image urls" });
72
- }
73
- };
74
- this.#tryOnSocketRef.onclose = () => {
75
- onClose?.();
76
- };
77
- this.#tryOnSocketRef.onerror = (event) => {
78
- onError?.(event);
79
- };
80
- }
81
- }
82
35
  async #getMeasurementsCheck(options) {
83
36
  const { scanId, onSuccess, onError } = options;
84
37
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-admin/swan-ai-measurements",
3
- "version": "1.1.46",
3
+ "version": "1.1.48",
4
4
  "description": "provides ai measurement suggestion",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",
package/src/constants.ts CHANGED
@@ -65,3 +65,4 @@ export const requiredMetaData: RequiredMetaDataKeys[] = ["gender", "focal_length
65
65
  export const REQUIRED_MESSAGE: string = "Please verify required parameters";
66
66
  export const REQUIRED_MESSAGE_FOR_META_DATA: string = "Please verify required parameters in meta data";
67
67
  export const REQUIRED_ERROR_MESSAGE_INVALID_EMAIL = "Invalid Email";
68
+ export const CHUNK_SIZE = 5 * 1024 * 1024;
package/src/fileUpload.ts CHANGED
@@ -1,12 +1,5 @@
1
1
  import axios from "axios";
2
- import {
3
- REQUIRED_MESSAGE,
4
- REQUIRED_MESSAGE_FOR_META_DATA,
5
- FILE_UPLOAD_ENDPOINT,
6
- APP_AUTH_BASE_URL,
7
- REQUIRED_ERROR_MESSAGE_INVALID_EMAIL,
8
- API_ENDPOINTS,
9
- } from "./constants.js";
2
+ import { REQUIRED_MESSAGE, REQUIRED_MESSAGE_FOR_META_DATA, FILE_UPLOAD_ENDPOINT, APP_AUTH_BASE_URL, REQUIRED_ERROR_MESSAGE_INVALID_EMAIL, API_ENDPOINTS, CHUNK_SIZE } from "./constants.js";
10
3
  import { addScanType, checkMetaDataValue, checkParameters, fetchData, getFileChunks, getUrl, isValidEmail } from "./utils.js";
11
4
  import Uppy from "@uppy/core";
12
5
  import AwsS3Multipart from "@uppy/aws-s3-multipart";
@@ -26,7 +19,7 @@ interface SetDeviceInfo {
26
19
  detection?: string;
27
20
  model?: string;
28
21
  gyro: { alpha?: string; gamma?: string; beta?: string; timestamp?: string }[];
29
- scanId:string
22
+ scanId: string;
30
23
  }
31
24
 
32
25
  interface UploadOptions {
@@ -34,6 +27,7 @@ interface UploadOptions {
34
27
  arrayMetaData: Partial<ObjMetaData>[];
35
28
  scanId: string;
36
29
  email: string;
30
+ callBack?: (a: { eventName: string; message: string }) => void;
37
31
  }
38
32
 
39
33
  export default class FileUpload {
@@ -46,7 +40,7 @@ export default class FileUpload {
46
40
  this.#stagingUrl = stagingUrl;
47
41
  }
48
42
 
49
- async uploadFileFrontend({ file, arrayMetaData, scanId, email }: UploadOptions) {
43
+ async uploadFileFrontend({ file, arrayMetaData, scanId, email, callBack }: UploadOptions) {
50
44
  if (!checkParameters(file, arrayMetaData, scanId, email)) {
51
45
  throw new Error(REQUIRED_MESSAGE);
52
46
  }
@@ -66,8 +60,10 @@ export default class FileUpload {
66
60
  limit: 10,
67
61
  retryDelays: [0, 1000, 3000, 5000],
68
62
  companionUrl: getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl }),
69
- getChunkSize: () => 5 * 1024 * 1024,
63
+ getChunkSize: () => CHUNK_SIZE,
70
64
  createMultipartUpload: (file: any) => {
65
+ const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
66
+ callBack?.({eventName:"uploading_start",message:`File ${file.name} will be divided into ${totalChunks} chunks`})
71
67
  const objectKey = `${scanId}.${file.extension}`;
72
68
  return fetchData({
73
69
  path: FILE_UPLOAD_ENDPOINT.UPLOAD_START,
@@ -80,8 +76,9 @@ export default class FileUpload {
80
76
  },
81
77
  });
82
78
  },
83
- completeMultipartUpload: (file: any, { uploadId, key, parts }: { uploadId: string | number; key: string | number; parts: any }) =>
84
- fetchData({
79
+ completeMultipartUpload: (file: any, { uploadId, key, parts }: { uploadId: string | number; key: string | number; parts: any }) => {
80
+ callBack?.({eventName:"uploading_complete_start",message:`${parts.length} chunks of file, uploaded`})
81
+ return fetchData({
85
82
  path: FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
86
83
  apiKey: this.#accessKey,
87
84
  stagingUrl: this.#stagingUrl,
@@ -91,7 +88,11 @@ export default class FileUpload {
91
88
  parts,
92
89
  originalFileName: file.name,
93
90
  },
94
- }),
91
+ }).then((response) => {
92
+ callBack?.({eventName:"uploading_complete_end",message:`Multipart upload completed successfully`})
93
+ return response;
94
+ });
95
+ },
95
96
 
96
97
  signPart: (file: any, partData: any) =>
97
98
  fetchData({
@@ -114,7 +115,11 @@ export default class FileUpload {
114
115
  });
115
116
 
116
117
  this.#uppyIns.on("upload-error", (file: any, error: any, response: any) => {
117
- reject(error);
118
+ if (error.isNetworkError) {
119
+ this.#uppyIns.retryUpload(file.id);
120
+ }else{
121
+ reject(error);
122
+ }
118
123
  });
119
124
  this.#uppyIns.on("upload-success", () => {
120
125
  resolve({ message: "file uploaded successfully" });
@@ -185,13 +190,17 @@ export default class FileUpload {
185
190
  }
186
191
  });
187
192
  }
188
- async setDeviceInfo(data:SetDeviceInfo) {
189
- const {scanId,...rest} = data;
193
+ async setDeviceInfo(data: SetDeviceInfo) {
194
+ const { scanId, ...rest } = data;
190
195
  if (checkParameters(scanId) === false) {
191
196
  throw new Error(REQUIRED_MESSAGE);
192
- }
193
- return axios.post(`${getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl })}${API_ENDPOINTS.DEVICE_INFO}/${scanId}`,{device_info:{...rest}} , {
194
- headers: { "X-Api-Key": this.#accessKey },
195
- });
197
+ }
198
+ return axios.post(
199
+ `${getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl })}${API_ENDPOINTS.DEVICE_INFO}/${scanId}`,
200
+ { device_info: { ...rest } },
201
+ {
202
+ headers: { "X-Api-Key": this.#accessKey },
203
+ },
204
+ );
196
205
  }
197
206
  }
@@ -3,15 +3,7 @@ import { API_ENDPOINTS, APP_AUTH_BASE_URL, APP_BASE_WEBSOCKET_URL, REQUIRED_MESS
3
3
  import { checkParameters, getUrl } from "./utils.js";
4
4
 
5
5
 
6
- interface TryOnSocketOptions {
7
- shopDomain: string;
8
- scanId: string;
9
- productName: string;
10
- onError?: (error: any) => void;
11
- onSuccess?: (data: any) => void;
12
- onClose?: () => void;
13
- onOpen?: () => void;
14
- }
6
+
15
7
 
16
8
  interface MeasurementRecommendation {
17
9
  shopDomain: string;
@@ -45,7 +37,6 @@ interface HandleTimeOutOptions {
45
37
  }
46
38
 
47
39
  class Measurement {
48
- #tryOnSocketRef: WebSocket | null = null;
49
40
  #measurementSocketRef: WebSocket | null = null;
50
41
  #timerPollingRef: NodeJS.Timeout | null = null;
51
42
  #timerWaitingRef: NodeJS.Timeout | null = null;
@@ -80,61 +71,7 @@ class Measurement {
80
71
  );
81
72
  }
82
73
 
83
- getTryOnMeasurements({ scanId, shopDomain, productName }: TryOnSocketOptions): Promise<AxiosResponse<any>> {
84
- if (!checkParameters(scanId, shopDomain, productName)) {
85
- throw new Error(REQUIRED_MESSAGE);
86
- }
87
- const tryOnUrl = `${getUrl({ urlName: APP_AUTH_BASE_URL, stagingUrl: this.#stagingUrl })}${
88
- API_ENDPOINTS.TRY_ON_SCAN
89
- }/${scanId}/shop/${shopDomain}/product/${productName}`;
90
- return axios.get(tryOnUrl, { headers: { "X-Api-Key": this.#accessKey } });
91
- }
92
-
93
- handleTryOnSocket(options: TryOnSocketOptions): void {
94
- const { shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen } = options;
95
-
96
- if (!checkParameters(shopDomain, scanId, productName)) {
97
- throw new Error(REQUIRED_MESSAGE);
98
- }
99
-
100
- this.#tryOnSocketRef?.close();
101
- const url = `${getUrl({
102
- urlName: APP_BASE_WEBSOCKET_URL,
103
- stagingUrl: this.#stagingUrl,
104
- })}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
105
- this.#tryOnSocketRef = new WebSocket(url);
106
- if (this.#tryOnSocketRef) {
107
- this.#tryOnSocketRef.onopen = () => {
108
- onOpen?.();
109
- };
110
-
111
- this.#tryOnSocketRef.onmessage = (event) => {
112
- let data;
113
- try {
114
- data = JSON.parse(event.data);
115
- } catch (error) {
116
- console.log(data, error, "noy correct format for data");
117
-
118
- return;
119
- }
120
- if (data?.tryOnProcessStatus === "available") {
121
- onSuccess?.(data);
122
- } else {
123
- onError?.({ message: "failed to get image urls" });
124
- }
125
- };
126
74
 
127
- this.#tryOnSocketRef.onclose = () => {
128
- onClose?.();
129
- };
130
-
131
- this.#tryOnSocketRef.onerror = (event) => {
132
- onError?.(event);
133
- };
134
- }
135
-
136
- }
137
-
138
75
  async #getMeasurementsCheck(options: GetMeasurementsCheckOptions): Promise<void> {
139
76
  const { scanId, onSuccess, onError } = options;
140
77