@swan-admin/swan-ai-measurements 1.0.11 → 1.0.13
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/auth.js +62 -0
- package/constants.js +15 -0
- package/custom.js +7 -0
- package/fileUpload.js +80 -0
- package/index.js +56 -73
- package/measurement.js +127 -0
- package/package.json +1 -1
package/auth.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { API_ENDPOINTS, APP_AUTH_BASE_URL, APP_AUTH_WEBSOCKET_URL, APP_BASE_URL } from "./constants.js";
|
|
3
|
+
let socketRef;
|
|
4
|
+
|
|
5
|
+
export const registerUser = ({ email, appVerifyUrl, gender, height, username = "", accessKey }) => {
|
|
6
|
+
let body = {
|
|
7
|
+
username,
|
|
8
|
+
email,
|
|
9
|
+
appVerifyUrl,
|
|
10
|
+
};
|
|
11
|
+
if (gender && height) {
|
|
12
|
+
body = { ...body, attributes: { gender, height } };
|
|
13
|
+
}
|
|
14
|
+
return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.REGISTER_USER}`, body);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const verifyToken = (token, accessKey) =>
|
|
18
|
+
axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.VERIFY_USER}`, null, {
|
|
19
|
+
params: { token },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const addUser = ({ scanId, email, name, height, gender, accessKey, offsetMarketingConsent }) =>
|
|
23
|
+
axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.ADD_USER}`, {
|
|
24
|
+
scan_id: scanId,
|
|
25
|
+
email,
|
|
26
|
+
name,
|
|
27
|
+
offsetMarketingConsent,
|
|
28
|
+
attributes: JSON.stringify({ height, gender }),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const getUserDetail = (email, accessKey) =>
|
|
32
|
+
axios.get(`${APP_BASE_URL}${API_ENDPOINTS.GET_USER_DETAIL}/${email}`);
|
|
33
|
+
|
|
34
|
+
export const handleAuthSocket = ({ email, scanId, accessKey, onError, onSuccess, onClose, onOpen }) => {
|
|
35
|
+
if (socketRef) {
|
|
36
|
+
socketRef.close();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
socketRef = new WebSocket(APP_AUTH_WEBSOCKET_URL);
|
|
40
|
+
const detailObj = {
|
|
41
|
+
email,
|
|
42
|
+
scanId,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
socketRef.onopen = () => {
|
|
46
|
+
onOpen();
|
|
47
|
+
socketRef.send(JSON.stringify(detailObj));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
socketRef.onmessage = (event) => {
|
|
51
|
+
const data = JSON.parse(event.data);
|
|
52
|
+
onSuccess(data);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
socketRef.onclose = () => {
|
|
56
|
+
onClose();
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
socketRef.current.onerror = (event) => {
|
|
60
|
+
onError(event);
|
|
61
|
+
};
|
|
62
|
+
};
|
package/constants.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export const FILE_UPLOAD_URL = "https://9xc8mxwlkj.execute-api.us-east-1.amazonaws.com/staging";
|
|
2
2
|
export const FILE_UPLOAD_KEY = "7a8ccc86249849be911b0d7dbc20290e";
|
|
3
|
+
export const APP_BASE_URL = "https://fitview-server-staging.ft2a64raup4pg.us-east-1.cs.amazonlightsail.com";
|
|
4
|
+
export const APP_AUTH_BASE_URL = "https://staging.api.getswan.co";
|
|
5
|
+
export const APP_AUTH_WEBSOCKET_URL = "wss://develop.wsnotify.api.getswan.co/auth";
|
|
6
|
+
export const APP_TRY_ON_WEBSOCKET_URL = "wss://bucbzczxjk.execute-api.ap-south-1.amazonaws.com";
|
|
7
|
+
export const APP_RECOMMENDATION_WEBSOCKET_URL = "wss://9cfbimvp2e.execute-api.us-east-1.amazonaws.com/staging";
|
|
3
8
|
|
|
4
9
|
export const UPPY_FILE_UPLOAD_ENDPOINT = {
|
|
5
10
|
UPLOAD_START: "/upload/start",
|
|
@@ -7,3 +12,13 @@ export const UPPY_FILE_UPLOAD_ENDPOINT = {
|
|
|
7
12
|
UPLOAD_SIGN_PART: "/upload/signpart",
|
|
8
13
|
UPLOAD_ABORT: "/upload/abort",
|
|
9
14
|
};
|
|
15
|
+
|
|
16
|
+
export const API_ENDPOINTS = {
|
|
17
|
+
GET_USER_DETAIL: "/api/user",
|
|
18
|
+
REGISTER_USER: "/auth/register",
|
|
19
|
+
VERIFY_USER: "/auth/verify",
|
|
20
|
+
ADD_USER: "/user",
|
|
21
|
+
CUSTOM_CUSTOMER: "/customers/custom",
|
|
22
|
+
MODEL: "/model",
|
|
23
|
+
TRY_ON: "/tryon/scan",
|
|
24
|
+
};
|
package/custom.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { API_ENDPOINTS, APP_AUTH_BASE_URL } from "./constants.js";
|
|
3
|
+
|
|
4
|
+
export const getCustomCustomerConfig = (store_url, accessKey) =>
|
|
5
|
+
axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.CUSTOM_CUSTOMER}`, { params: { store_url } });
|
|
6
|
+
|
|
7
|
+
export const getModelUrl = (id, accessKey) => axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.MODEL}/${id}`);
|
package/fileUpload.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import AwsS3Multipart from "@uppy/aws-s3-multipart";
|
|
2
|
+
import Uppy from "@uppy/core";
|
|
3
|
+
import { FILE_UPLOAD_KEY, UPPY_FILE_UPLOAD_ENDPOINT } from "./constants.js";
|
|
4
|
+
|
|
5
|
+
function uploadFile({ file, objMetaData, scanId, accessKey }) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
uppyIns = new Uppy({ autoProceed: true });
|
|
8
|
+
uppyIns.use(AwsS3Multipart, {
|
|
9
|
+
limit: 10,
|
|
10
|
+
retryDelays: [0, 1000, 3000, 5000],
|
|
11
|
+
getChunkSize: () => 5 * 1024 * 1024,
|
|
12
|
+
createMultipartUpload: (file) => {
|
|
13
|
+
const objectKey = `${scanId}.${file.extension}`;
|
|
14
|
+
return fetchData({
|
|
15
|
+
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_START,
|
|
16
|
+
apiKey: FILE_UPLOAD_KEY,
|
|
17
|
+
body: {
|
|
18
|
+
objectKey,
|
|
19
|
+
contentType: file.type,
|
|
20
|
+
objectMetadata: objMetaData,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
completeMultipartUpload: (file, { uploadId, key, parts }) =>
|
|
25
|
+
fetchData({
|
|
26
|
+
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
|
|
27
|
+
apiKey: FILE_UPLOAD_KEY,
|
|
28
|
+
body: {
|
|
29
|
+
uploadId,
|
|
30
|
+
objectKey: key,
|
|
31
|
+
parts,
|
|
32
|
+
originalFileName: file.name,
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
signPart: (file, partData) =>
|
|
37
|
+
fetchData({
|
|
38
|
+
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
|
|
39
|
+
apiKey: FILE_UPLOAD_KEY,
|
|
40
|
+
body: {
|
|
41
|
+
objectKey: partData.key,
|
|
42
|
+
uploadId: partData.uploadId,
|
|
43
|
+
partNumber: partData.partNumber,
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
abortMultipartUpload: (file, { uploadId, key }) =>
|
|
48
|
+
fetchData({
|
|
49
|
+
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_ABORT,
|
|
50
|
+
apiKey: FILE_UPLOAD_KEY,
|
|
51
|
+
body: {
|
|
52
|
+
uploadId,
|
|
53
|
+
objectKey: key,
|
|
54
|
+
originalFileName: file.name,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
uppyIns.addFile({
|
|
60
|
+
source: "manual",
|
|
61
|
+
name: file.name,
|
|
62
|
+
type: file.type,
|
|
63
|
+
data: file,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
uppyIns.on("upload-error", (file, error, response) => {
|
|
67
|
+
reject(error);
|
|
68
|
+
});
|
|
69
|
+
uppyIns.on("upload-success", () => {
|
|
70
|
+
resolve({ message: "file uploaded successfully" });
|
|
71
|
+
});
|
|
72
|
+
uppyIns.on("complete", (result) => {
|
|
73
|
+
if (uppyIns) {
|
|
74
|
+
uppyIns.close();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default uploadFile;
|
package/index.js
CHANGED
|
@@ -1,87 +1,70 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import AwsS3Multipart from "@uppy/aws-s3-multipart";
|
|
1
|
+
import { addUser, getUserDetail, registerUser, verifyToken } from "./auth.js";
|
|
2
|
+
import { getCustomCustomerConfig } from "./custom.js";
|
|
3
|
+
import uploadFile from "./fileUpload.js";
|
|
5
4
|
export default class Swan {
|
|
6
5
|
constructor(key) {
|
|
7
|
-
if (key !==
|
|
6
|
+
if (key !== 9876543210) {
|
|
8
7
|
throw new Error("wrong access key");
|
|
9
8
|
}
|
|
10
9
|
this.accessKey = key;
|
|
11
|
-
this.uppyIns = null;
|
|
12
10
|
}
|
|
11
|
+
|
|
12
|
+
registerUser({ email, appVerifyUrl, gender, height, username }) {
|
|
13
|
+
return registerUser({ email, appVerifyUrl, gender, height, username, accessKey: this.accessKey });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
verifyToken(token) {
|
|
17
|
+
return verifyToken(token, this.accessKey);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
addUser({ scanId, email, name, height, gender, offsetMarketingConsent }) {
|
|
21
|
+
return addUser({ scanId, email, name, height, gender, offsetMarketingConsent, accessKey: this.accessKey });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getUserDetail(email) {
|
|
25
|
+
return getUserDetail(email, this.accessKey);
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
uploadFile({ file, objMetaData, scanId }) {
|
|
14
|
-
return
|
|
15
|
-
|
|
16
|
-
this.uppyIns.use(AwsS3Multipart, {
|
|
17
|
-
limit: 10,
|
|
18
|
-
retryDelays: [0, 1000, 3000, 5000],
|
|
19
|
-
getChunkSize: () => 5 * 1024 * 1024,
|
|
20
|
-
createMultipartUpload: (file) => {
|
|
21
|
-
const objectKey = `${scanId}.${file.extension}`;
|
|
22
|
-
return fetchData({
|
|
23
|
-
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_START,
|
|
24
|
-
apiKey: this.accessKey,
|
|
25
|
-
body: {
|
|
26
|
-
objectKey,
|
|
27
|
-
contentType: file.type,
|
|
28
|
-
objectMetadata: objMetaData,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
completeMultipartUpload: (file, { uploadId, key, parts }) =>
|
|
33
|
-
fetchData({
|
|
34
|
-
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
|
|
35
|
-
apiKey: this.accessKey,
|
|
36
|
-
body: {
|
|
37
|
-
uploadId,
|
|
38
|
-
objectKey: key,
|
|
39
|
-
parts,
|
|
40
|
-
originalFileName: file.name,
|
|
41
|
-
},
|
|
42
|
-
}),
|
|
29
|
+
return uploadFile({ file, objMetaData, scanId, accessKey: this.accessKey });
|
|
30
|
+
}
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
apiKey: this.accessKey,
|
|
48
|
-
body: {
|
|
49
|
-
objectKey: partData.key,
|
|
50
|
-
uploadId: partData.uploadId,
|
|
51
|
-
partNumber: partData.partNumber,
|
|
52
|
-
},
|
|
53
|
-
}),
|
|
32
|
+
getModelUrl(id) {
|
|
33
|
+
return getModelUrl(id, this.accessKey);
|
|
34
|
+
}
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
apiKey: this.accessKey,
|
|
59
|
-
body: {
|
|
60
|
-
uploadId,
|
|
61
|
-
objectKey: key,
|
|
62
|
-
originalFileName: file.name,
|
|
63
|
-
},
|
|
64
|
-
}),
|
|
65
|
-
});
|
|
36
|
+
getCustomCustomerConfig(storeUrl) {
|
|
37
|
+
return getCustomCustomerConfig(storeUrl, this.accessKey);
|
|
38
|
+
}
|
|
66
39
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
40
|
+
getMeasurementStatus(scanId) {
|
|
41
|
+
return getMeasurementStatus(scanId, this.accessKey);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getTryOnMeasurements({ scanId, shopDomain, productName }) {
|
|
45
|
+
return getTryOnMeasurements({ scanId, shopDomain, productName, accessKey: this.accessKey });
|
|
46
|
+
}
|
|
73
47
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
48
|
+
handleTryOnSocket({ shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen }) {
|
|
49
|
+
return handleTryOnSocket({
|
|
50
|
+
shopDomain,
|
|
51
|
+
scanId,
|
|
52
|
+
productName,
|
|
53
|
+
accessKey: this.accessKey,
|
|
54
|
+
onError,
|
|
55
|
+
onSuccess,
|
|
56
|
+
onClose,
|
|
57
|
+
onOpen,
|
|
85
58
|
});
|
|
86
59
|
}
|
|
60
|
+
|
|
61
|
+
handleMeasurementSocket({ scanId, onError, onSuccess, onClose, onOpen }) {
|
|
62
|
+
return handleMeasurementSocket({ scanId, accessKey: this.accessKey, onError, onSuccess, onClose, onOpen });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
handleAuthSocket({ email, scanId, onError, onSuccess, onClose, onOpen }) {
|
|
66
|
+
return handleAuthSocket({ email, scanId, accessKey: this.accessKey, onError, onSuccess, onClose, onOpen });
|
|
67
|
+
}
|
|
87
68
|
}
|
|
69
|
+
|
|
70
|
+
const a = new Swan(9876543210);
|
package/measurement.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import {
|
|
3
|
+
API_ENDPOINTS,
|
|
4
|
+
APP_AUTH_BASE_URL,
|
|
5
|
+
APP_RECOMMENDATION_WEBSOCKET_URL,
|
|
6
|
+
APP_TRY_ON_WEBSOCKET_URL,
|
|
7
|
+
FILE_UPLOAD_KEY,
|
|
8
|
+
FILE_UPLOAD_URL,
|
|
9
|
+
} from "./constants.js";
|
|
10
|
+
|
|
11
|
+
let tryOnSocketRef;
|
|
12
|
+
let measurementSocketRef;
|
|
13
|
+
let timerPollingRef;
|
|
14
|
+
let timerWaitingRef;
|
|
15
|
+
|
|
16
|
+
export const getMeasurementStatus = (scanId, accessKey) => {
|
|
17
|
+
const url = `${FILE_UPLOAD_URL}/measurements?scanId=${scanId}`;
|
|
18
|
+
return axios.get(url, {
|
|
19
|
+
headers: { "X-Api-Key": FILE_UPLOAD_KEY },
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const getTryOnMeasurements = ({ scanId, shopDomain, productName, accessKey }) => {
|
|
24
|
+
const tryOnUrl = `${APP_AUTH_BASE_URL}${API_ENDPOINTS.TRY_ON}/${scanId}/shop/${shopDomain}/product/${productName}`;
|
|
25
|
+
return axios.get(tryOnUrl);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const handleTryOnSocket = ({
|
|
29
|
+
shopDomain,
|
|
30
|
+
scanId,
|
|
31
|
+
productName,
|
|
32
|
+
accessKey,
|
|
33
|
+
onError,
|
|
34
|
+
onSuccess,
|
|
35
|
+
onClose,
|
|
36
|
+
onOpen,
|
|
37
|
+
}) => {
|
|
38
|
+
if (tryOnSocketRef) {
|
|
39
|
+
tryOnSocketRef.close();
|
|
40
|
+
}
|
|
41
|
+
const url = `${APP_TRY_ON_WEBSOCKET_URL}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
|
|
42
|
+
tryOnSocketRef = new WebSocket(url);
|
|
43
|
+
|
|
44
|
+
tryOnSocketRef.onopen = () => {
|
|
45
|
+
onOpen();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
tryOnSocketRef.onmessage = (event) => {
|
|
49
|
+
const data = JSON.parse(event.data);
|
|
50
|
+
if (data?.tryOnProcessStatus === "available") {
|
|
51
|
+
onSuccess(data);
|
|
52
|
+
} else {
|
|
53
|
+
onError({ message: "failed to get image urls" });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
tryOnSocketRef.onclose = () => {
|
|
58
|
+
onClose();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
tryOnSocketRef.onerror = (event) => {
|
|
62
|
+
onError(event);
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const getMeasurementsCheck = async (onSuccess, onError, scanId, accessKey) => {
|
|
67
|
+
try {
|
|
68
|
+
const res = await getMeasurementStatus(scanId, accessKey);
|
|
69
|
+
if (res?.data && res?.data?.[0]?.isMeasured === true) {
|
|
70
|
+
onSuccess(res?.data);
|
|
71
|
+
clearInterval(timerPollingRef);
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
clearInterval(timerPollingRef);
|
|
75
|
+
onError(e);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handlePolling = (onSuccess, onError) => {
|
|
80
|
+
clearInterval(timerPollingRef);
|
|
81
|
+
timerPollingRef = setInterval(() => {
|
|
82
|
+
getMeasurementsCheck(onSuccess, onError);
|
|
83
|
+
}, 5000);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const disconnectSocket = () => {
|
|
87
|
+
if (measurementSocketRef) {
|
|
88
|
+
measurementSocketRef.close();
|
|
89
|
+
clearTimeout(timerWaitingRef);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const handleTimeOut = (onSuccess, onError) => {
|
|
94
|
+
timerWaitingRef = setTimeout(() => {
|
|
95
|
+
handlePolling(onSuccess, onError);
|
|
96
|
+
disconnectSocket();
|
|
97
|
+
}, 2 * 60000);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const handleMeasurementSocket = ({ scanId, accessKey, onError, onSuccess, onClose, onOpen }) => {
|
|
101
|
+
disconnectSocket();
|
|
102
|
+
const url = `${APP_RECOMMENDATION_WEBSOCKET_URL}?scanId=${scanId}`;
|
|
103
|
+
measurementSocketRef = new WebSocket(url);
|
|
104
|
+
|
|
105
|
+
measurementSocketRef.onopen = () => {
|
|
106
|
+
onOpen();
|
|
107
|
+
handleTimeOut(onSuccess, onError);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
measurementSocketRef.onmessage = (event) => {
|
|
111
|
+
const data = JSON.parse(event.data);
|
|
112
|
+
if (data?.code === 200 && data?.scanStatus === "success") {
|
|
113
|
+
onSuccess(data);
|
|
114
|
+
} else {
|
|
115
|
+
onError(data);
|
|
116
|
+
}
|
|
117
|
+
clearTimeout(timerWaitingRef);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
measurementSocketRef.onclose = () => {
|
|
121
|
+
onClose();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
measurementSocketRef.current.onerror = (event) => {
|
|
125
|
+
onError(event);
|
|
126
|
+
};
|
|
127
|
+
};
|