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 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
- ### AI Image Service Module
80
+ ### `getSimilarProducts(params: GetSimilarProductsParams): Promise<GetSimilarProductsResponse>`
81
81
 
82
- #### `getSimilarProducts(params: GetSimilarProductsParams): Promise<GetSimilarProductsResponse>`
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
- **Parameters**
84
+ #### Parameters
86
85
 
87
- | Parameter | Type | Required | Description |
88
- |-----------|----------------------------|----------|------------------------------------------------------------|
89
- | `params` | `GetSimilarProductsParams` | Yes | An object containing parameters for fetching similar products. |
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
- **Example**
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/types/ai-image-service';
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', // optional
100
- sessionId: 456, // optional
101
- page: 1, // optional
102
- perPage: 10, // optional
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/events",
4
- development: "https://data-event-service.internalsizebay.com/events"
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.example.com/production",
8
- development: "https://ai-image-service.example.com/development"
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(r) {
14
- const o = r.env || "development";
15
- this.serviceOverrides = r.services || {}, this.endpoints = {};
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 i = c[t][o];
19
- if (!i)
18
+ const o = c[t][n];
19
+ if (!o)
20
20
  continue;
21
- this.endpoints[t] = i;
21
+ this.endpoints[t] = o;
22
22
  }
23
23
  }
