@swan-admin/swan-ai-measurements 1.1.46 → 1.1.47
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/package.json +1 -1
- package/src/constants.ts +1 -0
- package/src/fileUpload.ts +30 -21
- package/src/measurement.ts +1 -64
package/package.json
CHANGED
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: () =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
194
|
-
|
|
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
|
}
|
package/src/measurement.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|