@swan-admin/swan-ai-measurements 1.0.28 → 1.0.30

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 CHANGED
@@ -1,60 +1,93 @@
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
- socketRef?.close?.();
36
-
37
- socketRef = new WebSocket(APP_AUTH_WEBSOCKET_URL);
38
- const detailObj = {
39
- email,
40
- scanId,
41
- };
42
-
43
- socketRef.onopen = () => {
44
- onOpen?.();
45
- socketRef.send(JSON.stringify(detailObj));
46
- };
47
-
48
- socketRef.onmessage = (event) => {
49
- const data = JSON.parse(event.data);
50
- onSuccess?.(data);
51
- };
52
-
53
- socketRef.onclose = () => {
54
- onClose?.();
55
- };
56
-
57
- socketRef.onerror = (event) => {
58
- onError?.(event);
59
- };
60
- };
1
+ import axios from "axios";
2
+ import {
3
+ API_ENDPOINTS,
4
+ APP_AUTH_BASE_URL,
5
+ APP_AUTH_WEBSOCKET_URL,
6
+ APP_BASE_URL,
7
+ REQUIRED_MESSAGE,
8
+ } from "./constants.js";
9
+ import { checkParameters } from "./utils.js";
10
+ let socketRef;
11
+
12
+ class Auth {
13
+ static accessKey;
14
+ constructor(key) {
15
+ Auth.accessKey = key;
16
+ }
17
+ registerUser({ email, appVerifyUrl, gender, height, username }) {
18
+ if (checkParameters(email, appVerifyUrl) === false) {
19
+ throw new Error(REQUIRED_MESSAGE);
20
+ }
21
+ let body = {
22
+ username,
23
+ email,
24
+ appVerifyUrl,
25
+ };
26
+ if (gender && height) {
27
+ body = { ...body, attributes: { gender, height } };
28
+ }
29
+ return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.REGISTER_USER}`, body);
30
+ }
31
+
32
+ verifyToken = (token) => {
33
+ if (!token) {
34
+ throw new Error(REQUIRED_MESSAGE);
35
+ }
36
+ return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.VERIFY_USER}`, null, {
37
+ params: { token },
38
+ });
39
+ };
40
+
41
+ addUser = ({ scanId, email, name, height, gender, offsetMarketingConsent }) => {
42
+ if (checkParameters(scanId, email, height, gender) === false) {
43
+ throw new Error(REQUIRED_MESSAGE);
44
+ }
45
+ return axios.post(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.ADD_USER}`, {
46
+ scan_id: scanId,
47
+ email,
48
+ name,
49
+ offsetMarketingConsent,
50
+ attributes: JSON.stringify({ height, gender }),
51
+ });
52
+ };
53
+
54
+ getUserDetail = (email) => {
55
+ if (!email) {
56
+ throw new Error(REQUIRED_MESSAGE);
57
+ }
58
+ return axios.get(`${APP_BASE_URL}${API_ENDPOINTS.GET_USER_DETAIL}/${email}`);
59
+ };
60
+
61
+ handleAuthSocket = ({ email, scanId, onError, onSuccess, onClose, onOpen }) => {
62
+ if (checkParameters(email, scanId) === false) {
63
+ throw new Error(REQUIRED_MESSAGE);
64
+ }
65
+ socketRef?.close?.();
66
+
67
+ socketRef = new WebSocket(APP_AUTH_WEBSOCKET_URL);
68
+ const detailObj = {
69
+ email,
70
+ scanId,
71
+ };
72
+
73
+ socketRef.onopen = () => {
74
+ socketRef.send(JSON.stringify(detailObj));
75
+ onOpen?.();
76
+ };
77
+
78
+ socketRef.onmessage = (event) => {
79
+ const data = JSON.parse(event.data);
80
+ onSuccess?.(data);
81
+ };
82
+
83
+ socketRef.onclose = () => {
84
+ onClose?.();
85
+ };
86
+
87
+ socketRef.onerror = (event) => {
88
+ onError?.(event);
89
+ };
90
+ };
91
+ }
92
+
93
+ export default Auth;
package/constants.js CHANGED
@@ -23,3 +23,5 @@ export const API_ENDPOINTS = {
23
23
  MODEL: "/model",
24
24
  TRY_ON: "/tryon/scan",
25
25
  };
26
+
27
+ export const REQUIRED_MESSAGE = "Please verify required parameters";
package/custom.js CHANGED
@@ -1,7 +1,22 @@
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}`);
1
+ import axios from "axios";
2
+ import { API_ENDPOINTS, APP_AUTH_BASE_URL, REQUIRED_MESSAGE } from "./constants.js";
3
+
4
+ export default class Custom {
5
+ static accessKey;
6
+ constructor(key) {
7
+ Custom.accessKey = key;
8
+ }
9
+ getCustomCustomerConfig = (store_url) => {
10
+ if (!store_url) {
11
+ throw new Error(REQUIRED_MESSAGE);
12
+ }
13
+ return axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.CUSTOM_CUSTOMER}`, { params: { store_url } });
14
+ };
15
+
16
+ getModelUrl = (id) => {
17
+ if (!id) {
18
+ throw new Error(REQUIRED_MESSAGE);
19
+ }
20
+ return axios.get(`${APP_AUTH_BASE_URL}${API_ENDPOINTS.MODEL}/${id}`);
21
+ };
22
+ }
package/fileUpload.js CHANGED
@@ -1,81 +1,88 @@
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
- import { fetchData } from "./utils.js";
5
-
6
- function uploadFile({ file, objMetaData, scanId, accessKey }) {
7
- return new Promise((resolve, reject) => {
8
- const uppyIns = new Uppy({ autoProceed: true });
9
- uppyIns.use(AwsS3Multipart, {
10
- limit: 10,
11
- retryDelays: [0, 1000, 3000, 5000],
12
- getChunkSize: () => 5 * 1024 * 1024,
13
- createMultipartUpload: (file) => {
14
- const objectKey = `${scanId}.${file.extension}`;
15
- return fetchData({
16
- path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_START,
17
- apiKey: FILE_UPLOAD_KEY,
18
- body: {
19
- objectKey,
20
- contentType: file.type,
21
- objectMetadata: objMetaData,
22
- },
23
- });
24
- },
25
- completeMultipartUpload: (file, { uploadId, key, parts }) =>
26
- fetchData({
27
- path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
28
- apiKey: FILE_UPLOAD_KEY,
29
- body: {
30
- uploadId,
31
- objectKey: key,
32
- parts,
33
- originalFileName: file.name,
34
- },
35
- }),
36
-
37
- signPart: (file, partData) =>
38
- fetchData({
39
- path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
40
- apiKey: FILE_UPLOAD_KEY,
41
- body: {
42
- objectKey: partData.key,
43
- uploadId: partData.uploadId,
44
- partNumber: partData.partNumber,
45
- },
46
- }),
47
-
48
- abortMultipartUpload: (file, { uploadId, key }) =>
49
- fetchData({
50
- path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_ABORT,
51
- apiKey: FILE_UPLOAD_KEY,
52
- body: {
53
- uploadId,
54
- objectKey: key,
55
- originalFileName: file.name,
56
- },
57
- }),
58
- });
59
-
60
- uppyIns.addFile({
61
- source: "manual",
62
- name: file.name,
63
- type: file.type,
64
- data: file,
65
- });
66
-
67
- uppyIns.on("upload-error", (file, error, response) => {
68
- reject(error);
69
- });
70
- uppyIns.on("upload-success", () => {
71
- resolve({ message: "file uploaded successfully" });
72
- });
73
- uppyIns.on("complete", (result) => {
74
- if (uppyIns) {
75
- uppyIns.close();
76
- }
77
- });
78
- });
79
- }
80
-
81
- export default uploadFile;
1
+ import AwsS3Multipart from "@uppy/aws-s3-multipart";
2
+ import Uppy from "@uppy/core";
3
+ import { FILE_UPLOAD_KEY, REQUIRED_MESSAGE, UPPY_FILE_UPLOAD_ENDPOINT } from "./constants.js";
4
+ import { checkParameters, fetchData } from "./utils.js";
5
+
6
+ export default class FileUpload {
7
+ static accessKey;
8
+ constructor(key) {
9
+ FileUpload.accessKey = key;
10
+ }
11
+ uploadFile({ file, objMetaData, scanId }) {
12
+ if (checkParameters(file, objMetaData, scanId) === false) {
13
+ throw new Error(REQUIRED_MESSAGE);
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ const uppyIns = new Uppy({ autoProceed: true });
17
+ uppyIns.use(AwsS3Multipart, {
18
+ limit: 10,
19
+ retryDelays: [0, 1000, 3000, 5000],
20
+ getChunkSize: () => 5 * 1024 * 1024,
21
+ createMultipartUpload: (file) => {
22
+ const objectKey = `${scanId}.${file.extension}`;
23
+ return fetchData({
24
+ path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_START,
25
+ apiKey: FILE_UPLOAD_KEY,
26
+ body: {
27
+ objectKey,
28
+ contentType: file.type,
29
+ objectMetadata: objMetaData,
30
+ },
31
+ });
32
+ },
33
+ completeMultipartUpload: (file, { uploadId, key, parts }) =>
34
+ fetchData({
35
+ path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_COMPLETE,
36
+ apiKey: FILE_UPLOAD_KEY,
37
+ body: {
38
+ uploadId,
39
+ objectKey: key,
40
+ parts,
41
+ originalFileName: file.name,
42
+ },
43
+ }),
44
+
45
+ signPart: (file, partData) =>
46
+ fetchData({
47
+ path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_SIGN_PART,
48
+ apiKey: FILE_UPLOAD_KEY,
49
+ body: {
50
+ objectKey: partData.key,
51
+ uploadId: partData.uploadId,
52
+ partNumber: partData.partNumber,
53
+ },
54
+ }),
55
+
56
+ abortMultipartUpload: (file, { uploadId, key }) =>
57
+ fetchData({
58
+ path: UPPY_FILE_UPLOAD_ENDPOINT.UPLOAD_ABORT,
59
+ apiKey: FILE_UPLOAD_KEY,
60
+ body: {
61
+ uploadId,
62
+ objectKey: key,
63
+ originalFileName: file.name,
64
+ },
65
+ }),
66
+ });
67
+
68
+ uppyIns.addFile({
69
+ source: "manual",
70
+ name: file.name,
71
+ type: file.type,
72
+ data: file,
73
+ });
74
+
75
+ uppyIns.on("upload-error", (file, error, response) => {
76
+ reject(error);
77
+ });
78
+ uppyIns.on("upload-success", () => {
79
+ resolve({ message: "file uploaded successfully" });
80
+ });
81
+ uppyIns.on("complete", (result) => {
82
+ if (uppyIns) {
83
+ uppyIns.close();
84
+ }
85
+ });
86
+ });
87
+ }
88
+ }
package/index.js CHANGED
@@ -1,77 +1,24 @@
1
- import { addUser, getUserDetail, handleAuthSocket, registerUser, verifyToken } from "./auth.js";
2
- import { getCustomCustomerConfig } from "./custom.js";
3
- import uploadFile from "./fileUpload.js";
4
- import {
5
- getMeasurementStatus,
6
- getTryOnMeasurements,
7
- handleMeasurementSocket,
8
- handleTryOnSocket,
9
- } from "./measurement.js";
10
- import { handlePoseDetectionSocket } from "./poseDetection.js";
11
- export default class Swan {
12
- constructor(key) {
13
- if (key !== 9876543210) {
14
- throw new Error("wrong access key");
15
- }
16
- this.accessKey = key;
17
- }
18
-
19
- registerUser({ email, appVerifyUrl, gender, height, username }) {
20
- return registerUser({ email, appVerifyUrl, gender, height, username, accessKey: this.accessKey });
21
- }
22
-
23
- verifyToken(token) {
24
- return verifyToken(token, this.accessKey);
25
- }
26
-
27
- addUser({ scanId, email, name, height, gender, offsetMarketingConsent }) {
28
- return addUser({ scanId, email, name, height, gender, offsetMarketingConsent, accessKey: this.accessKey });
29
- }
30
-
31
- getUserDetail(email) {
32
- return getUserDetail(email, this.accessKey);
33
- }
34
-
35
- uploadFile({ file, objMetaData, scanId }) {
36
- return uploadFile({ file, objMetaData, scanId, accessKey: this.accessKey });
37
- }
38
-
39
- getModelUrl(id) {
40
- return getModelUrl(id, this.accessKey);
41
- }
42
-
43
- getCustomCustomerConfig(storeUrl) {
44
- return getCustomCustomerConfig(storeUrl, this.accessKey);
45
- }
46
-
47
- getMeasurementStatus(scanId) {
48
- return getMeasurementStatus(scanId, this.accessKey);
49
- }
50
-
51
- getTryOnMeasurements({ scanId, shopDomain, productName }) {
52
- return getTryOnMeasurements({ scanId, shopDomain, productName, accessKey: this.accessKey });
53
- }
54
-
55
- handleTryOnSocket({ shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen }) {
56
- return handleTryOnSocket({
57
- shopDomain,
58
- scanId,
59
- productName,
60
- accessKey: this.accessKey,
61
- onError,
62
- onSuccess,
63
- onClose,
64
- onOpen,
65
- });
66
- }
67
-
68
- handleMeasurementSocket({ scanId, onError, onSuccess, onClose, onOpen }) {
69
- return handleMeasurementSocket({ scanId, accessKey: this.accessKey, onError, onSuccess, onClose, onOpen });
70
- }
71
-
72
- handleAuthSocket({ email, scanId, onError, onSuccess, onClose, onOpen }) {
73
- return handleAuthSocket({ email, scanId, accessKey: this.accessKey, onError, onSuccess, onClose, onOpen });
74
- }
75
-
76
- handlePoseDetectionSocket = handlePoseDetectionSocket;
77
- }
1
+ import Auth from "./auth.js";
2
+ import Custom from "./custom.js";
3
+ import FileUpload from "./fileUpload.js";
4
+ import Measurement from "./measurement.js";
5
+ import PoseDetection from "./poseDetection.js";
6
+ export default class Swan {
7
+ static accessKey;
8
+ constructor(key) {
9
+ if (key !== 9876543210) {
10
+ throw new Error("wrong access key");
11
+ }
12
+ Swan.accessKey = key;
13
+ }
14
+
15
+ auth = new Auth(Swan.accessKey);
16
+
17
+ custom = new Custom(Swan.accessKey);
18
+
19
+ fileUpload = new FileUpload(Swan.accessKey);
20
+
21
+ measurement = new Measurement(Swan.accessKey);
22
+
23
+ poseDetection = new PoseDetection(Swan.accessKey);
24
+ }
package/measurement.js CHANGED
@@ -1,136 +1,134 @@
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
- } from "./constants.js";
9
-
10
- let tryOnSocketRef;
11
- let measurementSocketRef;
12
- let timerPollingRef;
13
- let timerWaitingRef;
14
-
15
- export const getMeasurementStatus = (scanId, accessKey) => {
16
- const url = `${APP_AUTH_BASE_URL}/measurements?scanId=${scanId}`;
17
- return axios.get(url, {
18
- headers: { "X-Api-Key": FILE_UPLOAD_KEY },
19
- });
20
- };
21
-
22
- export const getTryOnMeasurements = ({ scanId, shopDomain, productName, accessKey }) => {
23
- const tryOnUrl = `${APP_AUTH_BASE_URL}${API_ENDPOINTS.TRY_ON}/${scanId}/shop/${shopDomain}/product/${productName}`;
24
- return axios.get(tryOnUrl);
25
- };
26
-
27
- export const handleTryOnSocket = ({
28
- shopDomain,
29
- scanId,
30
- productName,
31
- accessKey,
32
- onError,
33
- onSuccess,
34
- onClose,
35
- onOpen,
36
- }) => {
37
- if (tryOnSocketRef) {
38
- tryOnSocketRef.close();
39
- }
40
- const url = `${APP_TRY_ON_WEBSOCKET_URL}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
41
- tryOnSocketRef = new WebSocket(url);
42
-
43
- tryOnSocketRef.onopen = () => {
44
- if (onOpen) {
45
- onOpen();
46
- }
47
- };
48
-
49
- tryOnSocketRef.onmessage = (event) => {
50
- const data = JSON.parse(event.data);
51
- if (data?.tryOnProcessStatus === "available") {
52
- if (onSuccess) {
53
- onSuccess(data);
54
- }
55
- } else {
56
- if (onError) {
57
- onError({ message: "failed to get image urls" });
58
- }
59
- }
60
- };
61
-
62
- tryOnSocketRef.onclose = () => {
63
- if (onClose) {
64
- onClose();
65
- }
66
- };
67
-
68
- tryOnSocketRef.onerror = (event) => {
69
- if (onError) {
70
- onError(event);
71
- }
72
- };
73
- };
74
-
75
- const getMeasurementsCheck = async (onSuccess, onError, scanId, accessKey) => {
76
- try {
77
- const res = await getMeasurementStatus(scanId, accessKey);
78
- if (res?.data && res?.data?.[0]?.isMeasured === true) {
79
- onSuccess?.(res?.data);
80
- clearInterval(timerPollingRef);
81
- }
82
- } catch (e) {
83
- clearInterval(timerPollingRef);
84
- onError?.(e);
85
- }
86
- };
87
-
88
- const handlePolling = (onSuccess, onError) => {
89
- clearInterval(timerPollingRef);
90
- timerPollingRef = setInterval(() => {
91
- getMeasurementsCheck(onSuccess, onError);
92
- }, 5000);
93
- };
94
-
95
- const disconnectSocket = () => {
96
- if (measurementSocketRef) {
97
- measurementSocketRef.close();
98
- clearTimeout(timerWaitingRef);
99
- }
100
- };
101
-
102
- const handleTimeOut = (onSuccess, onError) => {
103
- timerWaitingRef = setTimeout(() => {
104
- handlePolling(onSuccess, onError);
105
- disconnectSocket();
106
- }, 2 * 60000);
107
- };
108
-
109
- export const handleMeasurementSocket = ({ scanId, accessKey, onError, onSuccess, onClose, onOpen }) => {
110
- disconnectSocket();
111
- const url = `${APP_RECOMMENDATION_WEBSOCKET_URL}?scanId=${scanId}`;
112
- measurementSocketRef = new WebSocket(url);
113
-
114
- measurementSocketRef.onopen = () => {
115
- onOpen?.();
116
- handleTimeOut(onSuccess, onError);
117
- };
118
-
119
- measurementSocketRef.onmessage = (event) => {
120
- const data = JSON.parse(event.data);
121
- if (data?.code === 200 && data?.scanStatus === "success") {
122
- onSuccess?.(data);
123
- } else {
124
- onError?.(data);
125
- }
126
- clearTimeout(timerWaitingRef);
127
- };
128
-
129
- measurementSocketRef.onclose = () => {
130
- onClose?.();
131
- };
132
-
133
- measurementSocketRef.onerror = (event) => {
134
- onError?.(event);
135
- };
136
- };
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
+ REQUIRED_MESSAGE,
9
+ } from "./constants.js";
10
+ import { checkParameters } from "./utils.js";
11
+
12
+ export default class Measurement {
13
+ static accessKey;
14
+ constructor(key) {
15
+ Measurement.accessKey = key;
16
+ }
17
+ static tryOnSocketRef = null;
18
+ static measurementSocketRef = null;
19
+ static timerPollingRef = null;
20
+ static timerWaitingRef = null;
21
+
22
+ getMeasurementStatus(scanId) {
23
+ if (!scanId) {
24
+ throw new Error(REQUIRED_MESSAGE);
25
+ }
26
+ const url = `${APP_AUTH_BASE_URL}/measurements?scanId=${scanId}`;
27
+ return axios.get(url, {
28
+ headers: { "X-Api-Key": FILE_UPLOAD_KEY },
29
+ });
30
+ }
31
+
32
+ getTryOnMeasurements({ scanId, shopDomain, productName }) {
33
+ if (checkParameters(scanId, shopDomain, productName) === false) {
34
+ throw new Error(REQUIRED_MESSAGE);
35
+ }
36
+ const tryOnUrl = `${APP_AUTH_BASE_URL}${API_ENDPOINTS.TRY_ON}/${scanId}/shop/${shopDomain}/product/${productName}`;
37
+ return axios.get(tryOnUrl);
38
+ }
39
+
40
+ handleTryOnSocket({ shopDomain, scanId, productName, onError, onSuccess, onClose, onOpen }) {
41
+ if (checkParameters(shopDomain, scanId, productName) === false) {
42
+ throw new Error(REQUIRED_MESSAGE);
43
+ }
44
+ Measurement.tryOnSocketRef?.close();
45
+
46
+ const url = `${APP_TRY_ON_WEBSOCKET_URL}/develop?store_url=${shopDomain}&product_name=${productName}&scan_id=${scanId}`;
47
+ Measurement.tryOnSocketRef = new WebSocket(url);
48
+
49
+ Measurement.tryOnSocketRef.onopen = () => {
50
+ onOpen?.();
51
+ };
52
+
53
+ Measurement.tryOnSocketRef.onmessage = (event) => {
54
+ const data = JSON.parse(event.data);
55
+ if (data?.tryOnProcessStatus === "available") {
56
+ onSuccess?.(data);
57
+ } else {
58
+ onError?.({ message: "failed to get image urls" });
59
+ }
60
+ };
61
+
62
+ Measurement.tryOnSocketRef.onclose = () => {
63
+ onClose?.();
64
+ };
65
+
66
+ Measurement.tryOnSocketRef.onerror = (event) => {
67
+ onError?.(event);
68
+ };
69
+ }
70
+
71
+ static getMeasurementsCheck = async (onSuccess, onError, scanId) => {
72
+ try {
73
+ const res = await getMeasurementStatus(scanId);
74
+ if (res?.data && res?.data?.[0]?.isMeasured === true) {
75
+ onSuccess?.(res?.data);
76
+ clearInterval(Measurement.timerPollingRef);
77
+ }
78
+ } catch (e) {
79
+ clearInterval(Measurement.timerPollingRef);
80
+ onError?.(e);
81
+ }
82
+ };
83
+
84
+ static handlePolling(onSuccess, onError) {
85
+ clearInterval(Measurement.timerPollingRef);
86
+ Measurement.timerPollingRef = setInterval(() => {
87
+ Measurement.getMeasurementsCheck(onSuccess, onError);
88
+ }, 5000);
89
+ }
90
+
91
+ static disconnectSocket = () => {
92
+ Measurement.measurementSocketRef?.close();
93
+ clearTimeout(Measurement.timerWaitingRef);
94
+ };
95
+
96
+ static handleTimeOut = (onSuccess, onError) => {
97
+ Measurement.timerWaitingRef = setTimeout(() => {
98
+ Measurement.handlePolling(onSuccess, onError);
99
+ disconnectSocket();
100
+ }, 2 * 60000);
101
+ };
102
+
103
+ handleMeasurementSocket = ({ scanId, onError, onSuccess, onClose, onOpen }) => {
104
+ if (!scanId) {
105
+ throw new Error(REQUIRED_MESSAGE);
106
+ }
107
+ Measurement.disconnectSocket();
108
+ const url = `${APP_RECOMMENDATION_WEBSOCKET_URL}?scanId=${scanId}`;
109
+ Measurement.measurementSocketRef = new WebSocket(url);
110
+
111
+ Measurement.measurementSocketRef.onopen = () => {
112
+ onOpen?.();
113
+ Measurement.handleTimeOut(onSuccess, onError);
114
+ };
115
+
116
+ Measurement.measurementSocketRef.onmessage = (event) => {
117
+ const data = JSON.parse(event.data);
118
+ if (data?.code === 200 && data?.scanStatus === "success") {
119
+ onSuccess?.(data);
120
+ } else {
121
+ onError?.(data);
122
+ }
123
+ clearTimeout(Measurement.timerWaitingRef);
124
+ };
125
+
126
+ Measurement.measurementSocketRef.onclose = () => {
127
+ onClose?.();
128
+ };
129
+
130
+ Measurement.measurementSocketRef.onerror = (event) => {
131
+ onError?.(event);
132
+ };
133
+ };
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-admin/swan-ai-measurements",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "provides ai measurement suggestion",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/poseDetection.js CHANGED
@@ -1,44 +1,46 @@
1
- import { APP_POSE_DETECTION_WEbSOCKET_URL } from "./constants.js";
2
- import { io } from "socket.io-client";
3
- let socket;
4
-
5
- export function handlePoseDetectionSocket() {
6
- return {
7
- connect: function () {
8
- return new Promise((resolve, reject) => {
9
- socket = io.connect(APP_POSE_DETECTION_WEbSOCKET_URL);
10
- socket?.on("connect", () => {
11
- resolve(socket.id); // "G5p5..."
12
- });
13
- socket?.on("connect_error", (err) => reject(err));
14
- });
15
- },
16
-
17
- videoEmit: function ({ image, scanId }) {
18
- if (!socket) {
19
- throw new Error("socket is not connected");
20
- }
21
- socket.emit("video", {
22
- image,
23
- user_unique_key: scanId,
24
- });
25
- },
26
-
27
- disconnect: function () {
28
- socket?.disconnect?.();
29
- },
30
-
31
- poseStatus: function (callBack) {
32
- if (!socket) {
33
- throw new Error("socket is not connected");
34
- }
35
- socket.on("pose_status", (data) => {
36
- callBack(data);
37
- });
38
- },
39
-
40
- connected: function () {
41
- return !!socket?.connected;
42
- },
43
- };
44
- }
1
+ import { APP_POSE_DETECTION_WEbSOCKET_URL } from "./constants.js";
2
+ import { io } from "socket.io-client";
3
+
4
+ export default class PoseDetection {
5
+ static socket = null;
6
+ static accessKey;
7
+ constructor(key) {
8
+ PoseDetection.accessKey = key;
9
+ }
10
+ connect() {
11
+ return new Promise((resolve, reject) => {
12
+ PoseDetection.socket = io.connect(APP_POSE_DETECTION_WEbSOCKET_URL);
13
+ PoseDetection.socket?.on("connect", () => {
14
+ resolve(PoseDetection.socket.id); // "G5p5..."
15
+ });
16
+ PoseDetection.socket?.on("connect_error", (err) => reject(err));
17
+ });
18
+ }
19
+
20
+ videoEmit({ image, scanId }) {
21
+ if (!PoseDetection.socket) {
22
+ throw new Error("socket is not connected");
23
+ }
24
+ PoseDetection.socket.emit("video", {
25
+ image,
26
+ user_unique_key: scanId,
27
+ });
28
+ }
29
+
30
+ disconnect() {
31
+ PoseDetection.socket?.disconnect?.();
32
+ }
33
+
34
+ poseStatus(callBack) {
35
+ if (!PoseDetection.socket) {
36
+ throw new Error("socket is not connected");
37
+ }
38
+ PoseDetection.socket.on("pose_status", (data) => {
39
+ callBack?.(data);
40
+ });
41
+ }
42
+
43
+ connected() {
44
+ return !!PoseDetection.socket?.connected;
45
+ }
46
+ }
package/utils.js CHANGED
@@ -21,3 +21,12 @@ export async function fetchData({
21
21
  return {};
22
22
  }
23
23
  }
24
+
25
+ export const checkParameters = (...args) => {
26
+ for (const element of args) {
27
+ if (!element) {
28
+ return false;
29
+ }
30
+ }
31
+ return true;
32
+ };