sizebay-core-sdk 1.0.0 → 1.0.1
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/CHANGELOG.md +7 -0
- package/README.md +82 -15
- package/dist/sizebay-core-sdk.es.js +52 -52
- package/dist/sizebay-core-sdk.umd.js +1 -1
- package/dist/types/src/modules/ai-image-service.d.ts +2 -2
- package/dist/types/src/types/ai-image-service.types.d.ts +10 -16
- package/package.json +1 -1
- package/src/config/endpoints.ts +4 -4
- package/src/modules/ai-image-service.ts +6 -6
- package/src/modules/tracker.ts +3 -4
- package/src/types/ai-image-service.types.ts +11 -16
- package/test/modules/ai-image-service.test.ts +33 -58
- package/test/modules/tracker.test.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.0.1](https://github.com/sizebay/events-sdk/compare/v1.0.0...v1.0.1) (2025-04-01)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* **ai-image-service:** correct endpoint configuration ([cc7c8f4](https://github.com/sizebay/events-sdk/commit/cc7c8f41b4961e6fdca62d87ef3de152351064cd))
|
|
6
|
+
* **tracker:** update URL construction logic ([7be913c](https://github.com/sizebay/events-sdk/commit/7be913c8b81dfdd1543d4d843a83753955f5b83a))
|
|
7
|
+
|
|
1
8
|
## 1.0.0 (2025-03-31)
|
|
2
9
|
|
|
3
10
|
### Features
|
package/README.md
CHANGED
|
@@ -75,31 +75,45 @@ async function trackEvent() {
|
|
|
75
75
|
trackEvent();
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
## AI Image Service Module
|
|
79
79
|
|
|
80
|
-
###
|
|
80
|
+
### `getSimilarProducts(params: GetSimilarProductsParams): Promise<GetSimilarProductsResponse>`
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
Fetches similar products based on the provided image parameters.
|
|
82
|
+
Fetches similar products based on the given parameters, returning a paginated result.
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
#### Parameters
|
|
86
85
|
|
|
87
|
-
| Parameter
|
|
88
|
-
|
|
89
|
-
| `
|
|
86
|
+
| Parameter | Type | Required | Description |
|
|
87
|
+
|------------------|--------------------------------|:--------:|------------------------------------------------------------------------------------------|
|
|
88
|
+
| `tenantId` | `number` | **Yes** | The tenant ID that initiated the request. |
|
|
89
|
+
| `collectionName` | `string` | **Yes** | The name of the relevant product collection. |
|
|
90
|
+
| `sessionId` | `number` | **Yes** | The session ID, typically required for internal event tracking. |
|
|
91
|
+
| `permalink` | `string` | **Yes** | A permanent link representing the main product. |
|
|
92
|
+
| `page` | `number` (optional) | No | Page number for pagination. |
|
|
93
|
+
| `perPage` | `number` (optional) | No | Number of items per page. |
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
#### Returns
|
|
96
|
+
|
|
97
|
+
**`Promise<GetSimilarProductsResponse>`**
|
|
98
|
+
An object containing:
|
|
99
|
+
|
|
100
|
+
- `data`: An array of `Product` objects.
|
|
101
|
+
- `page`: The current page number.
|
|
102
|
+
- `perPage`: The number of items per page.
|
|
103
|
+
- `total`: The total number of items available.
|
|
104
|
+
|
|
105
|
+
#### Example
|
|
92
106
|
|
|
93
107
|
```typescript
|
|
94
|
-
import { GetSimilarProductsParams } from 'sizebay-core-sdk
|
|
108
|
+
import { GetSimilarProductsParams } from 'sizebay-core-sdk';
|
|
95
109
|
|
|
96
110
|
const params: GetSimilarProductsParams = {
|
|
97
111
|
tenantId: 123,
|
|
98
112
|
permalink: 'https://example.com/product',
|
|
99
|
-
collectionName: 'summer-collection',
|
|
100
|
-
sessionId: 456,
|
|
101
|
-
page: 1,
|
|
102
|
-
perPage: 10,
|
|
113
|
+
collectionName: 'summer-collection',
|
|
114
|
+
sessionId: 456,
|
|
115
|
+
page: 1,
|
|
116
|
+
perPage: 10,
|
|
103
117
|
};
|
|
104
118
|
|
|
105
119
|
async function fetchSimilarProducts() {
|
|
@@ -112,4 +126,57 @@ async function fetchSimilarProducts() {
|
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
fetchSimilarProducts();
|
|
115
|
-
```
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### `GetRecommendedSizeByProducts(payload: GetRecommendedSizeByProductsParams): Promise<GetRecommendedSizeByProductsResponse[]>`
|
|
134
|
+
|
|
135
|
+
Retrieves the recommended sizes for one or more products based on the provided parameters.
|
|
136
|
+
|
|
137
|
+
#### Parameters
|
|
138
|
+
|
|
139
|
+
| Parameter | Type | Required | Description |
|
|
140
|
+
|-------------:|-------------------------|:--------:|----------------------------------------------------------------------------------------------------------------|
|
|
141
|
+
| `tenantId` | `number` | **Yes** | The tenant ID that initiated the request. |
|
|
142
|
+
| `sid` | `string` (optional) | No | The session ID for internal events, if needed. |
|
|
143
|
+
| `sizeSystem` | `string` | **Yes** | The size system (e.g., 'BR', 'US', 'EU'). |
|
|
144
|
+
| `permalinks` | `string[]` | **Yes** | A list of product permalinks for which size recommendations are requested. |
|
|
145
|
+
|
|
146
|
+
#### Returns
|
|
147
|
+
|
|
148
|
+
**`Promise<GetRecommendedSizeByProductsResponse[]>`**
|
|
149
|
+
An array of objects, each containing:
|
|
150
|
+
|
|
151
|
+
- `id`: The internal identifier for the product.
|
|
152
|
+
- `permalink`: The product permalink from the request.
|
|
153
|
+
- `recommendedSize`: The recommended size (`string`) or `null` if no recommendation is available.
|
|
154
|
+
|
|
155
|
+
#### Example
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { GetRecommendedSizeByProductsParams } from 'sizebay-core-sdk';
|
|
159
|
+
|
|
160
|
+
const payload: GetRecommendedSizeByProductsParams = {
|
|
161
|
+
tenantId: 123,
|
|
162
|
+
sid: '0c7f5233b325',
|
|
163
|
+
sizeSystem: 'BR',
|
|
164
|
+
permalinks: [
|
|
165
|
+
'https://example.com/product1',
|
|
166
|
+
'https://example.com/product2',
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
async function fetchRecommendedSizes() {
|
|
171
|
+
try {
|
|
172
|
+
const response = await client.GetRecommendedSizeByProducts(payload);
|
|
173
|
+
response.forEach((item) => {
|
|
174
|
+
console.log(`Product ID: ${item.id}, Recommended Size: ${item.recommendedSize}`);
|
|
175
|
+
});
|
|
176
|
+
} catch (error: any) {
|
|
177
|
+
console.error('Error fetching recommended product sizes:', error.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
fetchRecommendedSizes();
|
|
182
|
+
```
|
|
@@ -1,101 +1,101 @@
|
|
|
1
1
|
const c = {
|
|
2
2
|
tracker: {
|
|
3
|
-
production: "https://data-event-service.internalsizebay.com
|
|
4
|
-
development: "https://data-event-service.internalsizebay.com
|
|
3
|
+
production: "https://data-event-service.internalsizebay.com",
|
|
4
|
+
development: "https://data-event-service.internalsizebay.com"
|
|
5
5
|
},
|
|
6
6
|
aiImageService: {
|
|
7
|
-
production: "https://ai-image-service.
|
|
8
|
-
development: "https://ai-image-service.
|
|
7
|
+
production: "https://ai-image-service.internalsizebay.com/",
|
|
8
|
+
development: "https://ai-image-service-dev.internalsizebay.com/"
|
|
9
9
|
}
|
|
10
10
|
// Adicione outros serviços conforme necessário
|
|
11
11
|
};
|
|
12
12
|
class a {
|
|
13
|
-
constructor(
|
|
14
|
-
const
|
|
15
|
-
this.serviceOverrides =
|
|
13
|
+
constructor(e) {
|
|
14
|
+
const n = e.env || "development";
|
|
15
|
+
this.serviceOverrides = e.services || {}, this.endpoints = {};
|
|
16
16
|
for (const t in c)
|
|
17
17
|
if (Object.prototype.hasOwnProperty.call(c, t)) {
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
18
|
+
const o = c[t][n];
|
|
19
|
+
if (!o)
|
|
20
20
|
continue;
|
|
21
|
-
this.endpoints[t] =
|
|
21
|
+
this.endpoints[t] = o;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
getEndpoint(
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
24
|
+
getEndpoint(e) {
|
|
25
|
+
const n = this.endpoints[e];
|
|
26
|
+
if (!n)
|
|
27
27
|
throw new Error(
|
|
28
|
-
`Endpoint for service '${
|
|
28
|
+
`Endpoint for service '${e}' is not configured.`
|
|
29
29
|
);
|
|
30
|
-
return
|
|
30
|
+
return n;
|
|
31
31
|
}
|
|
32
|
-
getServiceConfig(
|
|
33
|
-
return this.serviceOverrides[
|
|
32
|
+
getServiceConfig(e) {
|
|
33
|
+
return this.serviceOverrides[e] || {};
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
class p {
|
|
37
|
-
constructor(
|
|
38
|
-
this.endpoint =
|
|
37
|
+
constructor(e) {
|
|
38
|
+
this.endpoint = e.getEndpoint("tracker");
|
|
39
39
|
}
|
|
40
|
-
async track(
|
|
40
|
+
async track(e, n) {
|
|
41
41
|
const t = {
|
|
42
|
-
eventName:
|
|
43
|
-
...
|
|
44
|
-
};
|
|
42
|
+
eventName: e,
|
|
43
|
+
...n
|
|
44
|
+
}, r = new URL(`${this.endpoint}/events`);
|
|
45
45
|
try {
|
|
46
|
-
const
|
|
46
|
+
const o = await fetch(r, {
|
|
47
47
|
method: "POST",
|
|
48
48
|
headers: { "Content-Type": "application/json" },
|
|
49
49
|
body: JSON.stringify(t)
|
|
50
50
|
});
|
|
51
|
-
if (!
|
|
52
|
-
const i = await
|
|
53
|
-
throw new Error(`Request error: ${
|
|
51
|
+
if (!o.ok) {
|
|
52
|
+
const i = await o.text();
|
|
53
|
+
throw new Error(`Request error: ${o.status} - ${i}`);
|
|
54
54
|
}
|
|
55
|
-
return await
|
|
56
|
-
} catch (
|
|
57
|
-
throw
|
|
55
|
+
return await o.json();
|
|
56
|
+
} catch (o) {
|
|
57
|
+
throw o;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
class d {
|
|
62
|
-
constructor(
|
|
63
|
-
this.endpoint =
|
|
62
|
+
constructor(e) {
|
|
63
|
+
this.endpoint = e.getEndpoint("aiImageService");
|
|
64
64
|
}
|
|
65
|
-
async getSimilarProducts(
|
|
66
|
-
const
|
|
67
|
-
Object.entries(
|
|
68
|
-
|
|
65
|
+
async getSimilarProducts(e) {
|
|
66
|
+
const n = new URL(`${this.endpoint}/recommendations/similar`);
|
|
67
|
+
Object.entries(e).forEach(([t, r]) => {
|
|
68
|
+
r !== void 0 && n.searchParams.append(t, String(r));
|
|
69
69
|
});
|
|
70
70
|
try {
|
|
71
|
-
const t = await fetch(
|
|
71
|
+
const t = await fetch(n.toString(), {
|
|
72
72
|
method: "GET",
|
|
73
73
|
headers: {
|
|
74
74
|
"Content-Type": "application/json"
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
77
|
if (!t.ok) {
|
|
78
|
-
const
|
|
79
|
-
throw new Error(`Request error: ${t.status} - ${
|
|
78
|
+
const r = await t.text();
|
|
79
|
+
throw new Error(`Request error: ${t.status} - ${r}`);
|
|
80
80
|
}
|
|
81
81
|
return await t.json();
|
|
82
82
|
} catch (t) {
|
|
83
83
|
throw new Error(`Error fetching similar products: ${t.message}`);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
async
|
|
87
|
-
const
|
|
86
|
+
async getRecommendedSizeByProducts(e) {
|
|
87
|
+
const n = new URL(`${this.endpoint}/recommendations/size-by-products`);
|
|
88
88
|
try {
|
|
89
|
-
const t = await fetch(
|
|
89
|
+
const t = await fetch(n.toString(), {
|
|
90
90
|
method: "POST",
|
|
91
91
|
headers: {
|
|
92
92
|
"Content-Type": "application/json"
|
|
93
93
|
},
|
|
94
|
-
body: JSON.stringify(
|
|
94
|
+
body: JSON.stringify(e)
|
|
95
95
|
});
|
|
96
96
|
if (!t.ok) {
|
|
97
|
-
const
|
|
98
|
-
throw new Error(`Request error: ${t.status} - ${
|
|
97
|
+
const r = await t.text();
|
|
98
|
+
throw new Error(`Request error: ${t.status} - ${r}`);
|
|
99
99
|
}
|
|
100
100
|
return await t.json();
|
|
101
101
|
} catch (t) {
|
|
@@ -108,14 +108,14 @@ const h = [
|
|
|
108
108
|
d
|
|
109
109
|
];
|
|
110
110
|
function f(s) {
|
|
111
|
-
const
|
|
112
|
-
return
|
|
113
|
-
Object.getOwnPropertyNames(
|
|
114
|
-
typeof
|
|
111
|
+
const e = new a(s), n = h.map((r) => new r(e)), t = { config: e };
|
|
112
|
+
return n.forEach((r) => {
|
|
113
|
+
Object.getOwnPropertyNames(r).forEach((i) => {
|
|
114
|
+
typeof r[i] == "function" && (t[i] = r[i].bind(r));
|
|
115
115
|
});
|
|
116
|
-
const
|
|
117
|
-
Object.getOwnPropertyNames(
|
|
118
|
-
|
|
116
|
+
const o = Object.getPrototypeOf(r);
|
|
117
|
+
Object.getOwnPropertyNames(o).forEach((i) => {
|
|
118
|
+
i !== "constructor" && typeof r[i] == "function" && (t[i] = r[i].bind(r));
|
|
119
119
|
});
|
|
120
120
|
}), t;
|
|
121
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(s
|
|
1
|
+
(function(c,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(c=typeof globalThis<"u"?globalThis:c||self,s(c["sizebay-core-sdk"]={}))})(this,function(c){"use strict";const s={tracker:{production:"https://data-event-service.internalsizebay.com",development:"https://data-event-service.internalsizebay.com"},aiImageService:{production:"https://ai-image-service.internalsizebay.com/",development:"https://ai-image-service-dev.internalsizebay.com/"}};class p{constructor(t){const n=t.env||"development";this.serviceOverrides=t.services||{},this.endpoints={};for(const e in s)if(Object.prototype.hasOwnProperty.call(s,e)){const o=s[e][n];if(!o)continue;this.endpoints[e]=o}}getEndpoint(t){const n=this.endpoints[t];if(!n)throw new Error(`Endpoint for service '${t}' is not configured.`);return n}getServiceConfig(t){return this.serviceOverrides[t]||{}}}class d{constructor(t){this.endpoint=t.getEndpoint("tracker")}async track(t,n){const e={eventName:t,...n},r=new URL(`${this.endpoint}/events`);try{const o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok){const i=await o.text();throw new Error(`Request error: ${o.status} - ${i}`)}return await o.json()}catch(o){throw o}}}class f{constructor(t){this.endpoint=t.getEndpoint("aiImageService")}async getSimilarProducts(t){const n=new URL(`${this.endpoint}/recommendations/similar`);Object.entries(t).forEach(([e,r])=>{r!==void 0&&n.searchParams.append(e,String(r))});try{const e=await fetch(n.toString(),{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const r=await e.text();throw new Error(`Request error: ${e.status} - ${r}`)}return await e.json()}catch(e){throw new Error(`Error fetching similar products: ${e.message}`)}}async getRecommendedSizeByProducts(t){const n=new URL(`${this.endpoint}/recommendations/size-by-products`);try{const e=await fetch(n.toString(),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok){const r=await e.text();throw new Error(`Request error: ${e.status} - ${r}`)}return await e.json()}catch(e){throw new Error(`Error fetching recommended product size: ${e.message}`)}}}const h=[d,f];function u(a){const t=new p(a),n=h.map(r=>new r(t)),e={config:t};return n.forEach(r=>{Object.getOwnPropertyNames(r).forEach(i=>{typeof r[i]=="function"&&(e[i]=r[i].bind(r))});const o=Object.getPrototypeOf(r);Object.getOwnPropertyNames(o).forEach(i=>{i!=="constructor"&&typeof r[i]=="function"&&(e[i]=r[i].bind(r))})}),e}c.createClient=u,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Config } from '../config';
|
|
2
|
-
import {
|
|
2
|
+
import { GetRecommendedSizeByProductsParams, GetRecommendedSizeByProductsResponse, GetSimilarProductsParams, GetSimilarProductsResponse } from '../types/ai-image-service.types';
|
|
3
3
|
export declare class AIImageService {
|
|
4
4
|
private endpoint;
|
|
5
5
|
constructor(config: Config);
|
|
6
6
|
getSimilarProducts(params: GetSimilarProductsParams): Promise<GetSimilarProductsResponse>;
|
|
7
|
-
|
|
7
|
+
getRecommendedSizeByProducts(payload: GetRecommendedSizeByProductsParams): Promise<GetRecommendedSizeByProductsResponse[]>;
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface GetSimilarProductsParams {
|
|
2
2
|
tenantId: number;
|
|
3
|
-
collectionName
|
|
4
|
-
sessionId
|
|
3
|
+
collectionName: string;
|
|
4
|
+
sessionId: number;
|
|
5
5
|
permalink: string;
|
|
6
6
|
page?: number;
|
|
7
7
|
perPage?: number;
|
|
@@ -29,20 +29,14 @@ export interface GetSimilarProductsResponse {
|
|
|
29
29
|
perPage: number;
|
|
30
30
|
total: number;
|
|
31
31
|
}
|
|
32
|
-
export interface
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
productInfo: any | null;
|
|
36
|
-
recommendedSize: string;
|
|
37
|
-
recommendedComposedMeasure: any | null;
|
|
38
|
-
composedMeasureOrder: any | null;
|
|
39
|
-
productGender: string;
|
|
40
|
-
profileName: string;
|
|
32
|
+
export interface GetRecommendedSizeByProductsParams {
|
|
33
|
+
tenantId: number;
|
|
34
|
+
sid?: string;
|
|
41
35
|
sizeSystem: string;
|
|
36
|
+
permalinks: string[];
|
|
42
37
|
}
|
|
43
|
-
export interface
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
[key: string]: string | number | boolean;
|
|
38
|
+
export interface GetRecommendedSizeByProductsResponse {
|
|
39
|
+
id: string;
|
|
40
|
+
permalink: string;
|
|
41
|
+
recommendedSize: string | null;
|
|
48
42
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sizebay-core-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A SDK designed for integrating multiple services (such as event tracking, AI services, etc.) into your application.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/config/endpoints.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { EndpointDefinition } from "@src/types";
|
|
|
2
2
|
|
|
3
3
|
export const endpoints: Record<string, EndpointDefinition> = {
|
|
4
4
|
tracker: {
|
|
5
|
-
production: 'https://data-event-service.internalsizebay.com
|
|
6
|
-
development: 'https://data-event-service.internalsizebay.com
|
|
5
|
+
production: 'https://data-event-service.internalsizebay.com',
|
|
6
|
+
development: 'https://data-event-service.internalsizebay.com',
|
|
7
7
|
},
|
|
8
8
|
|
|
9
9
|
aiImageService: {
|
|
10
|
-
production: 'https://ai-image-service.
|
|
11
|
-
development: 'https://ai-image-service.
|
|
10
|
+
production: 'https://ai-image-service.internalsizebay.com/',
|
|
11
|
+
development: 'https://ai-image-service-dev.internalsizebay.com/',
|
|
12
12
|
},
|
|
13
13
|
// Adicione outros serviços conforme necessário
|
|
14
14
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Config } from '@src/config';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
GetRecommendedSizeByProductsParams,
|
|
4
|
+
GetRecommendedSizeByProductsResponse,
|
|
5
5
|
GetSimilarProductsParams,
|
|
6
6
|
GetSimilarProductsResponse,
|
|
7
7
|
} from '@src/types/ai-image-service.types';
|
|
@@ -42,9 +42,9 @@ export class AIImageService {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
public async
|
|
46
|
-
payload:
|
|
47
|
-
): Promise<
|
|
45
|
+
public async getRecommendedSizeByProducts(
|
|
46
|
+
payload: GetRecommendedSizeByProductsParams,
|
|
47
|
+
): Promise<GetRecommendedSizeByProductsResponse[]> {
|
|
48
48
|
const url = new URL(`${this.endpoint}/recommendations/size-by-products`);
|
|
49
49
|
|
|
50
50
|
try {
|
|
@@ -60,7 +60,7 @@ export class AIImageService {
|
|
|
60
60
|
const errorText = await response.text();
|
|
61
61
|
throw new Error(`Request error: ${response.status} - ${errorText}`);
|
|
62
62
|
}
|
|
63
|
-
return (await response.json()) as
|
|
63
|
+
return (await response.json()) as GetRecommendedSizeByProductsResponse[];
|
|
64
64
|
} catch (error: any) {
|
|
65
65
|
throw new Error(`Error fetching recommended product size: ${error.message}`);
|
|
66
66
|
}
|
package/src/modules/tracker.ts
CHANGED
|
@@ -5,9 +5,7 @@ export class Tracker {
|
|
|
5
5
|
|
|
6
6
|
private endpoint: string;
|
|
7
7
|
|
|
8
|
-
constructor(config: Config) {
|
|
9
|
-
// Define "config" como não enumerável
|
|
10
|
-
|
|
8
|
+
constructor(config: Config) {
|
|
11
9
|
this.endpoint = config.getEndpoint('tracker');
|
|
12
10
|
}
|
|
13
11
|
|
|
@@ -16,9 +14,10 @@ export class Tracker {
|
|
|
16
14
|
eventName,
|
|
17
15
|
...payload,
|
|
18
16
|
};
|
|
17
|
+
const url = new URL(`${this.endpoint}/events`);
|
|
19
18
|
|
|
20
19
|
try {
|
|
21
|
-
const response = await fetch(
|
|
20
|
+
const response = await fetch(url, {
|
|
22
21
|
method: "POST",
|
|
23
22
|
headers: { "Content-Type": "application/json" },
|
|
24
23
|
body: JSON.stringify(data),
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export interface GetSimilarProductsParams {
|
|
2
2
|
tenantId: number;
|
|
3
|
-
collectionName
|
|
4
|
-
sessionId
|
|
3
|
+
collectionName: string;
|
|
4
|
+
sessionId: number;
|
|
5
5
|
permalink: string;
|
|
6
6
|
page?: number;
|
|
7
7
|
perPage?: number;
|
|
8
8
|
}
|
|
9
|
+
|
|
9
10
|
export interface Product {
|
|
10
11
|
id: string;
|
|
11
12
|
title: string;
|
|
@@ -31,22 +32,16 @@ export interface GetSimilarProductsResponse {
|
|
|
31
32
|
total: number;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
export interface
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
productInfo: any | null;
|
|
38
|
-
recommendedSize: string;
|
|
39
|
-
recommendedComposedMeasure: any | null;
|
|
40
|
-
composedMeasureOrder: any | null;
|
|
41
|
-
productGender: string;
|
|
42
|
-
profileName: string;
|
|
35
|
+
export interface GetRecommendedSizeByProductsParams {
|
|
36
|
+
tenantId: number;
|
|
37
|
+
sid?: string;
|
|
43
38
|
sizeSystem: string;
|
|
39
|
+
permalinks: string[];
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
export interface GetRecommendedProductSizeParams {
|
|
47
|
-
products: ProductRecommendedSize[];
|
|
48
|
-
}
|
|
49
42
|
|
|
50
|
-
export interface
|
|
51
|
-
|
|
43
|
+
export interface GetRecommendedSizeByProductsResponse {
|
|
44
|
+
id: string;
|
|
45
|
+
permalink: string;
|
|
46
|
+
recommendedSize: string | null;
|
|
52
47
|
}
|
|
@@ -2,27 +2,27 @@ import { AIImageService } from '@src/modules/ai-image-service';
|
|
|
2
2
|
import {
|
|
3
3
|
GetSimilarProductsParams,
|
|
4
4
|
GetSimilarProductsResponse,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
GetRecommendedSizeByProductsParams,
|
|
6
|
+
GetRecommendedSizeByProductsResponse,
|
|
7
7
|
} from '@src/types/ai-image-service.types';
|
|
8
8
|
|
|
9
9
|
describe('AIImageService', () => {
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
const fakeEndpoint = 'https://example.com/ai-image-service';
|
|
12
12
|
let fakeConfig: { getEndpoint: (serviceName: string) => string };
|
|
13
13
|
let aiImageService: AIImageService;
|
|
14
14
|
|
|
15
15
|
beforeEach(() => {
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
fakeConfig = {
|
|
18
18
|
getEndpoint: (serviceName: string) => fakeEndpoint,
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
aiImageService = new AIImageService(fakeConfig as any);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
afterEach(() => {
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
if (global.fetch && (global.fetch as jest.Mock).mockReset) {
|
|
27
27
|
(global.fetch as jest.Mock).mockReset();
|
|
28
28
|
}
|
|
@@ -73,7 +73,6 @@ describe('AIImageService', () => {
|
|
|
73
73
|
|
|
74
74
|
const result = await aiImageService.getSimilarProducts(params);
|
|
75
75
|
|
|
76
|
-
// Build expected URL with query parameters.
|
|
77
76
|
const expectedUrl = new URL(`${fakeEndpoint}/recommendations/similar`);
|
|
78
77
|
Object.entries(params).forEach(([key, value]) => {
|
|
79
78
|
if (value !== undefined) {
|
|
@@ -131,12 +130,16 @@ describe('AIImageService', () => {
|
|
|
131
130
|
});
|
|
132
131
|
});
|
|
133
132
|
|
|
134
|
-
describe('
|
|
133
|
+
describe('getRecommendedSizeByProducts', () => {
|
|
135
134
|
it('should send the POST request with the correct payload and return the JSON response', async () => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
|
|
136
|
+
const fakeResponseData: GetRecommendedSizeByProductsResponse[] = [
|
|
137
|
+
{
|
|
138
|
+
id: '1',
|
|
139
|
+
permalink: 'https://example.com/product/1',
|
|
140
|
+
recommendedSize: 'M',
|
|
141
|
+
},
|
|
142
|
+
];
|
|
140
143
|
|
|
141
144
|
const fakeFetchResponse = {
|
|
142
145
|
ok: true,
|
|
@@ -145,23 +148,15 @@ describe('AIImageService', () => {
|
|
|
145
148
|
|
|
146
149
|
global.fetch = jest.fn().mockResolvedValue(fakeFetchResponse as any);
|
|
147
150
|
|
|
148
|
-
const payload:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
recommendedSize: 'M',
|
|
155
|
-
recommendedComposedMeasure: null,
|
|
156
|
-
composedMeasureOrder: null,
|
|
157
|
-
productGender: 'unisex',
|
|
158
|
-
profileName: 'profile1',
|
|
159
|
-
sizeSystem: 'US',
|
|
160
|
-
},
|
|
161
|
-
],
|
|
151
|
+
const payload: GetRecommendedSizeByProductsParams = {
|
|
152
|
+
tenantId: 123,
|
|
153
|
+
|
|
154
|
+
sid: 'some-session-id',
|
|
155
|
+
sizeSystem: 'US',
|
|
156
|
+
permalinks: ['https://example.com/product/1'],
|
|
162
157
|
};
|
|
163
158
|
|
|
164
|
-
const result = await aiImageService.
|
|
159
|
+
const result = await aiImageService.getRecommendedSizeByProducts(payload);
|
|
165
160
|
|
|
166
161
|
const expectedUrl = `${fakeEndpoint}/recommendations/size-by-products`;
|
|
167
162
|
|
|
@@ -183,24 +178,14 @@ describe('AIImageService', () => {
|
|
|
183
178
|
|
|
184
179
|
global.fetch = jest.fn().mockResolvedValue(fakeFetchResponse as any);
|
|
185
180
|
|
|
186
|
-
const payload:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
analysisResponse: null,
|
|
191
|
-
productInfo: null,
|
|
192
|
-
recommendedSize: 'M',
|
|
193
|
-
recommendedComposedMeasure: null,
|
|
194
|
-
composedMeasureOrder: null,
|
|
195
|
-
productGender: 'unisex',
|
|
196
|
-
profileName: 'profile1',
|
|
197
|
-
sizeSystem: 'US',
|
|
198
|
-
},
|
|
199
|
-
],
|
|
181
|
+
const payload: GetRecommendedSizeByProductsParams = {
|
|
182
|
+
tenantId: 123,
|
|
183
|
+
sizeSystem: 'US',
|
|
184
|
+
permalinks: ['https://example.com/product/1'],
|
|
200
185
|
};
|
|
201
186
|
|
|
202
187
|
await expect(
|
|
203
|
-
aiImageService.
|
|
188
|
+
aiImageService.getRecommendedSizeByProducts(payload),
|
|
204
189
|
).rejects.toThrow(`Request error: 500 - ${errorText}`);
|
|
205
190
|
});
|
|
206
191
|
|
|
@@ -208,27 +193,17 @@ describe('AIImageService', () => {
|
|
|
208
193
|
const errorMessage = 'Network error';
|
|
209
194
|
global.fetch = jest.fn().mockRejectedValue(new Error(errorMessage));
|
|
210
195
|
|
|
211
|
-
const payload:
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
analysisResponse: null,
|
|
216
|
-
productInfo: null,
|
|
217
|
-
recommendedSize: 'M',
|
|
218
|
-
recommendedComposedMeasure: null,
|
|
219
|
-
composedMeasureOrder: null,
|
|
220
|
-
productGender: 'unisex',
|
|
221
|
-
profileName: 'profile1',
|
|
222
|
-
sizeSystem: 'US',
|
|
223
|
-
},
|
|
224
|
-
],
|
|
196
|
+
const payload: GetRecommendedSizeByProductsParams = {
|
|
197
|
+
tenantId: 123,
|
|
198
|
+
sizeSystem: 'US',
|
|
199
|
+
permalinks: ['https://example.com/product/1'],
|
|
225
200
|
};
|
|
226
201
|
|
|
227
202
|
await expect(
|
|
228
|
-
aiImageService.
|
|
203
|
+
aiImageService.getRecommendedSizeByProducts(payload),
|
|
229
204
|
).rejects.toThrow(
|
|
230
205
|
`Error fetching recommended product size: ${errorMessage}`,
|
|
231
206
|
);
|
|
232
207
|
});
|
|
233
208
|
});
|
|
234
|
-
});
|
|
209
|
+
});
|
|
@@ -14,7 +14,9 @@ describe('Tracker', () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
afterEach(() => {
|
|
17
|
-
jest.
|
|
17
|
+
if (global.fetch && (global.fetch as jest.Mock).mockClear) {
|
|
18
|
+
(global.fetch as jest.Mock).mockClear();
|
|
19
|
+
}
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
it('should send the event and return the JSON response', async () => {
|
|
@@ -36,7 +38,8 @@ describe('Tracker', () => {
|
|
|
36
38
|
|
|
37
39
|
const result = await tracker.track(eventName, payload);
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
const expectedUrl = new URL(`${fakeEndpoint}/events`);
|
|
42
|
+
expect(global.fetch).toHaveBeenCalledWith(expectedUrl, {
|
|
40
43
|
method: 'POST',
|
|
41
44
|
headers: { 'Content-Type': 'application/json' },
|
|
42
45
|
body: JSON.stringify({ eventName, ...payload }),
|
|
@@ -46,7 +49,6 @@ describe('Tracker', () => {
|
|
|
46
49
|
|
|
47
50
|
it('should throw an error if the response is not ok', async () => {
|
|
48
51
|
const errorText = 'Internal Server Error';
|
|
49
|
-
|
|
50
52
|
const fakeFetchResponse = {
|
|
51
53
|
ok: false,
|
|
52
54
|
status: 500,
|