@swan-admin/swan-ai-measurements 1.0.53 → 1.0.55
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 +74 -14
- package/custom.js +36 -6
- package/fileUpload.js +51 -11
- package/index.js +10 -6
- package/measurement.js +98 -23
- package/package.json +20 -3
- package/poseDetection.js +44 -19
- package/tryOn.js +123 -29
- package/types/auth.d.ts +78 -0
- package/types/constants.d.ts +30 -0
- package/types/custom.d.ts +26 -0
- package/types/fileUpload.d.ts +31 -0
- package/types/index.d.ts +17 -0
- package/types/measurement.d.ts +69 -0
- package/types/poseDetection.d.ts +43 -0
- package/types/tryOn.d.ts +90 -0
- package/types/utils.d.ts +13 -0
- package/utils.js +59 -59
- package/constants.js +0 -46
package/auth.js
CHANGED
|
@@ -2,11 +2,38 @@ const axios = require("axios");
|
|
|
2
2
|
const { API_ENDPOINTS, APP_AUTH_BASE_URL, APP_AUTH_WEBSOCKET_URL, APP_BASE_URL, REQUIRED_MESSAGE } = require("./constants.js");
|
|
3
3
|
const { checkParameters } = require("./utils.js");
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Represents a Auth class for handling authentication operations.
|
|
7
|
+
*/
|
|
5
8
|
class Auth {
|
|
6
9
|
#socketRef;
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The access key used for authentication.
|
|
13
|
+
* @type {string}
|
|
14
|
+
* @private
|
|
15
|
+
*/
|
|
16
|
+
#accessKey;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Constructs a new instance of the Auth class.
|
|
20
|
+
* @param {string} accessKey - The access key used for authentication.
|
|
21
|
+
*/
|
|
22
|
+
constructor(accessKey) {
|
|
23
|
+
this.#accessKey = accessKey;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Register a new user.
|
|
27
|
+
* @param {Object} params - The parameters for user registration.
|
|
28
|
+
* @param {string} params.email - The email of the user.
|
|
29
|
+
* @param {string} params.appVerifyUrl - The verification URL.
|
|
30
|
+
* @param {string} [params.gender] - Optional. The gender of the user.
|
|
31
|
+
* @param {string} [params.height] - Optional. The height of the user.
|
|
32
|
+
* @param {string} params.username - Optional. The username of the user.
|
|
33
|
+
* @returns {Promise} - The axios response promise.
|
|
34
|
+
*/
|
|
35
|
+
registerUser({ email, appVerifyUrl, gender, height, username }) {
|
|
36
|
+
if (checkParameters(email, appVerifyUrl) === false) {
|
|
10
37
|
throw new Error(REQUIRED_MESSAGE);
|
|
11
38
|
}
|
|
12
39
|
let body = {
|
|
@@ -18,22 +45,40 @@ class Auth {
|
|
|
18
45
|
body = { ...body, attributes: { gender, height } };
|
|
19
46
|
}
|
|
20
47
|
return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.REGISTER_USER}`, body, {
|
|
21
|
-
headers: { "X-Api-Key": accessKey },
|
|
48
|
+
headers: { "X-Api-Key": this.#accessKey },
|
|
22
49
|
});
|
|
23
50
|
}
|
|
24
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Verify a user token.
|
|
54
|
+
* @param {string} token
|
|
55
|
+
* @returns {Promise}
|
|
56
|
+
*/
|
|
57
|
+
|
|
25
58
|
verifyToken = (token, accessKey) => {
|
|
26
|
-
if (checkParameters(token
|
|
59
|
+
if (checkParameters(token) === false) {
|
|
27
60
|
throw new Error(REQUIRED_MESSAGE);
|
|
28
61
|
}
|
|
29
62
|
return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.VERIFY_USER}`, null, {
|
|
30
63
|
params: { token },
|
|
31
|
-
headers: { "X-Api-Key": accessKey },
|
|
64
|
+
headers: { "X-Api-Key": this.#accessKey },
|
|
32
65
|
});
|
|
33
66
|
};
|
|
34
67
|
|
|
35
|
-
|
|
36
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Add a user.
|
|
70
|
+
* @param {Object} params
|
|
71
|
+
* @param {string} params.scanId - The scan ID.
|
|
72
|
+
* @param {string} params.email - The email of the user.
|
|
73
|
+
* @param {string} params.name - The name of the user.
|
|
74
|
+
* @param {string} params.height - The height of the user.
|
|
75
|
+
* @param {string} params.gender - The gender of the user.
|
|
76
|
+
* @param {boolean} [params.offsetMarketingConsent] - Optional. The marketing consent offset.
|
|
77
|
+
* @returns {Promise} - The axios response promise.
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
addUser = ({ scanId, email, name, height, gender, offsetMarketingConsent }) => {
|
|
81
|
+
if (checkParameters(scanId, email, height, gender) === false) {
|
|
37
82
|
throw new Error(REQUIRED_MESSAGE);
|
|
38
83
|
}
|
|
39
84
|
return axios.post(
|
|
@@ -45,21 +90,36 @@ class Auth {
|
|
|
45
90
|
offsetMarketingConsent,
|
|
46
91
|
attributes: JSON.stringify({ height, gender }),
|
|
47
92
|
},
|
|
48
|
-
{ headers: { "X-Api-Key": accessKey } }
|
|
93
|
+
{ headers: { "X-Api-Key": this.#accessKey } }
|
|
49
94
|
);
|
|
50
95
|
};
|
|
51
96
|
|
|
52
|
-
|
|
53
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Get user details.
|
|
99
|
+
* @param {string} email
|
|
100
|
+
* @returns {Promise}
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
getUserDetail = (email) => {
|
|
104
|
+
if (checkParameters(email) === false) {
|
|
54
105
|
throw new Error(REQUIRED_MESSAGE);
|
|
55
106
|
}
|
|
56
107
|
return axios.get(`${APP_BASE_URL}${API_ENDPOINTS.GET_USER_DETAIL}/${email}`, {
|
|
57
|
-
headers: { "X-Api-Key": accessKey },
|
|
108
|
+
headers: { "X-Api-Key": this.#accessKey },
|
|
58
109
|
});
|
|
59
110
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Handle authentication via WebSocket.
|
|
113
|
+
* @param {Object} params
|
|
114
|
+
* @param {string} params.email - The email address of the user.
|
|
115
|
+
* @param {string} params.scanId - The scan ID associated with the user.
|
|
116
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
117
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful authentication.
|
|
118
|
+
* @param {function} [params.onClose] - Optional. Callback function to handle the WebSocket close event.
|
|
119
|
+
* @param {function} [params.onOpen] - Optional. Callback function to handle the WebSocket open event.
|
|
120
|
+
*/
|
|
121
|
+
handleAuthSocket = ({ email, scanId, onError, onSuccess, onClose, onOpen }) => {
|
|
122
|
+
if (checkParameters(email, scanId) === false) {
|
|
63
123
|
throw new Error(REQUIRED_MESSAGE);
|
|
64
124
|
}
|
|
65
125
|
this.#socketRef?.close?.();
|
package/custom.js
CHANGED
|
@@ -2,22 +2,52 @@ const axios = require("axios");
|
|
|
2
2
|
const { API_ENDPOINTS, APP_AUTH_BASE_URL, REQUIRED_MESSAGE } = require("./constants.js");
|
|
3
3
|
const { checkParameters } = require("./utils.js");
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Represents a Custom class for handling custom operations.
|
|
7
|
+
*/
|
|
5
8
|
class Custom {
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The access key used for authentication.
|
|
11
|
+
* @type {string}
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
#accessKey;
|
|
15
|
+
/**
|
|
16
|
+
* Constructs a new instance of the Custom class.
|
|
17
|
+
* @param {string} accessKey - The access key used for authentication.
|
|
18
|
+
*/
|
|
19
|
+
constructor(accessKey) {
|
|
20
|
+
this.#accessKey = accessKey;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves custom customer configuration based on the store URL.
|
|
25
|
+
* @param {string} store_url - The URL of the store.
|
|
26
|
+
* @returns {Promise} - A promise that resolves with the custom customer configuration.
|
|
27
|
+
* @throws {Error} - If required parameters are missing.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
getCustomCustomerConfig = (store_url) => {
|
|
31
|
+
if (checkParameters(store_url) === false) {
|
|
8
32
|
throw new Error(REQUIRED_MESSAGE);
|
|
9
33
|
}
|
|
10
34
|
return axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.CUSTOM_CUSTOMER}`, {
|
|
11
35
|
params: { store_url },
|
|
12
|
-
headers: { "X-Api-Key": accessKey },
|
|
36
|
+
headers: { "X-Api-Key": this.#accessKey },
|
|
13
37
|
});
|
|
14
38
|
};
|
|
15
39
|
|
|
16
|
-
|
|
17
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves the model URL based on the model ID.
|
|
42
|
+
* @param {string} id - The ID of the model.
|
|
43
|
+
* @returns {Promise} - A promise that resolves with the model URL.
|
|
44
|
+
* @throws {Error} - If required parameters are missing.
|
|
45
|
+
*/
|
|
46
|
+
getModelUrl = (id) => {
|
|
47
|
+
if (checkParameters(id) === false) {
|
|
18
48
|
throw new Error(REQUIRED_MESSAGE);
|
|
19
49
|
}
|
|
20
|
-
return axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.MODEL}/${id}`, { headers: { "X-Api-Key": accessKey } });
|
|
50
|
+
return axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.MODEL}/${id}`, { headers: { "X-Api-Key": this.#accessKey } });
|
|
21
51
|
};
|
|
22
52
|
}
|
|
23
53
|
|
package/fileUpload.js
CHANGED
|
@@ -1,22 +1,62 @@
|
|
|
1
1
|
const { REQUIRED_MESSAGE, REQUIRED_MESSAGE_FOR_META_DATA, UPPY_FILE_UPLOAD_ENDPOINT } = require("./constants.js");
|
|
2
2
|
const { checkMetaDataValue, checkParameters, fetchData } = require("./utils.js");
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Class representing a file uploader using Uppy for multipart uploads.
|
|
5
|
+
*/
|
|
4
6
|
class FileUpload {
|
|
7
|
+
/**
|
|
8
|
+
* The Uppy instance.
|
|
9
|
+
* @type {Object}
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
5
12
|
#uppyIns;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reference to the Uppy module.
|
|
16
|
+
* @type {Object}
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
6
19
|
#Uppy;
|
|
7
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Reference to the AwsS3Multipart module.
|
|
22
|
+
* @type {Object}
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
8
25
|
|
|
9
|
-
|
|
26
|
+
#AwsS3Multipart;
|
|
27
|
+
/**
|
|
28
|
+
* The access key used for authentication.
|
|
29
|
+
* @type {string}
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
#accessKey;
|
|
33
|
+
/**
|
|
34
|
+
* Constructs a new instance of the FileUpload class.
|
|
35
|
+
* @param {string} accessKey - The access key used for authentication.
|
|
36
|
+
*/
|
|
37
|
+
constructor(accessKey) {
|
|
10
38
|
this.initializeModules();
|
|
39
|
+
this.#accessKey = accessKey;
|
|
11
40
|
}
|
|
12
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Asynchronously initializes the Uppy and AwsS3Multipart modules.
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
13
45
|
async initializeModules() {
|
|
14
46
|
this.#Uppy = (await import("@uppy/core")).default;
|
|
15
47
|
this.#AwsS3Multipart = (await import("@uppy/aws-s3-multipart")).default;
|
|
16
48
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Uploads a file with optional metadata and scan ID.
|
|
51
|
+
* @param {Object} params - The parameters for file upload.
|
|
52
|
+
* @param {File} params.file - The file to upload.
|
|
53
|
+
* @param {Object} params.objMetaData - Optional. Metadata associated with the file.
|
|
54
|
+
* @param {string} params.scanId - Optional. The ID of the scan.
|
|
55
|
+
* @returns {Promise} - A promise that resolves when the file is uploaded successfully.
|
|
56
|
+
* @throws {Error} - If required parameters are missing or metadata value is invalid.
|
|
57
|
+
*/
|
|
58
|
+
async uploadFile({ file, objMetaData, scanId }) {
|
|
59
|
+
if (checkParameters(file, objMetaData, scanId) === false) {
|
|
20
60
|
throw new Error(REQUIRED_MESSAGE);
|
|
21
61
|
}
|
|
22
62
|
if (checkMetaDataValue(objMetaData) === false) {
|
|
@@ -40,7 +80,7 @@ class FileUpload {
|
|
|
40
80
|
const objectKey = `${scanId}.${file.extension}`;
|
|
41
81
|
return fetchData({
|
|
42
82
|
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_START,
|
|
43
|
-
apiKey: accessKey,
|
|
83
|
+
apiKey: this.#accessKey,
|
|
44
84
|
body: {
|
|
45
85
|
objectKey,
|
|
46
86
|
contentType: file.type,
|
|
@@ -51,7 +91,7 @@ class FileUpload {
|
|
|
51
91
|
completeMultipartUpload: (file, { uploadId, key, parts }) =>
|
|
52
92
|
fetchData({
|
|
53
93
|
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
|
|
54
|
-
apiKey: accessKey,
|
|
94
|
+
apiKey: this.#accessKey,
|
|
55
95
|
body: {
|
|
56
96
|
uploadId,
|
|
57
97
|
objectKey: key,
|
|
@@ -62,7 +102,7 @@ class FileUpload {
|
|
|
62
102
|
signPart: (file, partData) =>
|
|
63
103
|
fetchData({
|
|
64
104
|
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
|
|
65
|
-
apiKey: accessKey,
|
|
105
|
+
apiKey: this.#accessKey,
|
|
66
106
|
body: {
|
|
67
107
|
objectKey: partData.key,
|
|
68
108
|
uploadId: partData.uploadId,
|
|
@@ -72,7 +112,7 @@ class FileUpload {
|
|
|
72
112
|
abortMultipartUpload: (file, { uploadId, key }) =>
|
|
73
113
|
fetchData({
|
|
74
114
|
path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_ABORT,
|
|
75
|
-
apiKey: accessKey,
|
|
115
|
+
apiKey: this.#accessKey,
|
|
76
116
|
body: {
|
|
77
117
|
uploadId,
|
|
78
118
|
objectKey: key,
|
package/index.js
CHANGED
|
@@ -5,17 +5,21 @@ const Measurement = require("./measurement.js");
|
|
|
5
5
|
const PoseDetection = require("./poseDetection.js");
|
|
6
6
|
const TryOn = require("./tryOn.js");
|
|
7
7
|
class Swan {
|
|
8
|
-
|
|
8
|
+
#accessKey;
|
|
9
|
+
constructor(accessKey) {
|
|
10
|
+
this.#accessKey = accessKey;
|
|
11
|
+
}
|
|
12
|
+
auth = new Auth(this.#accessKey);
|
|
9
13
|
|
|
10
|
-
custom = new Custom();
|
|
14
|
+
custom = new Custom(this.#accessKey);
|
|
11
15
|
|
|
12
|
-
fileUpload = new FileUpload();
|
|
16
|
+
fileUpload = new FileUpload(this.#accessKey);
|
|
13
17
|
|
|
14
|
-
measurement = new Measurement();
|
|
18
|
+
measurement = new Measurement(this.#accessKey);
|
|
15
19
|
|
|
16
|
-
poseDetection = new PoseDetection();
|
|
20
|
+
poseDetection = new PoseDetection(this.#accessKey);
|
|
17
21
|
|
|
18
|
-
tryOn = new TryOn();
|
|
22
|
+
tryOn = new TryOn(this.#accessKey);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
module.exports = Swan;
|
package/measurement.js
CHANGED
|
@@ -2,33 +2,71 @@ const axios = require("axios");
|
|
|
2
2
|
const { API_ENDPOINTS, APP_AUTH_BASE_URL, APP_RECOMMENDATION_WEBSOCKET_URL, APP_TRY_ON_WEBSOCKET_URL, REQUIRED_MESSAGE } = require("./constants.js");
|
|
3
3
|
const { checkParameters } = require("./utils.js");
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Class representing measurement-related functionality.
|
|
7
|
+
*/
|
|
5
8
|
class Measurement {
|
|
6
9
|
#tryOnSocketRef = null;
|
|
7
10
|
#measurementSocketRef = null;
|
|
8
11
|
#timerPollingRef = null;
|
|
9
12
|
#timerWaitingRef = null;
|
|
10
13
|
#count = 1;
|
|
14
|
+
#accessKey;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructs a new instance of the Measurement class.
|
|
18
|
+
* @param {string} accessKey - The access key used for authentication.
|
|
19
|
+
*/
|
|
20
|
+
constructor(accessKey) {
|
|
21
|
+
this.#accessKey = accessKey;
|
|
22
|
+
}
|
|
11
23
|
|
|
12
|
-
|
|
13
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Retrieves the measurement status for a given scan ID.
|
|
26
|
+
* @param {string} scanId - The ID of the scan.
|
|
27
|
+
* @returns {Promise} - The axios response promise.
|
|
28
|
+
* @throws {Error} - If the required parameter is missing.
|
|
29
|
+
*/
|
|
30
|
+
getMeasurementStatus(scanId) {
|
|
31
|
+
if (checkParameters(scanId) === false) {
|
|
14
32
|
throw new Error(REQUIRED_MESSAGE);
|
|
15
33
|
}
|
|
16
34
|
const url = `${APP_AUTH_BASE_URL}/measurements?scanId=${scanId}`;
|
|
17
35
|
return axios.get(url, {
|
|
18
|
-
headers: { "X-Api-Key": accessKey },
|
|
36
|
+
headers: { "X-Api-Key": this.#accessKey },
|
|
19
37
|
});
|
|
20
38
|
}
|
|
21
39
|
|
|
22
|
-
|
|
23
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves the try-on measurements for a given scan ID, shop domain, and product name.
|
|
42
|
+
* @param {Object} params - The parameters for the try-on measurements.
|
|
43
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
44
|
+
* @param {string} params.shopDomain - The shop domain.
|
|
45
|
+
* @param {string} params.productName - The product name.
|
|
46
|
+
* @returns {Promise} - The axios response promise.
|
|
47
|
+
* @throws {Error} - If the required parameters are missing.
|
|
48
|
+
*/
|
|
49
|
+
getTryOnMeasurements({ scanId, shopDomain, productName }) {
|
|
50
|
+
if (checkParameters(scanId, shopDomain, productName) === false) {
|
|
24
51
|
throw new Error(REQUIRED_MESSAGE);
|
|
25
52
|
}
|
|
26
53
|
const tryOnUrl = `${APP_AUTH_BASE_URL}${API_ENDPOINTS.TRY_ON_SCAN}/${scanId}/shop/${shopDomain}/product/${productName}`;
|
|
27
|
-
return axios.get(tryOnUrl, { headers: { "X-Api-Key": accessKey } });
|
|
54
|
+
return axios.get(tryOnUrl, { headers: { "X-Api-Key": this.#accessKey } });
|
|
28
55
|
}
|
|
29
56
|
|
|
30
|
-
|
|
31
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Handles the try-on WebSocket connection.
|
|
59
|
+
* @param {Object} params - The parameters for the WebSocket connection.
|
|
60
|
+
* @param {string} params.shopDomain - The shop domain.
|
|
61
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
62
|
+
* @param {string} params.productName - The product name.
|
|
63
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
64
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful messages.
|
|
65
|
+
* @param {function} [params.onClose] - Optional. Callback function to handle WebSocket close event.
|
|
66
|
+
* @param {function} [params.onOpen] - Optional. Callback function to handle WebSocket open event.
|
|
67
|
+
*/
|
|
68
|
+
handleTryOnSocket({ shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen }) {
|
|
69
|
+
if (checkParameters(shopDomain, scanId, productName) === false) {
|
|
32
70
|
throw new Error(REQUIRED_MESSAGE);
|
|
33
71
|
}
|
|
34
72
|
this.#tryOnSocketRef?.close();
|
|
@@ -57,16 +95,24 @@ class Measurement {
|
|
|
57
95
|
};
|
|
58
96
|
}
|
|
59
97
|
|
|
60
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Checks the measurement status and handles polling.
|
|
100
|
+
* @param {Object} params - The parameters for checking measurements.
|
|
101
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
102
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful status check.
|
|
103
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
104
|
+
* @private
|
|
105
|
+
*/
|
|
106
|
+
async #getMeasurementsCheck({ scanId, onSuccess, onError }) {
|
|
61
107
|
try {
|
|
62
|
-
const res = await this.getMeasurementStatus(scanId
|
|
108
|
+
const res = await this.getMeasurementStatus(scanId);
|
|
63
109
|
if (res?.data && res?.data?.[0]?.isMeasured === true) {
|
|
64
110
|
onSuccess?.(res?.data);
|
|
65
111
|
clearInterval(this.#timerPollingRef);
|
|
66
112
|
} else {
|
|
67
113
|
if (this.#count < 8) {
|
|
68
114
|
this.#count++;
|
|
69
|
-
this.#handlePolling({ scanId, onSuccess, onError
|
|
115
|
+
this.#handlePolling({ scanId, onSuccess, onError });
|
|
70
116
|
} else {
|
|
71
117
|
this.#count = 1;
|
|
72
118
|
clearInterval(this.#timerPollingRef);
|
|
@@ -77,30 +123,59 @@ class Measurement {
|
|
|
77
123
|
clearInterval(this.#timerPollingRef);
|
|
78
124
|
onError?.(e);
|
|
79
125
|
}
|
|
80
|
-
}
|
|
126
|
+
}
|
|
81
127
|
|
|
82
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Handles polling for measurements.
|
|
130
|
+
* @param {Object} params - The parameters for polling.
|
|
131
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
132
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful polling.
|
|
133
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
134
|
+
* @private
|
|
135
|
+
*/
|
|
136
|
+
#handlePolling({ scanId, onSuccess, onError }) {
|
|
83
137
|
clearInterval(this.#timerPollingRef);
|
|
84
138
|
this.#timerPollingRef = setTimeout(() => {
|
|
85
|
-
this.#getMeasurementsCheck({ scanId, onSuccess, onError
|
|
139
|
+
this.#getMeasurementsCheck({ scanId, onSuccess, onError });
|
|
86
140
|
}, this.#count * 5000);
|
|
87
141
|
}
|
|
88
142
|
|
|
89
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Disconnects the measurement WebSocket and clears the timeout.
|
|
145
|
+
* @private
|
|
146
|
+
*/
|
|
147
|
+
#disconnectSocket() {
|
|
90
148
|
this.#measurementSocketRef?.close();
|
|
91
149
|
clearTimeout(this.#timerWaitingRef);
|
|
92
|
-
}
|
|
150
|
+
}
|
|
93
151
|
|
|
94
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Handles the timeout for the measurement WebSocket.
|
|
154
|
+
* @param {Object} params - The parameters for handling timeout.
|
|
155
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
156
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful timeout.
|
|
157
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
158
|
+
* @private
|
|
159
|
+
*/
|
|
160
|
+
#handleTimeOut({ scanId, onSuccess, onError }) {
|
|
95
161
|
this.#count = 1;
|
|
96
162
|
this.#timerWaitingRef = setTimeout(() => {
|
|
97
|
-
this.#handlePolling({ scanId, onSuccess, onError
|
|
163
|
+
this.#handlePolling({ scanId, onSuccess, onError });
|
|
98
164
|
this.#disconnectSocket();
|
|
99
165
|
}, 2 * 60000);
|
|
100
|
-
}
|
|
166
|
+
}
|
|
101
167
|
|
|
102
|
-
|
|
103
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Handles the measurement WebSocket connection.
|
|
170
|
+
* @param {Object} params - The parameters for the WebSocket connection.
|
|
171
|
+
* @param {string} params.scanId - The ID of the scan.
|
|
172
|
+
* @param {function} [params.onError] - Optional. Callback function to handle errors.
|
|
173
|
+
* @param {function} [params.onSuccess] - Optional. Callback function to handle successful messages.
|
|
174
|
+
* @param {function} [params.onClose] - Optional. Callback function to handle WebSocket close event.
|
|
175
|
+
* @param {function} [params.onOpen] - Optional. Callback function to handle WebSocket open event.
|
|
176
|
+
*/
|
|
177
|
+
handleMeasurementSocket({ scanId, onError, onSuccess, onClose, onOpen }) {
|
|
178
|
+
if (checkParameters(scanId) === false) {
|
|
104
179
|
throw new Error(REQUIRED_MESSAGE);
|
|
105
180
|
}
|
|
106
181
|
setTimeout(() => {
|
|
@@ -109,7 +184,7 @@ class Measurement {
|
|
|
109
184
|
this.#measurementSocketRef = new WebSocket(url);
|
|
110
185
|
this.#measurementSocketRef.onopen = () => {
|
|
111
186
|
onOpen?.();
|
|
112
|
-
this.#handleTimeOut({ scanId, onSuccess, onError
|
|
187
|
+
this.#handleTimeOut({ scanId, onSuccess, onError });
|
|
113
188
|
};
|
|
114
189
|
|
|
115
190
|
this.#measurementSocketRef.onmessage = (event) => {
|
|
@@ -130,7 +205,7 @@ class Measurement {
|
|
|
130
205
|
onError?.(event);
|
|
131
206
|
};
|
|
132
207
|
}, 5000);
|
|
133
|
-
}
|
|
208
|
+
}
|
|
134
209
|
}
|
|
135
210
|
|
|
136
211
|
module.exports = Measurement;
|
package/package.json
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swan-admin/swan-ai-measurements",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.55",
|
|
4
4
|
"description": "provides ai measurement suggestion",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "types/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.js",
|
|
9
|
+
"auth.js",
|
|
10
|
+
"constant.js",
|
|
11
|
+
"custom.js",
|
|
12
|
+
"fileUpload.js",
|
|
13
|
+
"measurement.js",
|
|
14
|
+
"poseDetection.js",
|
|
15
|
+
"tryOn.js",
|
|
16
|
+
"utils.js",
|
|
17
|
+
"types/"
|
|
18
|
+
],
|
|
6
19
|
"dependencies": {
|
|
20
|
+
"@types/axios": "^0.14.0",
|
|
7
21
|
"@uppy/aws-s3-multipart": "^3.10.2",
|
|
8
22
|
"@uppy/core": "^3.9.3",
|
|
9
23
|
"axios": "^1.6.7",
|
|
10
24
|
"dotenv": "^16.4.5",
|
|
25
|
+
"socket.io": "^4.7.5",
|
|
11
26
|
"socket.io-client": "^4.7.5"
|
|
12
27
|
},
|
|
13
28
|
"devDependencies": {
|
|
14
|
-
"nodemon": "^3.1.0"
|
|
29
|
+
"nodemon": "^3.1.0",
|
|
30
|
+
"typescript": "^5.4.5"
|
|
15
31
|
},
|
|
16
32
|
"scripts": {
|
|
17
33
|
"start": "nodemon index.js",
|
|
18
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
34
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
35
|
+
"build:types": "tsc"
|
|
19
36
|
},
|
|
20
37
|
"repository": {
|
|
21
38
|
"type": "git",
|
package/poseDetection.js
CHANGED
|
@@ -1,29 +1,45 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const
|
|
1
|
+
const { APP_POSE_DETECTION_WEBSOCKET_URL, REQUIRED_MESSAGE } = require("./constants.js");
|
|
2
|
+
const io = require("socket.io");
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Class representing pose detection functionality.
|
|
6
|
+
*/
|
|
4
7
|
class PoseDetection {
|
|
5
8
|
#socketRef = null;
|
|
9
|
+
#accessKey;
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new instance of the PoseDetection class.
|
|
13
|
+
* @param {string} accessKey - The access key used for authentication.
|
|
14
|
+
*/
|
|
15
|
+
constructor(accessKey) {
|
|
16
|
+
this.#accessKey = accessKey;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Connects to the pose detection WebSocket server.
|
|
21
|
+
* @returns {Promise<string>} - A promise that resolves with the socket ID on successful connection.
|
|
22
|
+
*/
|
|
23
|
+
connect() {
|
|
11
24
|
return new Promise((resolve, reject) => {
|
|
12
|
-
this.#socketRef = io.connect(
|
|
25
|
+
this.#socketRef = io.connect(APP_POSE_DETECTION_WEBSOCKET_URL);
|
|
13
26
|
this.#socketRef?.on("connect", () => {
|
|
14
|
-
resolve(this.#socketRef.id);
|
|
27
|
+
resolve(this.#socketRef.id);
|
|
15
28
|
});
|
|
16
29
|
this.#socketRef?.on("connect_error", (err) => reject(err));
|
|
17
30
|
});
|
|
18
31
|
}
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Emits a video frame to the pose detection server.
|
|
35
|
+
* @param {Object} params - The parameters for emitting the video frame.
|
|
36
|
+
* @param {string} params.image - The image data.
|
|
37
|
+
* @param {string} params.scanId - The unique scan ID.
|
|
38
|
+
* @throws {Error} - If the socket is not connected.
|
|
39
|
+
*/
|
|
40
|
+
videoEmit({ image, scanId }) {
|
|
25
41
|
if (!this.#socketRef) {
|
|
26
|
-
throw new Error("
|
|
42
|
+
throw new Error("Socket is not connected");
|
|
27
43
|
}
|
|
28
44
|
this.#socketRef.emit("video", {
|
|
29
45
|
image,
|
|
@@ -31,22 +47,31 @@ class PoseDetection {
|
|
|
31
47
|
});
|
|
32
48
|
}
|
|
33
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Disconnects from the pose detection WebSocket server.
|
|
52
|
+
*/
|
|
34
53
|
disconnect() {
|
|
35
54
|
this.#socketRef?.disconnect?.();
|
|
36
55
|
}
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Registers a callback function to handle pose status updates.
|
|
59
|
+
* @param {function} callBack - The callback function to handle pose status updates.
|
|
60
|
+
* @throws {Error} - If the socket is not connected.
|
|
61
|
+
*/
|
|
62
|
+
poseStatus(callBack) {
|
|
42
63
|
if (!this.#socketRef) {
|
|
43
|
-
throw new Error("
|
|
64
|
+
throw new Error("Socket is not connected");
|
|
44
65
|
}
|
|
45
66
|
this.#socketRef.on("pose_status", (data) => {
|
|
46
67
|
callBack?.(data);
|
|
47
68
|
});
|
|
48
69
|
}
|
|
49
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Checks if the socket is connected.
|
|
73
|
+
* @returns {boolean} - True if the socket is connected, false otherwise.
|
|
74
|
+
*/
|
|
50
75
|
connected() {
|
|
51
76
|
return !!this.#socketRef?.connected;
|
|
52
77
|
}
|