sizebay-core-sdk 1.0.0 → 1.1.0
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 +13 -0
- package/README.md +140 -26
- 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/modules/tracker.d.ts +2 -2
- package/dist/types/src/types/ai-image-service.types.d.ts +10 -16
- package/dist/types/src/types/event.types.d.ts +15 -0
- 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 +5 -6
- package/src/types/ai-image-service.types.ts +11 -16
- package/src/types/event.types.ts +25 -10
- 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,16 @@
|
|
|
1
|
+
## [1.1.0](https://github.com/sizebay/events-sdk/compare/v1.0.1...v1.1.0) (2025-04-01)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **tracker:** update TrackData types and documentation ([e7187f2](https://github.com/sizebay/events-sdk/commit/e7187f2ca7b5d0ecee3404b19bf3fa21f8c14953))
|
|
6
|
+
|
|
7
|
+
## [1.0.1](https://github.com/sizebay/events-sdk/compare/v1.0.0...v1.0.1) (2025-04-01)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **ai-image-service:** correct endpoint configuration ([cc7c8f4](https://github.com/sizebay/events-sdk/commit/cc7c8f41b4961e6fdca62d87ef3de152351064cd))
|
|
12
|
+
* **tracker:** update URL construction logic ([7be913c](https://github.com/sizebay/events-sdk/commit/7be913c8b81dfdd1543d4d843a83753955f5b83a))
|
|
13
|
+
|
|
1
14
|
## 1.0.0 (2025-03-31)
|
|
2
15
|
|
|
3
16
|
### Features
|
package/README.md
CHANGED
|
@@ -35,25 +35,63 @@ const client = createClient({
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
## Tracker Module
|
|
39
39
|
|
|
40
|
-
#### `track(eventName: string, payload:
|
|
41
|
-
Sends an event to the designated API endpoint.
|
|
40
|
+
#### `track(eventName: string, payload: TrackData): Promise<TrackResponse>`
|
|
41
|
+
Sends an event to the designated API endpoint, returning a standardized response.
|
|
42
42
|
|
|
43
43
|
**Parameters**
|
|
44
44
|
|
|
45
|
-
| Parameter
|
|
46
|
-
|
|
47
|
-
| `eventName`
|
|
48
|
-
| `payload`
|
|
45
|
+
| Parameter | Type | Required | Description |
|
|
46
|
+
|-------------|-------------|----------|-----------------------------------------------------------------------|
|
|
47
|
+
| `eventName` | `string` | Yes | The name of the event (e.g., "ADD_TO_CART", "ORDER"). |
|
|
48
|
+
| `payload` | `TrackData` | Yes | An object containing event data. See the structure of `TrackData` below. |
|
|
49
|
+
|
|
50
|
+
**TrackData Structure**
|
|
51
|
+
|
|
52
|
+
| Property | Type | Required | Description |
|
|
53
|
+
|-------------|-------------------------------|----------|-----------------------------------------------------------------------|
|
|
54
|
+
| **sid** | `string` | Yes | Unique session identifier. |
|
|
55
|
+
| **tenantId**| `number` | Yes | Identifier of the tenant (client) sending the event. |
|
|
56
|
+
| **sessionId**| `number` | Yes | Internal session identifier. |
|
|
57
|
+
| **permalink**| `string` (optional) | No | Product URL associated with the event. When the event is linked to product (e.g., ADD_TO_CART RECOMMENDATION_DONE), it is required. |
|
|
58
|
+
| **properties**| `Record<string, JSONValue>` | Yes | Object containing additional properties as key-value pairs. |
|
|
59
|
+
**Returns**
|
|
60
|
+
|
|
61
|
+
- **201** – Event successfully created.
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"statusCode": 201,
|
|
65
|
+
"message": "Event successfully created."
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
- **400** – Invalid or missing fields.
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"statusCode": 400,
|
|
72
|
+
"error": "Bad Request",
|
|
73
|
+
"message": [
|
|
74
|
+
"tenantId must be an integer number"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
- **500** – Internal server error.
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"statusCode": 500,
|
|
82
|
+
"error": "Internal server error",
|
|
83
|
+
"message": [
|
|
84
|
+
"Unexpected error on server side"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
49
88
|
|
|
50
89
|
**Example**
|
|
51
90
|
|
|
52
91
|
```typescript
|
|
53
|
-
const eventPayload = {
|
|
92
|
+
const eventPayload: TrackData = {
|
|
54
93
|
sid: 'a0cf8559-926a-4a75-b4ca-7c4c13fed69c',
|
|
55
94
|
tenantId: 123,
|
|
56
|
-
eventName: 'ADD_TO_CART',
|
|
57
95
|
sessionId: 123,
|
|
58
96
|
permalink: 'https://www.example.com/2IC-7370',
|
|
59
97
|
properties: {
|
|
@@ -66,40 +104,63 @@ const eventPayload = {
|
|
|
66
104
|
async function trackEvent() {
|
|
67
105
|
try {
|
|
68
106
|
const response = await client.track('ADD_TO_CART', eventPayload);
|
|
69
|
-
|
|
107
|
+
|
|
108
|
+
if (response.statusCode === 201) {
|
|
109
|
+
console.log('Event tracked successfully:', response.message);
|
|
110
|
+
} else {
|
|
111
|
+
console.error(
|
|
112
|
+
`Error tracking event (${response.statusCode}):`,
|
|
113
|
+
response.error,
|
|
114
|
+
response.message
|
|
115
|
+
);
|
|
116
|
+
}
|
|
70
117
|
} catch (error: any) {
|
|
71
|
-
console.error('
|
|
118
|
+
console.error('Unexpected error tracking event:', error.message);
|
|
72
119
|
}
|
|
73
120
|
}
|
|
74
121
|
|
|
75
122
|
trackEvent();
|
|
76
123
|
```
|
|
77
124
|
|
|
78
|
-
|
|
125
|
+
## AI Image Service Module
|
|
79
126
|
|
|
80
|
-
###
|
|
127
|
+
### `getSimilarProducts(params: GetSimilarProductsParams): Promise<GetSimilarProductsResponse>`
|
|
81
128
|
|
|
82
|
-
|
|
83
|
-
Fetches similar products based on the provided image parameters.
|
|
129
|
+
Fetches similar products based on the given parameters, returning a paginated result.
|
|
84
130
|
|
|
85
|
-
|
|
131
|
+
#### Parameters
|
|
86
132
|
|
|
87
|
-
| Parameter
|
|
88
|
-
|
|
89
|
-
| `
|
|
133
|
+
| Parameter | Type | Required | Description |
|
|
134
|
+
|------------------|--------------------------------|:--------:|------------------------------------------------------------------------------------------|
|
|
135
|
+
| `tenantId` | `number` | **Yes** | The tenant ID that initiated the request. |
|
|
136
|
+
| `collectionName` | `string` | **Yes** | The name of the relevant product collection. |
|
|
137
|
+
| `sessionId` | `number` | **Yes** | The session ID, typically required for internal event tracking. |
|
|
138
|
+
| `permalink` | `string` | **Yes** | A permanent link representing the main product. |
|
|
139
|
+
| `page` | `number` (optional) | No | Page number for pagination. |
|
|
140
|
+
| `perPage` | `number` (optional) | No | Number of items per page. |
|
|
90
141
|
|
|
91
|
-
|
|
142
|
+
#### Returns
|
|
143
|
+
|
|
144
|
+
**`Promise<GetSimilarProductsResponse>`**
|
|
145
|
+
An object containing:
|
|
146
|
+
|
|
147
|
+
- `data`: An array of `Product` objects.
|
|
148
|
+
- `page`: The current page number.
|
|
149
|
+
- `perPage`: The number of items per page.
|
|
150
|
+
- `total`: The total number of items available.
|
|
151
|
+
|
|
152
|
+
#### Example
|
|
92
153
|
|
|
93
154
|
```typescript
|
|
94
|
-
import { GetSimilarProductsParams } from 'sizebay-core-sdk
|
|
155
|
+
import { GetSimilarProductsParams } from 'sizebay-core-sdk';
|
|
95
156
|
|
|
96
157
|
const params: GetSimilarProductsParams = {
|
|
97
158
|
tenantId: 123,
|
|
98
159
|
permalink: 'https://example.com/product',
|
|
99
|
-
collectionName: 'summer-collection',
|
|
100
|
-
sessionId: 456,
|
|
101
|
-
page: 1,
|
|
102
|
-
perPage: 10,
|
|
160
|
+
collectionName: 'summer-collection',
|
|
161
|
+
sessionId: 456,
|
|
162
|
+
page: 1,
|
|
163
|
+
perPage: 10,
|
|
103
164
|
};
|
|
104
165
|
|
|
105
166
|
async function fetchSimilarProducts() {
|
|
@@ -112,4 +173,57 @@ async function fetchSimilarProducts() {
|
|
|
112
173
|
}
|
|
113
174
|
|
|
114
175
|
fetchSimilarProducts();
|
|
115
|
-
```
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### `GetRecommendedSizeByProducts(payload: GetRecommendedSizeByProductsParams): Promise<GetRecommendedSizeByProductsResponse[]>`
|
|
181
|
+
|
|
182
|
+
Retrieves the recommended sizes for one or more products based on the provided parameters.
|
|
183
|
+
|
|
184
|
+
#### Parameters
|
|
185
|
+
|
|
186
|
+
| Parameter | Type | Required | Description |
|
|
187
|
+
|-------------:|-------------------------|:--------:|----------------------------------------------------------------------------------------------------------------|
|
|
188
|
+
| `tenantId` | `number` | **Yes** | The tenant ID that initiated the request. |
|
|
189
|
+
| `sid` | `string` (optional) | No | The session ID for internal events, if needed. |
|
|
190
|
+
| `sizeSystem` | `string` | **Yes** | The size system (e.g., 'BR', 'US', 'EU'). |
|
|
191
|
+
| `permalinks` | `string[]` | **Yes** | A list of product permalinks for which size recommendations are requested. |
|
|
192
|
+
|
|
193
|
+
#### Returns
|
|
194
|
+
|
|
195
|
+
**`Promise<GetRecommendedSizeByProductsResponse[]>`**
|
|
196
|
+
An array of objects, each containing:
|
|
197
|
+
|
|
198
|
+
- `id`: The internal identifier for the product.
|
|
199
|
+
- `permalink`: The product permalink from the request.
|
|
200
|
+
- `recommendedSize`: The recommended size (`string`) or `null` if no recommendation is available.
|
|
201
|
+
|
|
202
|
+
#### Example
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { GetRecommendedSizeByProductsParams } from 'sizebay-core-sdk';
|
|
206
|
+
|
|
207
|
+
const payload: GetRecommendedSizeByProductsParams = {
|
|
208
|
+
tenantId: 123,
|
|
209
|
+
sid: '0c7f5233b325',
|
|
210
|
+
sizeSystem: 'BR',
|
|
211
|
+
permalinks: [
|
|
212
|
+
'https://example.com/product1',
|
|
213
|
+
'https://example.com/product2',
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
async function fetchRecommendedSizes() {
|
|
218
|
+
try {
|
|
219
|
+
const response = await client.GetRecommendedSizeByProducts(payload);
|
|
220
|
+
response.forEach((item) => {
|
|
221
|
+
console.log(`Product ID: ${item.id}, Recommended Size: ${item.recommendedSize}`);
|
|
222
|
+
});
|
|
223
|
+
} catch (error: any) {
|
|
224
|
+
console.error('Error fetching recommended product sizes:', error.message);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
fetchRecommendedSizes();
|
|
229
|
+
```
|
|
@@ -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
|
-
import { TrackData } from '../types';
|
|
1
|
+
import { TrackData, TrackResponse } from '../types';
|
|
2
2
|
import { Config } from '../config';
|
|
3
3
|
export declare class Tracker {
|
|
4
4
|
private endpoint;
|
|
5
5
|
constructor(config: Config);
|
|
6
|
-
track(eventName: string, payload: TrackData): Promise<
|
|
6
|
+
track(eventName: string, payload: TrackData): Promise<TrackResponse>;
|
|
7
7
|
}
|
|
@@ -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
|
}
|
|
@@ -11,3 +11,18 @@ export interface TrackData {
|
|
|
11
11
|
export interface DataEventPayload extends TrackData {
|
|
12
12
|
eventName: string;
|
|
13
13
|
}
|
|
14
|
+
export interface TrackSuccessResponse {
|
|
15
|
+
statusCode: 201;
|
|
16
|
+
message: 'Event successfully created.';
|
|
17
|
+
}
|
|
18
|
+
export interface TrackBadRequestResponse {
|
|
19
|
+
statusCode: 400;
|
|
20
|
+
error: 'Bad Request';
|
|
21
|
+
message: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface TrackServerErrorResponse {
|
|
24
|
+
statusCode: 500;
|
|
25
|
+
error: 'Internal server error';
|
|
26
|
+
message: string[];
|
|
27
|
+
}
|
|
28
|
+
export type TrackResponse = TrackSuccessResponse | TrackBadRequestResponse | TrackServerErrorResponse;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sizebay-core-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
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
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import { DataEventPayload, TrackData } from "../types";
|
|
1
|
+
import { DataEventPayload, TrackData, TrackResponse } from "../types";
|
|
2
2
|
import { Config } from "../config";
|
|
3
3
|
|
|
4
4
|
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
|
|
|
14
|
-
public async track(eventName: string, payload: TrackData): Promise<
|
|
12
|
+
public async track(eventName: string, payload: TrackData): Promise<TrackResponse> {
|
|
15
13
|
const data: DataEventPayload = {
|
|
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
|
}
|
package/src/types/event.types.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Represents any valid JSON value.
|
|
3
|
-
*/
|
|
4
1
|
export type JSONValue =
|
|
5
2
|
| string
|
|
6
3
|
| number
|
|
@@ -9,9 +6,6 @@ export type JSONValue =
|
|
|
9
6
|
| JSONValue[]
|
|
10
7
|
| { [key: string]: JSONValue };
|
|
11
8
|
|
|
12
|
-
/**
|
|
13
|
-
* Interface that defines the structure of a tracked event.
|
|
14
|
-
*/
|
|
15
9
|
export interface TrackData {
|
|
16
10
|
sid: string;
|
|
17
11
|
tenantId: number;
|
|
@@ -20,9 +14,30 @@ export interface TrackData {
|
|
|
20
14
|
properties: Record<string, JSONValue>;
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
/**
|
|
24
|
-
* Payload for the track event.
|
|
25
|
-
*/
|
|
26
17
|
export interface DataEventPayload extends TrackData {
|
|
27
18
|
eventName: string;
|
|
28
|
-
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TrackSuccessResponse {
|
|
22
|
+
statusCode: 201;
|
|
23
|
+
message: 'Event successfully created.';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TrackBadRequestResponse {
|
|
27
|
+
statusCode: 400;
|
|
28
|
+
error: 'Bad Request';
|
|
29
|
+
|
|
30
|
+
message: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface TrackServerErrorResponse {
|
|
34
|
+
statusCode: 500;
|
|
35
|
+
error: 'Internal server error';
|
|
36
|
+
|
|
37
|
+
message: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type TrackResponse =
|
|
41
|
+
| TrackSuccessResponse
|
|
42
|
+
| TrackBadRequestResponse
|
|
43
|
+
| TrackServerErrorResponse;
|
|
@@ -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,
|