24
- getEndpoint(r) {
25
- const o = this.endpoints[r];
26
- if (!o)
24
+ getEndpoint(e) {
25
+ const n = this.endpoints[e];
26
+ if (!n)
27
27
  throw new Error(
28
- `Endpoint for service '${r}' is not configured.`
28
+ `Endpoint for service '${e}' is not configured.`
29
29
  );
30
- return o;
30
+ return n;
31
31
  }
32
- getServiceConfig(r) {
33
- return this.serviceOverrides[r] || {};
32
+ getServiceConfig(e) {
33
+ return this.serviceOverrides[e] || {};
34
34
  }
35
35
  }
36
36
  class p {
37
- constructor(r) {
38
- this.endpoint = r.getEndpoint("tracker");
37
+ constructor(e) {
38
+ this.endpoint = e.getEndpoint("tracker");
39
39
  }
40
- async track(r, o) {
40
+ async track(e, n) {
41
41
  const t = {
42
- eventName: r,
43
- ...o
44
- };
42
+ eventName: e,
43
+ ...n
44
+ }, r = new URL(`${this.endpoint}/events`);
45
45
  try {
46
- const e = await fetch(this.endpoint, {
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 (!e.ok) {
52
- const i = await e.text();
53
- throw new Error(`Request error: ${e.status} - ${i}`);
51
+ if (!o.ok) {
52
+ const i = await o.text();
53
+ throw new Error(`Request error: ${o.status} - ${i}`);
54
54
  }
55
- return await e.json();
56
- } catch (e) {
57
- throw e;
55
+ return await o.json();
56
+ } catch (o) {
57
+ throw o;
58
58
  }
59
59
  }
60
60
  }
61
61
  class d {
62
- constructor(r) {
63
- this.endpoint = r.getEndpoint("aiImageService");
62
+ constructor(e) {
63
+ this.endpoint = e.getEndpoint("aiImageService");
64
64
  }
65
- async getSimilarProducts(r) {
66
- const o = new URL(`${this.endpoint}/recommendations/similar`);
67
- Object.entries(r).forEach(([t, e]) => {
68
- e !== void 0 && o.searchParams.append(t, String(e));
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(o.toString(), {
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 e = await t.text();
79
- throw new Error(`Request error: ${t.status} - ${e}`);
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 getRecommendedProductSize(r) {
87
- const o = new URL(`${this.endpoint}/recommendations/size-by-products`);
86
+ async getRecommendedSizeByProducts(e) {
87
+ const n = new URL(`${this.endpoint}/recommendations/size-by-products`);
88
88
  try {
89
- const t = await fetch(o.toString(), {
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(r)
94
+ body: JSON.stringify(e)
95
95
  });
96
96
  if (!t.ok) {
97
- const e = await t.text();
98
- throw new Error(`Request error: ${t.status} - ${e}`);
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 r = new a(s), o = h.map((e) => new e(r)), t = { config: r };
112
- return o.forEach((e) => {
113
- Object.getOwnPropertyNames(e).forEach((n) => {
114
- typeof e[n] == "function" && (t[n] = e[n].bind(e));
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 i = Object.getPrototypeOf(e);
117
- Object.getOwnPropertyNames(i).forEach((n) => {
118
- n !== "constructor" && typeof e[n] == "function" && (t[n] = e[n].bind(e));
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,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(s=typeof globalThis<"u"?globalThis:s||self,i(s["sizebay-core-sdk"]={}))})(this,function(s){"use strict";const i={tracker:{production:"https://data-event-service.internalsizebay.com/events",development:"https://data-event-service.internalsizebay.com/events"},aiImageService:{production:"https://ai-image-service.example.com/production",development:"https://ai-image-service.example.com/development"}};class p{constructor(r){const o=r.env||"development";this.serviceOverrides=r.services||{},this.endpoints={};for(const e in i)if(Object.prototype.hasOwnProperty.call(i,e)){const c=i[e][o];if(!c)continue;this.endpoints[e]=c}}getEndpoint(r){const o=this.endpoints[r];if(!o)throw new Error(`Endpoint for service '${r}' is not configured.`);return o}getServiceConfig(r){return this.serviceOverrides[r]||{}}}class d{constructor(r){this.endpoint=r.getEndpoint("tracker")}async track(r,o){const e={eventName:r,...o};try{const t=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const c=await t.text();throw new Error(`Request error: ${t.status} - ${c}`)}return await t.json()}catch(t){throw t}}}class f{constructor(r){this.endpoint=r.getEndpoint("aiImageService")}async getSimilarProducts(r){const o=new URL(`${this.endpoint}/recommendations/similar`);Object.entries(r).forEach(([e,t])=>{t!==void 0&&o.searchParams.append(e,String(t))});try{const e=await fetch(o.toString(),{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){const t=await e.text();throw new Error(`Request error: ${e.status} - ${t}`)}return await e.json()}catch(e){throw new Error(`Error fetching similar products: ${e.message}`)}}async getRecommendedProductSize(r){const o=new URL(`${this.endpoint}/recommendations/size-by-products`);try{const e=await fetch(o.toString(),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!e.ok){const t=await e.text();throw new Error(`Request error: ${e.status} - ${t}`)}return await e.json()}catch(e){throw new Error(`Error fetching recommended product size: ${e.message}`)}}}const h=[d,f];function u(a){const r=new p(a),o=h.map(t=>new t(r)),e={config:r};return o.forEach(t=>{Object.getOwnPropertyNames(t).forEach(n=>{typeof t[n]=="function"&&(e[n]=t[n].bind(t))});const c=Object.getPrototypeOf(t);Object.getOwnPropertyNames(c).forEach(n=>{n!=="constructor"&&typeof t[n]=="function"&&(e[n]=t[n].bind(t))})}),e}s.createClient=u,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})});
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 { GetRecommendedProductSizeParams, GetRecommendedProductSizeResponse, GetSimilarProductsParams, GetSimilarProductsResponse } from '../types/ai-image-service.types';
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
- getRecommendedProductSize(payload: GetRecommendedProductSizeParams): Promise<GetRecommendedProductSizeResponse>;
7
+ getRecommendedSizeByProducts(payload: GetRecommendedSizeByProductsParams): Promise<GetRecommendedSizeByProductsResponse[]>;
8
8
  }
@@ -1,7 +1,7 @@
1
1
  export interface GetSimilarProductsParams {
2
2
  tenantId: number;
3
- collectionName?: string;
4
- sessionId?: number;
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 ProductRecommendedSize {
33
- permalink: string;
34
- analysisResponse: any | null;
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 GetRecommendedProductSizeParams {
44
- products: ProductRecommendedSize[];
45
- }
46
- export interface GetRecommendedProductSizeResponse {
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.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",
@@ -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/events',
6
- development: 'https://data-event-service.internalsizebay.com/events',
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.example.com/production',
11
- development: 'https://ai-image-service.example.com/development',
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
- GetRecommendedProductSizeParams,
4
- GetRecommendedProductSizeResponse,
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 getRecommendedProductSize(
46
- payload: GetRecommendedProductSizeParams,
47
- ): Promise<GetRecommendedProductSizeResponse> {
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 GetRecommendedProductSizeResponse;
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
  }
@@ -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(this.endpoint, {
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?: string;
4
- sessionId?: number;
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 ProductRecommendedSize {
35
- permalink: string;
36
- analysisResponse: any | null;
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 GetRecommendedProductSizeResponse {
51
- [key: string]: string | number | boolean;
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
- GetRecommendedProductSizeParams,
6
- GetRecommendedProductSizeResponse,
5
+ GetRecommendedSizeByProductsParams,
6
+ GetRecommendedSizeByProductsResponse,
7
7
  } from '@src/types/ai-image-service.types';
8
8
 
9
9
  describe('AIImageService', () => {
10
- // Use a valid base URL for constructing request URLs.
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
- // Reinitialize the fake configuration for each test.
16
+
17
17
  fakeConfig = {
18
18
  getEndpoint: (serviceName: string) => fakeEndpoint,
19
19
  };
20
- // Cast fakeConfig as any to bypass missing properties required by Config.
20
+
21
21
  aiImageService = new AIImageService(fakeConfig as any);
22
22
  });
23
23
 
24
24
  afterEach(() => {
25
- // Reset global.fetch if it was set.
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('getRecommendedProductSize', () => {
133
+ describe('getRecommendedSizeByProducts', () => {
135
134
  it('should send the POST request with the correct payload and return the JSON response', async () => {
136
- const fakeResponseData: GetRecommendedProductSizeResponse = {
137
- recommendedSize: 'M',
138
- someOtherKey: 123,
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: GetRecommendedProductSizeParams = {
149
- products: [
150
- {
151
- permalink: 'https://example.com/product/1',
152
- analysisResponse: null,
153
- productInfo: null,
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.getRecommendedProductSize(payload);
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: GetRecommendedProductSizeParams = {
187
- products: [
188
- {
189
- permalink: 'https://example.com/product/1',
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.getRecommendedProductSize(payload),
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: GetRecommendedProductSizeParams = {
212
- products: [
213
- {
214
- permalink: 'https://example.com/product/1',
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.getRecommendedProductSize(payload),
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.resetAllMocks();
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
- expect(global.fetch).toHaveBeenCalledWith(fakeEndpoint, {
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,