sizebay-core-sdk 1.0.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/.github/pull_request_template.md +24 -0
- package/.github/workflows/publish.yml +48 -0
- package/.github/workflows/tests-on-pr.yml +37 -0
- package/.prettierrc +7 -0
- package/.releaserc.json +32 -0
- package/CHANGELOG.md +13 -0
- package/README.dev.md +184 -0
- package/README.md +115 -0
- package/dist/sizebay-core-sdk.es.js +124 -0
- package/dist/sizebay-core-sdk.umd.js +1 -0
- package/dist/types/src/config/endpoints.d.ts +2 -0
- package/dist/types/src/config/index.d.ts +10 -0
- package/dist/types/src/core/client.d.ts +2 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/modules/ai-image-service.d.ts +8 -0
- package/dist/types/src/modules/index.d.ts +3 -0
- package/dist/types/src/modules/tracker.d.ts +7 -0
- package/dist/types/src/types/ai-image-service.types.d.ts +48 -0
- package/dist/types/src/types/client.types.d.ts +13 -0
- package/dist/types/src/types/event.types.d.ts +13 -0
- package/dist/types/src/types/index.d.ts +4 -0
- package/dist/types/src/types/sdk.types.d.ts +15 -0
- package/dist/types/test/config/config.test.d.ts +1 -0
- package/dist/types/test/core/client.test.d.ts +1 -0
- package/dist/types/test/example.d.ts +1 -0
- package/dist/types/test/index.test.d.ts +1 -0
- package/dist/types/test/jest.setup.d.ts +0 -0
- package/dist/types/test/modules/ai-image-service.test.d.ts +1 -0
- package/dist/types/test/modules/tracker.test.d.ts +1 -0
- package/jest.config.cjs +18 -0
- package/package.json +44 -0
- package/src/config/endpoints.ts +14 -0
- package/src/config/index.ts +42 -0
- package/src/core/client.ts +26 -0
- package/src/index.ts +2 -0
- package/src/modules/ai-image-service.ts +68 -0
- package/src/modules/index.ts +7 -0
- package/src/modules/tracker.ts +37 -0
- package/src/types/ai-image-service.types.ts +52 -0
- package/src/types/client.types.ts +30 -0
- package/src/types/event.types.ts +28 -0
- package/src/types/index.ts +4 -0
- package/src/types/sdk.types.ts +17 -0
- package/test/config/config.test.ts +59 -0
- package/test/core/client.test.ts +32 -0
- package/test/example.ts +53 -0
- package/test/index.test.ts +12 -0
- package/test/jest.setup.ts +8 -0
- package/test/modules/ai-image-service.test.ts +234 -0
- package/test/modules/tracker.test.ts +86 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +27 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface GetSimilarProductsParams {
|
|
2
|
+
tenantId: number;
|
|
3
|
+
collectionName?: string;
|
|
4
|
+
sessionId?: number;
|
|
5
|
+
permalink: string;
|
|
6
|
+
page?: number;
|
|
7
|
+
perPage?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface Product {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
productType: string;
|
|
13
|
+
link: string;
|
|
14
|
+
imageLink: string;
|
|
15
|
+
gender: string;
|
|
16
|
+
availability: string;
|
|
17
|
+
productHash: string;
|
|
18
|
+
price: string;
|
|
19
|
+
salePrice?: string;
|
|
20
|
+
itemGroupId: string;
|
|
21
|
+
brand: string;
|
|
22
|
+
color: string;
|
|
23
|
+
gtin: string;
|
|
24
|
+
additionalImageLinks: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface GetSimilarProductsResponse {
|
|
27
|
+
data: Product[];
|
|
28
|
+
page: number;
|
|
29
|
+
perPage: number;
|
|
30
|
+
total: number;
|
|
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;
|
|
41
|
+
sizeSystem: string;
|
|
42
|
+
}
|
|
43
|
+
export interface GetRecommendedProductSizeParams {
|
|
44
|
+
products: ProductRecommendedSize[];
|
|
45
|
+
}
|
|
46
|
+
export interface GetRecommendedProductSizeResponse {
|
|
47
|
+
[key: string]: string | number | boolean;
|
|
48
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Config } from '../config';
|
|
2
|
+
import { moduleClasses } from '../modules';
|
|
3
|
+
type InstanceTypeOfClass<T> = T extends new (...args: any[]) => infer R ? R : never;
|
|
4
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => any : never) extends (x: infer I) => any ? I : never;
|
|
5
|
+
export type PublicAPI<T> = {
|
|
6
|
+
[K in keyof T as T[K] extends Function ? K : never]: T[K];
|
|
7
|
+
};
|
|
8
|
+
type ModulesUnion = PublicAPI<InstanceTypeOfClass<(typeof moduleClasses)[number]>>;
|
|
9
|
+
type ModulesIntersection = UnionToIntersection<ModulesUnion>;
|
|
10
|
+
export type ClientType = {
|
|
11
|
+
config: Config;
|
|
12
|
+
} & ModulesIntersection;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type JSONValue = string | number | boolean | null | JSONValue[] | {
|
|
2
|
+
[key: string]: JSONValue;
|
|
3
|
+
};
|
|
4
|
+
export interface TrackData {
|
|
5
|
+
sid: string;
|
|
6
|
+
tenantId: number;
|
|
7
|
+
sessionId: number;
|
|
8
|
+
permalink?: string;
|
|
9
|
+
properties: Record<string, JSONValue>;
|
|
10
|
+
}
|
|
11
|
+
export interface DataEventPayload extends TrackData {
|
|
12
|
+
eventName: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SDKConfigOptions {
|
|
2
|
+
env?: 'development' | 'production';
|
|
3
|
+
globalOptions?: {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
};
|
|
6
|
+
services?: {
|
|
7
|
+
[serviceName: string]: {
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface EndpointDefinition {
|
|
13
|
+
production: string;
|
|
14
|
+
development: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { pathsToModuleNameMapper } = require('ts-jest');
|
|
2
|
+
const { compilerOptions } = require('./tsconfig.json');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
preset: 'ts-jest',
|
|
7
|
+
testEnvironment: 'node',
|
|
8
|
+
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
|
|
9
|
+
transform: {
|
|
10
|
+
'^.+\\.ts$': 'ts-jest',
|
|
11
|
+
},
|
|
12
|
+
testMatch: ['**/test/**/*.test.ts'], // Garante que os testes sejam encontrados corretamente
|
|
13
|
+
collectCoverage: true,
|
|
14
|
+
coverageDirectory: 'coverage',
|
|
15
|
+
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
|
|
16
|
+
setupFilesAfterEnv: ["<rootDir>/test/jest.setup.ts"],
|
|
17
|
+
roots: ['<rootDir>/src', '<rootDir>/test'], // Define onde os arquivos de teste podem ser encontrados
|
|
18
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sizebay-core-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A SDK designed for integrating multiple services (such as event tracking, AI services, etc.) into your application.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"release": "semantic-release",
|
|
10
|
+
"build": "vite build",
|
|
11
|
+
"prepublishOnly": "npm run build",
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"test:ci": "jest --ci",
|
|
14
|
+
"test:dev": "ts-node -r tsconfig-paths/register test/example.ts"
|
|
15
|
+
},
|
|
16
|
+
"author": "sizebay",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"events",
|
|
20
|
+
"sdk",
|
|
21
|
+
"sizebay",
|
|
22
|
+
"tracking"
|
|
23
|
+
],
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
26
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
27
|
+
"@semantic-release/git": "^10.0.1",
|
|
28
|
+
"@semantic-release/npm": "^12.0.1",
|
|
29
|
+
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
30
|
+
"@types/jest": "^29.5.14",
|
|
31
|
+
"@types/node-fetch": "^2.6.12",
|
|
32
|
+
"conventional-changelog-conventionalcommits": "^8.0.0",
|
|
33
|
+
"jest": "^29.7.0",
|
|
34
|
+
"prettier": "^3.0.0",
|
|
35
|
+
"semantic-release": "^24.2.1",
|
|
36
|
+
"ts-jest": "^29.2.5",
|
|
37
|
+
"ts-node": "^10.9.2",
|
|
38
|
+
"tsconfig-paths": "^4.2.0",
|
|
39
|
+
"typescript": "^5.7.3",
|
|
40
|
+
"vite": "^6.0.11",
|
|
41
|
+
"vite-plugin-dts": "^4.5.0",
|
|
42
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EndpointDefinition } from "@src/types";
|
|
2
|
+
|
|
3
|
+
export const endpoints: Record<string, EndpointDefinition> = {
|
|
4
|
+
tracker: {
|
|
5
|
+
production: 'https://data-event-service.internalsizebay.com/events',
|
|
6
|
+
development: 'https://data-event-service.internalsizebay.com/events',
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
aiImageService: {
|
|
10
|
+
production: 'https://ai-image-service.example.com/production',
|
|
11
|
+
development: 'https://ai-image-service.example.com/development',
|
|
12
|
+
},
|
|
13
|
+
// Adicione outros serviços conforme necessário
|
|
14
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SDKConfigOptions } from '@src/types';
|
|
2
|
+
import { endpoints } from './endpoints';
|
|
3
|
+
import { EndpointDefinition } from '@src/types';
|
|
4
|
+
|
|
5
|
+
export class Config {
|
|
6
|
+
private endpoints: Record<string, string>;
|
|
7
|
+
private serviceOverrides: { [service: string]: { [key: string]: any } };
|
|
8
|
+
|
|
9
|
+
constructor(options: SDKConfigOptions) {
|
|
10
|
+
const env = options.env || 'development';
|
|
11
|
+
this.serviceOverrides = options.services || {};
|
|
12
|
+
|
|
13
|
+
this.endpoints = {};
|
|
14
|
+
|
|
15
|
+
for (const service in endpoints) {
|
|
16
|
+
if (Object.prototype.hasOwnProperty.call(endpoints, service)) {
|
|
17
|
+
const endpointDefinition = endpoints[service];
|
|
18
|
+
const endpoint = endpointDefinition[env as keyof EndpointDefinition];
|
|
19
|
+
|
|
20
|
+
if (!endpoint) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.endpoints[service] = endpoint;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getEndpoint(serviceName: string): string {
|
|
30
|
+
const endpoint = this.endpoints[serviceName];
|
|
31
|
+
if (!endpoint) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Endpoint for service '${serviceName}' is not configured.`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return endpoint;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getServiceConfig(serviceName: string): { [key: string]: any } {
|
|
40
|
+
return this.serviceOverrides[serviceName] || {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Config } from '@src/config';
|
|
2
|
+
import { moduleClasses } from '@src/modules';
|
|
3
|
+
import { ClientType, SDKConfigOptions } from '@src/types';
|
|
4
|
+
|
|
5
|
+
export function createClient(options: SDKConfigOptions): ClientType {
|
|
6
|
+
const config = new Config(options);
|
|
7
|
+
const modules = moduleClasses.map((ModuleClass) => new ModuleClass(config));
|
|
8
|
+
const client: any = { config };
|
|
9
|
+
|
|
10
|
+
modules.forEach((moduleInstance) => {
|
|
11
|
+
Object.getOwnPropertyNames(moduleInstance).forEach((key) => {
|
|
12
|
+
if (typeof moduleInstance[key] === 'function') {
|
|
13
|
+
client[key] = moduleInstance[key].bind(moduleInstance);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const prototype = Object.getPrototypeOf(moduleInstance);
|
|
18
|
+
Object.getOwnPropertyNames(prototype).forEach((key) => {
|
|
19
|
+
if (key !== 'constructor' && typeof moduleInstance[key] === 'function') {
|
|
20
|
+
client[key] = moduleInstance[key].bind(moduleInstance);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return client as ClientType;
|
|
26
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Config } from '@src/config';
|
|
2
|
+
import {
|
|
3
|
+
GetRecommendedProductSizeParams,
|
|
4
|
+
GetRecommendedProductSizeResponse,
|
|
5
|
+
GetSimilarProductsParams,
|
|
6
|
+
GetSimilarProductsResponse,
|
|
7
|
+
} from '@src/types/ai-image-service.types';
|
|
8
|
+
|
|
9
|
+
export class AIImageService {
|
|
10
|
+
private endpoint: string;
|
|
11
|
+
|
|
12
|
+
constructor(config: Config) {
|
|
13
|
+
this.endpoint = config.getEndpoint('aiImageService');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async getSimilarProducts(
|
|
17
|
+
params: GetSimilarProductsParams,
|
|
18
|
+
): Promise<GetSimilarProductsResponse> {
|
|
19
|
+
const url = new URL(`${this.endpoint}/recommendations/similar`);
|
|
20
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
21
|
+
if (value !== undefined) {
|
|
22
|
+
url.searchParams.append(key, String(value));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(url.toString(), {
|
|
28
|
+
method: 'GET',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
const errorText = await response.text();
|
|
36
|
+
throw new Error(`Request error: ${response.status} - ${errorText}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (await response.json()) as GetSimilarProductsResponse;
|
|
40
|
+
} catch (error: any) {
|
|
41
|
+
throw new Error(`Error fetching similar products: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async getRecommendedProductSize(
|
|
46
|
+
payload: GetRecommendedProductSizeParams,
|
|
47
|
+
): Promise<GetRecommendedProductSizeResponse> {
|
|
48
|
+
const url = new URL(`${this.endpoint}/recommendations/size-by-products`);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetch(url.toString(), {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(payload),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorText = await response.text();
|
|
61
|
+
throw new Error(`Request error: ${response.status} - ${errorText}`);
|
|
62
|
+
}
|
|
63
|
+
return (await response.json()) as GetRecommendedProductSizeResponse;
|
|
64
|
+
} catch (error: any) {
|
|
65
|
+
throw new Error(`Error fetching recommended product size: ${error.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DataEventPayload, TrackData } from "../types";
|
|
2
|
+
import { Config } from "../config";
|
|
3
|
+
|
|
4
|
+
export class Tracker {
|
|
5
|
+
|
|
6
|
+
private endpoint: string;
|
|
7
|
+
|
|
8
|
+
constructor(config: Config) {
|
|
9
|
+
// Define "config" como não enumerável
|
|
10
|
+
|
|
11
|
+
this.endpoint = config.getEndpoint('tracker');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async track(eventName: string, payload: TrackData): Promise<any> {
|
|
15
|
+
const data: DataEventPayload = {
|
|
16
|
+
eventName,
|
|
17
|
+
...payload,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(this.endpoint, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: { "Content-Type": "application/json" },
|
|
24
|
+
body: JSON.stringify(data),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const errorText = await response.text();
|
|
29
|
+
throw new Error(`Request error: ${response.status} - ${errorText}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return await response.json();
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface GetSimilarProductsParams {
|
|
2
|
+
tenantId: number;
|
|
3
|
+
collectionName?: string;
|
|
4
|
+
sessionId?: number;
|
|
5
|
+
permalink: string;
|
|
6
|
+
page?: number;
|
|
7
|
+
perPage?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface Product {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
productType: string;
|
|
13
|
+
link: string;
|
|
14
|
+
imageLink: string;
|
|
15
|
+
gender: string;
|
|
16
|
+
availability: string;
|
|
17
|
+
productHash: string;
|
|
18
|
+
price: string;
|
|
19
|
+
salePrice?: string;
|
|
20
|
+
itemGroupId: string;
|
|
21
|
+
brand: string;
|
|
22
|
+
color: string;
|
|
23
|
+
gtin: string;
|
|
24
|
+
additionalImageLinks: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface GetSimilarProductsResponse {
|
|
28
|
+
data: Product[];
|
|
29
|
+
page: number;
|
|
30
|
+
perPage: number;
|
|
31
|
+
total: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
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;
|
|
43
|
+
sizeSystem: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GetRecommendedProductSizeParams {
|
|
47
|
+
products: ProductRecommendedSize[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface GetRecommendedProductSizeResponse {
|
|
51
|
+
[key: string]: string | number | boolean;
|
|
52
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Config } from '@src/config';
|
|
2
|
+
import { moduleClasses } from '@src/modules';
|
|
3
|
+
|
|
4
|
+
type InstanceTypeOfClass<T> = T extends new (...args: any[]) => infer R
|
|
5
|
+
? R
|
|
6
|
+
: never;
|
|
7
|
+
|
|
8
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => any : never) extends (
|
|
9
|
+
x: infer I,
|
|
10
|
+
) => any
|
|
11
|
+
? I
|
|
12
|
+
: never;
|
|
13
|
+
|
|
14
|
+
// Helper que extrai apenas os métodos (funções) públicos do módulo
|
|
15
|
+
export type PublicAPI<T> = {
|
|
16
|
+
[K in keyof T as T[K] extends Function ? K : never]: T[K];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Cria uma união com os tipos dos módulos (apenas a API pública)
|
|
20
|
+
type ModulesUnion = PublicAPI<
|
|
21
|
+
InstanceTypeOfClass<(typeof moduleClasses)[number]>
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
// Converte a união em interseção
|
|
25
|
+
type ModulesIntersection = UnionToIntersection<ModulesUnion>;
|
|
26
|
+
|
|
27
|
+
// Define o tipo final do Client (expondo apenas a API pública dos módulos)
|
|
28
|
+
export type ClientType = {
|
|
29
|
+
config: Config;
|
|
30
|
+
} & ModulesIntersection;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents any valid JSON value.
|
|
3
|
+
*/
|
|
4
|
+
export type JSONValue =
|
|
5
|
+
| string
|
|
6
|
+
| number
|
|
7
|
+
| boolean
|
|
8
|
+
| null
|
|
9
|
+
| JSONValue[]
|
|
10
|
+
| { [key: string]: JSONValue };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Interface that defines the structure of a tracked event.
|
|
14
|
+
*/
|
|
15
|
+
export interface TrackData {
|
|
16
|
+
sid: string;
|
|
17
|
+
tenantId: number;
|
|
18
|
+
sessionId: number;
|
|
19
|
+
permalink?: string;
|
|
20
|
+
properties: Record<string, JSONValue>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Payload for the track event.
|
|
25
|
+
*/
|
|
26
|
+
export interface DataEventPayload extends TrackData {
|
|
27
|
+
eventName: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SDKConfigOptions {
|
|
2
|
+
env?: 'development' | 'production';
|
|
3
|
+
|
|
4
|
+
globalOptions?: {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
services?: {
|
|
9
|
+
[serviceName: string]: {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface EndpointDefinition {
|
|
15
|
+
production: string;
|
|
16
|
+
development: string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Config } from "@src/config";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
jest.mock('@src/config/endpoints', () => ({
|
|
5
|
+
endpoints: {
|
|
6
|
+
serviceA: {
|
|
7
|
+
development: "http://localhost:3000",
|
|
8
|
+
production: "https://api.example.com",
|
|
9
|
+
},
|
|
10
|
+
serviceB: {
|
|
11
|
+
development: "http://localhost:3001",
|
|
12
|
+
production: "https://api2.example.com",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe('Config', () => {
|
|
18
|
+
describe('getEndpoint', () => {
|
|
19
|
+
it('should return the service endpoint for the default environment (development)', () => {
|
|
20
|
+
const options = { env: 'development', services: {} } as const;
|
|
21
|
+
const config = new Config(options);
|
|
22
|
+
expect(config.getEndpoint('serviceA')).toBe("http://localhost:3000");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return the service endpoint for the production environment', () => {
|
|
26
|
+
const options = { env: 'production', services: {} } as const;
|
|
27
|
+
const config = new Config(options);
|
|
28
|
+
expect(config.getEndpoint('serviceB')).toBe("https://api2.example.com");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should throw an error if the service endpoint is not configured", () => {
|
|
32
|
+
const options = { env: 'development', services: {} } as const;
|
|
33
|
+
const config = new Config(options);
|
|
34
|
+
expect(() => config.getEndpoint('nonExistingService')).toThrowError(
|
|
35
|
+
"Endpoint for service 'nonExistingService' is not configured."
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('getServiceConfig', () => {
|
|
42
|
+
it('should return the service configuration if it exists', () => {
|
|
43
|
+
const options = {
|
|
44
|
+
env: 'development',
|
|
45
|
+
services: {
|
|
46
|
+
serviceA: { someKey: 'someValue' },
|
|
47
|
+
},
|
|
48
|
+
} as const;
|
|
49
|
+
const config = new Config(options);
|
|
50
|
+
expect(config.getServiceConfig('serviceA')).toEqual({ someKey: 'someValue' });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return an empty object if the service configuration does not exist', () => {
|
|
54
|
+
const options = { env: 'development', services: {} } as const;
|
|
55
|
+
const config = new Config(options);
|
|
56
|
+
expect(config.getServiceConfig('nonExistingService')).toEqual({});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { moduleClasses } from '@src/modules';
|
|
2
|
+
|
|
3
|
+
import { SDKConfigOptions } from '@src/types';
|
|
4
|
+
import { createClient } from '@src/index';
|
|
5
|
+
|
|
6
|
+
describe('createClient', () => {
|
|
7
|
+
const options: SDKConfigOptions = {
|
|
8
|
+
env: 'development',
|
|
9
|
+
globalOptions: { key: 'value' },
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const client = createClient(options);
|
|
13
|
+
|
|
14
|
+
it('should instantiate each module listed in moduleClasses and add its methods to the client', () => {
|
|
15
|
+
moduleClasses.forEach((ModuleClass) => {
|
|
16
|
+
const instance = new ModuleClass(client.config);
|
|
17
|
+
|
|
18
|
+
Object.getOwnPropertyNames(instance).forEach((prop) => {
|
|
19
|
+
if (typeof instance[prop] === 'function') {
|
|
20
|
+
expect(typeof client[prop]).toBe('function');
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const proto = Object.getPrototypeOf(instance);
|
|
25
|
+
Object.getOwnPropertyNames(proto).forEach((prop) => {
|
|
26
|
+
if (prop !== 'constructor' && typeof instance[prop] === 'function') {
|
|
27
|
+
expect(typeof client[prop]).toBe('function');
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
package/test/example.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createClient } from '@src/core/client';
|
|
2
|
+
|
|
3
|
+
/*async function main() {
|
|
4
|
+
const client = createClient({ env: 'development'});
|
|
5
|
+
|
|
6
|
+
const payload = {
|
|
7
|
+
sid: 'a0cf8559-926a-4a75-b4ca-7c4c13fed69c',
|
|
8
|
+
tenantId: 123,
|
|
9
|
+
eventName: 'ADD_TO_CART',
|
|
10
|
+
sessionId: 123,
|
|
11
|
+
permalink: 'https://www.example.com/2IC-7370',
|
|
12
|
+
properties: {
|
|
13
|
+
quantity: 1,
|
|
14
|
+
device: 'APP',
|
|
15
|
+
country: 'BR',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const result = await client.track('samuel', payload);
|
|
21
|
+
console.log('Resposta 200 do endpoint:', result);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Erro ao enviar o evento:', error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
async function main() {
|
|
30
|
+
// Cria o client com a configuração desejada
|
|
31
|
+
const client = createClient({ env: 'development' });
|
|
32
|
+
|
|
33
|
+
// Define os parâmetros para buscar produtos similares, conforme a tipagem
|
|
34
|
+
const params = {
|
|
35
|
+
tenantId: 123,
|
|
36
|
+
permalink: 'https://www.example.com/produto-exemplo',
|
|
37
|
+
collectionName: 'colecao-exemplo', // opcional
|
|
38
|
+
sessionId: 456, // opcional
|
|
39
|
+
page: 1, // opcional
|
|
40
|
+
perPage: 10 // opcional
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// Chama o método do módulo AIImageService
|
|
45
|
+
const result = await client.getSimilarProducts(params);
|
|
46
|
+
console.log('Resposta 200 do endpoint AIImageService:', result);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('Erro ao buscar produtos similares:', error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
main();
|