@hellena-sdk/hellena 1.0.7 → 1.0.8

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/README.md CHANGED
@@ -197,7 +197,8 @@ Consulta [Pagamentos](docs/payments.md) para os parâmetros e o formato de respo
197
197
  | `hellena.product` | Listar, pesquisar e consultar produtos. |
198
198
  | `hellena.order` | Criar encomendas, renovar o ID de transação, calcular portes e descontos de cupões. |
199
199
  | `hellena.comment` | Consultar, criar, atualizar e eliminar comentários. |
200
- | `hellena.rating` | Consultar resumos e avaliações, criar ou eliminar avaliações. |
200
+ | `hellena.rating` | Consultar resumos completos, listar, criar e eliminar avaliações. |
201
+ | `hellena.category` | Listar categorias e consultar os produtos associados a cada categoria. |
201
202
  | `hellena.payment` | Consultar métodos de pagamento e criar pagamentos WiPay suportados. |
202
203
  | `hellena.organization` | Consultar informações da organização e links sociais. |
203
204
  | `hellena.sendRestRequest()` | Fazer pedidos REST a endpoints que ainda não têm método dedicado. |
@@ -275,7 +276,8 @@ A documentação detalhada e os exemplos por recurso estão em [`docs/README.md`
275
276
  | [Produtos](docs/products.md) | Listagem, pesquisa e detalhe |
276
277
  | [Encomendas](docs/orders.md) | Checkout, entrega, cupões e transações |
277
278
  | [Comentários](docs/comments.md) | Consulta e gestão de comentários |
278
- | [Avaliações](docs/ratings.md) | Resumos e gestão de avaliações |
279
+ | [Avaliações](docs/ratings.md) | Resumos, distribuição por estrelas e gestão de avaliações |
280
+ | [Categorias](docs/categories.md) | Listagem de categorias e produtos associados |
279
281
  | [Pagamentos](docs/payments.md) | Métodos de pagamento e WiPay |
280
282
  | [Organização](docs/organization.md) | Dados da organização e links sociais |
281
283
  | [REST, GraphQL e erros](docs/rest-graphql-errors.md) | Transporte genérico e tratamento de erros |
package/dist/main.d.ts CHANGED
@@ -6,6 +6,7 @@ export declare class HellenaClient extends HellenaConnect {
6
6
  readonly comment: import("./resources/comment/comment.feature").CommentFeature;
7
7
  readonly rating: import("./resources/rating/rating.feature").RatingFeature;
8
8
  readonly payment: import("./resources/payment/payment.feature").PaymentFeature;
9
+ readonly category: import("./resources/category/category.feature").CategoryFeature;
9
10
  constructor(apiKey: string, options?: HellenaClientOptions);
10
11
  }
11
12
  export { HellenaAPIError, type HellenaClientOptions, type HellenaRequestOptions } from "./core/HellenaConnect";
@@ -15,3 +16,4 @@ export * from "./resources/comment/dto/comment.dto";
15
16
  export * from "./resources/rating/dto/rating.dto";
16
17
  export * from "./resources/payment/dto/payment.dto";
17
18
  export * from "./resources/organization/dto/organization.dto";
19
+ export * from "./resources/category/dto/category.dto";
package/dist/main.js CHANGED
@@ -153,15 +153,38 @@ class ProductService {
153
153
  this.connect = connect;
154
154
  }
155
155
  getAllProducts(params = {}) {
156
- return this.connect.sendRestRequest("products/all", { query: { page: params.page, limit: params.limit } });
156
+ return this.connect.sendRestRequest("products/all", { query: this.toQuery(params) });
157
157
  }
158
158
  searchProducts(params) {
159
- const { ref, ...pagination } = params;
160
- return this.connect.sendRestRequest("products/search", { query: { ref, ...pagination } });
159
+ const { ref, ...filters } = params;
160
+ return this.connect.sendRestRequest("products/search", {
161
+ query: { ...this.toQuery(filters), ...ref ? { ref } : {} }
162
+ });
161
163
  }
162
164
  getProductById(id) {
163
165
  return this.connect.sendRestRequest(`products/${encodeURIComponent(id)}`);
164
166
  }
167
+ toQuery(params) {
168
+ const list = (value) => Array.isArray(value) ? value.join(",") : value;
169
+ return {
170
+ page: params.page,
171
+ limit: params.limit,
172
+ q: params.q,
173
+ category: params.category,
174
+ color: list(params.color),
175
+ brand: params.brand,
176
+ model: list(params.model),
177
+ material: list(params.material),
178
+ size: list(params.size),
179
+ tags: list(params.tags),
180
+ gender: list(params.gender),
181
+ minPrice: params.minPrice,
182
+ maxPrice: params.maxPrice,
183
+ inStock: params.inStock,
184
+ sortBy: params.sortBy,
185
+ sortOrder: params.sortOrder
186
+ };
187
+ }
165
188
  }
166
189
 
167
190
  // src/resources/product/product.feature.ts
@@ -171,13 +194,33 @@ class ProductFeature {
171
194
  this.service = service;
172
195
  }
173
196
  listProducts(params = {}) {
197
+ this.validatePriceRange(params);
174
198
  return this.service.getAllProducts(params);
175
199
  }
176
- searchProducts(params) {
200
+ filterProducts(filters = {}) {
201
+ return this.listProducts(filters);
202
+ }
203
+ searchProducts(params = {}) {
204
+ this.validatePriceRange(params);
177
205
  return this.service.searchProducts(params);
178
206
  }
179
207
  getProductByIdOrSlug(id) {
180
- return this.service.getProductById(id);
208
+ if (!id?.trim()) {
209
+ throw new Error("O ID ou slug do produto é obrigatório.");
210
+ }
211
+ return this.service.getProductById(id.trim());
212
+ }
213
+ validatePriceRange(params) {
214
+ const { minPrice, maxPrice } = params;
215
+ if (minPrice !== undefined && (!Number.isFinite(minPrice) || minPrice < 0)) {
216
+ throw new Error("minPrice deve ser um número maior ou igual a zero.");
217
+ }
218
+ if (maxPrice !== undefined && (!Number.isFinite(maxPrice) || maxPrice < 0)) {
219
+ throw new Error("maxPrice deve ser um número maior ou igual a zero.");
220
+ }
221
+ if (minPrice !== undefined && maxPrice !== undefined && minPrice > maxPrice) {
222
+ throw new Error("minPrice não pode ser superior a maxPrice.");
223
+ }
181
224
  }
182
225
  }
183
226
 
@@ -292,8 +335,11 @@ class RatingFeature {
292
335
  constructor(service) {
293
336
  this.service = service;
294
337
  }
295
- getProductRatingSummary(stockId) {
296
- return this.service.summary(stockId);
338
+ getProductRatingSummary(stockId, params = {}) {
339
+ return this.service.summary(stockId, params);
340
+ }
341
+ listProductRatings(params) {
342
+ return this.service.findMany(params);
297
343
  }
298
344
  getCustomerProductRating(params) {
299
345
  return this.service.findOne(params);
@@ -312,17 +358,21 @@ class RatingService {
312
358
  constructor(connect) {
313
359
  this.connect = connect;
314
360
  }
315
- summary(stockId) {
316
- return this.connect.sendRestRequest(`ratings/products/${encodeURIComponent(stockId)}/summary`);
361
+ summary(stockId, params = {}) {
362
+ return this.connect.sendRestRequest(`rating/products/${encodeURIComponent(stockId)}/summary`, { query: params });
363
+ }
364
+ findMany(params) {
365
+ const { stockId, ...pagination } = params;
366
+ return this.connect.sendRestRequest(`rating/products/${encodeURIComponent(stockId)}/ratings`, { query: pagination });
317
367
  }
318
368
  findOne(params) {
319
- return this.connect.sendRestRequest(`ratings/products/${encodeURIComponent(params.stockId)}`, { query: { customerId: params.customerId } });
369
+ return this.connect.sendRestRequest(`rating/products/${encodeURIComponent(params.stockId)}`, { query: { customerId: params.customerId } });
320
370
  }
321
371
  create(data) {
322
- return this.connect.sendRestRequest("ratings", { method: "POST", body: data });
372
+ return this.connect.sendRestRequest("rating", { method: "POST", body: data });
323
373
  }
324
374
  delete(id) {
325
- return this.connect.sendRestRequest(`ratings/${encodeURIComponent(id)}`, { method: "DELETE" });
375
+ return this.connect.sendRestRequest(`rating/${encodeURIComponent(id)}`, { method: "DELETE" });
326
376
  }
327
377
  }
328
378
 
@@ -364,6 +414,42 @@ function PaymentModel(connect) {
364
414
  return new PaymentFeature(new PaymentService(connect));
365
415
  }
366
416
 
417
+ // src/resources/category/category.feature.ts
418
+ class CategoryFeature {
419
+ service;
420
+ constructor(service) {
421
+ this.service = service;
422
+ }
423
+ listCategories(params = {}) {
424
+ return this.service.findMany(params);
425
+ }
426
+ getCategoryByRef(params) {
427
+ return this.service.findOne(params);
428
+ }
429
+ }
430
+
431
+ // src/resources/category/service/category.ser.ts
432
+ class CategoryService {
433
+ connect;
434
+ constructor(connect) {
435
+ this.connect = connect;
436
+ }
437
+ findMany(params = {}) {
438
+ return this.connect.sendRestRequest("category", {
439
+ query: { page: params.page, limit: params.limit, search: params.search }
440
+ });
441
+ }
442
+ findOne(params) {
443
+ const { ref, ...pagination } = params;
444
+ return this.connect.sendRestRequest(`category/${encodeURIComponent(ref)}`, { query: pagination });
445
+ }
446
+ }
447
+
448
+ // src/resources/category/category.model.ts
449
+ function CategoryModel(connect) {
450
+ return new CategoryFeature(new CategoryService(connect));
451
+ }
452
+
367
453
  // src/main.ts
368
454
  class HellenaClient extends HellenaConnect {
369
455
  product = ProductModel(this);
@@ -372,6 +458,7 @@ class HellenaClient extends HellenaConnect {
372
458
  comment = CommentModel(this);
373
459
  rating = RatingModel(this);
374
460
  payment = PaymentModel(this);
461
+ category = CategoryModel(this);
375
462
  constructor(apiKey, options = {}) {
376
463
  super(apiKey, options);
377
464
  }
@@ -0,0 +1,10 @@
1
+ import type { CategoryListParams, CategoryProductsParams, CategoryWithProductsDTO, PaginatedCategoriesDTO } from "./dto/category.dto";
2
+ import type { CategoryService } from "./service/category.ser";
3
+ export declare class CategoryFeature {
4
+ private readonly service;
5
+ constructor(service: CategoryService);
6
+ /** Lista as categorias da organização com paginação e pesquisa opcional. */
7
+ listCategories(params?: CategoryListParams): Promise<PaginatedCategoriesDTO>;
8
+ /** Obtém uma categoria pelo ID ou identificador e os respetivos produtos paginados. */
9
+ getCategoryByRef(params: CategoryProductsParams): Promise<CategoryWithProductsDTO>;
10
+ }
@@ -0,0 +1,3 @@
1
+ import type { HellenaConnect } from "../../core/HellenaConnect";
2
+ import { CategoryFeature } from "./category.feature";
3
+ export declare function CategoryModel(connect: HellenaConnect): CategoryFeature;
@@ -0,0 +1,26 @@
1
+ import type { PaginatedResponse, ProductDTO, PaginationMeta } from "../../product/dto/product.dto";
2
+ export interface CategoryDTO {
3
+ id: string;
4
+ name: string;
5
+ category: string;
6
+ icon?: string | null;
7
+ image?: string | null;
8
+ organizationId?: string;
9
+ createdAt?: string;
10
+ updatedAt?: string;
11
+ }
12
+ export interface CategoryListParams {
13
+ page?: number;
14
+ limit?: number;
15
+ search?: string;
16
+ }
17
+ export interface CategoryProductsParams {
18
+ ref: string;
19
+ page?: number;
20
+ limit?: number;
21
+ }
22
+ export interface CategoryWithProductsDTO extends CategoryDTO {
23
+ products: ProductDTO[];
24
+ meta: PaginationMeta;
25
+ }
26
+ export type PaginatedCategoriesDTO = PaginatedResponse<CategoryDTO>;
@@ -0,0 +1,8 @@
1
+ import type { HellenaConnect } from "../../../core/HellenaConnect";
2
+ import type { CategoryListParams, CategoryProductsParams, CategoryWithProductsDTO, PaginatedCategoriesDTO } from "../dto/category.dto";
3
+ export declare class CategoryService {
4
+ private readonly connect;
5
+ constructor(connect: HellenaConnect);
6
+ findMany(params?: CategoryListParams): Promise<PaginatedCategoriesDTO>;
7
+ findOne(params: CategoryProductsParams): Promise<CategoryWithProductsDTO>;
8
+ }
@@ -3,6 +3,7 @@ export interface PriceDTO {
3
3
  quantity: number;
4
4
  price: number;
5
5
  priceType?: string;
6
+ isPromotion?: boolean;
6
7
  }
7
8
  export interface ProductVariantDTO {
8
9
  id: string;
@@ -19,7 +20,7 @@ export interface ProductVariantDTO {
19
20
  }
20
21
  export interface ProductDTO {
21
22
  id: string;
22
- slug?: string;
23
+ slug?: string | null;
23
24
  barcode: string | null;
24
25
  name: string;
25
26
  category: string | null;
@@ -30,13 +31,18 @@ export interface ProductDTO {
30
31
  image_sides: string[] | null;
31
32
  color: string[] | null;
32
33
  brand: string | null;
34
+ model?: string[] | null;
33
35
  material: string[] | null;
34
36
  size: string[] | null;
35
37
  tags: string[] | null;
38
+ gender?: string[] | null;
36
39
  prices: PriceDTO[];
37
40
  unit: string | null;
38
41
  unitsPerBox?: number | null;
39
42
  quantity: number;
43
+ averageRating?: number;
44
+ ratingCount?: number;
45
+ commentsCount?: number;
40
46
  variants?: ProductVariantDTO[];
41
47
  }
42
48
  export interface PaginationMeta {
@@ -54,7 +60,21 @@ export interface PaginatedResponse<T> {
54
60
  export interface ProductListParams {
55
61
  page?: number;
56
62
  limit?: number;
63
+ q?: string;
64
+ category?: string;
65
+ color?: string | string[];
66
+ brand?: string;
67
+ model?: string | string[];
68
+ material?: string | string[];
69
+ size?: string | string[];
70
+ tags?: string | string[];
71
+ gender?: string | string[];
72
+ minPrice?: number;
73
+ maxPrice?: number;
74
+ inStock?: boolean;
75
+ sortBy?: "createdAt" | "updatedAt" | "name";
76
+ sortOrder?: "asc" | "desc";
57
77
  }
58
78
  export interface ProductSearchParams extends ProductListParams {
59
- ref: string;
79
+ ref?: string;
60
80
  }
@@ -3,10 +3,30 @@ import type { ProductService } from "./service/product.ser";
3
3
  export declare class ProductFeature {
4
4
  private readonly service;
5
5
  constructor(service: ProductService);
6
- /** Lista produtos com paginação. */
6
+ /**
7
+ * Lista produtos com paginação e filtros combináveis.
8
+ *
9
+ * Filtros suportados:
10
+ * - q: pesquisa textual;
11
+ * - minPrice / maxPrice: intervalo de preços;
12
+ * - category, brand: categoria e marca;
13
+ * - color, model, material, size, tags e gender: valor único ou lista;
14
+ * - inStock: disponibilidade em stock;
15
+ * - sortBy / sortOrder: ordenação dos resultados.
16
+ */
7
17
  listProducts(params?: ProductListParams): Promise<PaginatedResponse<ProductDTO>>;
8
- /** Pesquisa produtos por ID, slug, nome, código de barras, categoria, marca ou descrição. */
9
- searchProducts(params: ProductSearchParams): Promise<PaginatedResponse<ProductDTO>>;
18
+ /**
19
+ * Filtra produtos sem exigir um termo de pesquisa.
20
+ * É um método explícito equivalente a listProducts, útil para interfaces de catálogo.
21
+ */
22
+ filterProducts(filters?: ProductListParams): Promise<PaginatedResponse<ProductDTO>>;
23
+ /**
24
+ * Pesquisa produtos por texto (ref ou q) e combina a pesquisa com os restantes filtros.
25
+ * Aceita os mesmos filtros de listProducts, incluindo intervalo de preço, categoria,
26
+ * cor, marca, modelo, material, tamanho, tags, género e disponibilidade.
27
+ */
28
+ searchProducts(params?: ProductSearchParams): Promise<PaginatedResponse<ProductDTO>>;
10
29
  /** Obtém os detalhes de um produto através do ID ou slug. */
11
30
  getProductByIdOrSlug(id: string): Promise<ProductDTO>;
31
+ private validatePriceRange;
12
32
  }
@@ -6,4 +6,5 @@ export declare class ProductService {
6
6
  getAllProducts(params?: ProductListParams): Promise<PaginatedResponse<ProductDTO>>;
7
7
  searchProducts(params: ProductSearchParams): Promise<PaginatedResponse<ProductDTO>>;
8
8
  getProductById(id: string): Promise<ProductDTO>;
9
+ private toQuery;
9
10
  }
@@ -1,3 +1,4 @@
1
+ import type { PaginatedResponse } from "../../product/dto/product.dto";
1
2
  export interface RatingDTO {
2
3
  id: string;
3
4
  stockId: string;
@@ -17,9 +18,35 @@ export interface AddRatingDTO {
17
18
  customerName?: string;
18
19
  customerEmail?: string;
19
20
  }
20
- export interface RatingSummaryDTO {
21
- stockId: string;
21
+ export interface RatingProductDTO {
22
+ id: string;
23
+ name: string;
24
+ slug?: string | null;
25
+ image?: string | null;
26
+ brand?: string | null;
27
+ category?: string | null;
28
+ averageRating?: number;
29
+ ratingCount?: number;
30
+ commentsCount?: number;
31
+ }
32
+ export interface RatingDistributionDTO {
33
+ score: 1 | 2 | 3 | 4 | 5;
34
+ count: number;
35
+ percentage: number;
36
+ }
37
+ export interface RatingSummaryStatsDTO {
22
38
  averageRating: number;
23
- ratingCount: number;
39
+ totalRatings: number;
40
+ totalScore: number;
41
+ minScore: number | null;
42
+ maxScore: number | null;
24
43
  commentsCount: number;
44
+ distribution: RatingDistributionDTO[];
45
+ ratingLabel: string;
46
+ }
47
+ export interface RatingSummaryDTO {
48
+ product: RatingProductDTO;
49
+ summary: RatingSummaryStatsDTO;
50
+ ratings: PaginatedResponse<RatingDTO>;
25
51
  }
52
+ export type PaginatedRatingsDTO = PaginatedResponse<RatingDTO>;
@@ -1,19 +1,29 @@
1
- import type { AddRatingDTO, RatingDTO, RatingSummaryDTO } from "./dto/rating.dto";
1
+ import type { AddRatingDTO, PaginatedRatingsDTO, RatingDTO, RatingSummaryDTO } from "./dto/rating.dto";
2
2
  import type { RatingService } from "./service/rating.ser";
3
3
  export declare class RatingFeature {
4
4
  private readonly service;
5
5
  constructor(service: RatingService);
6
- /** Obtém a classificação média e as contagens de avaliações/comentários de um produto. */
7
- getProductRatingSummary(stockId: string): Promise<RatingSummaryDTO>;
6
+ /** Obtém a média, distribuição por estrelas, comentários e avaliações recentes de um produto. */
7
+ getProductRatingSummary(stockId: string, params?: {
8
+ page?: number;
9
+ limit?: number;
10
+ }): Promise<RatingSummaryDTO>;
11
+ /** Lista as avaliações de um produto com paginação. */
12
+ listProductRatings(params: {
13
+ stockId: string;
14
+ page?: number;
15
+ limit?: number;
16
+ }): Promise<PaginatedRatingsDTO>;
8
17
  /** Obtém a avaliação de um cliente para um produto, se existir. */
9
18
  getCustomerProductRating(params: {
10
19
  stockId: string;
11
20
  customerId: string;
12
21
  }): Promise<RatingDTO | null>;
13
- /** Regista uma avaliação de produto. */
22
+ /** Regista ou atualiza a avaliação de um cliente. */
14
23
  createProductRating(data: AddRatingDTO): Promise<RatingDTO>;
15
24
  /** Elimina uma avaliação pelo seu identificador. */
16
25
  deleteProductRating(id: string): Promise<{
17
26
  success: boolean;
27
+ id?: string;
18
28
  }>;
19
29
  }
@@ -1,9 +1,17 @@
1
1
  import type { HellenaConnect } from "../../../core/HellenaConnect";
2
- import type { AddRatingDTO, RatingDTO, RatingSummaryDTO } from "../dto/rating.dto";
2
+ import type { AddRatingDTO, PaginatedRatingsDTO, RatingDTO, RatingSummaryDTO } from "../dto/rating.dto";
3
3
  export declare class RatingService {
4
4
  private readonly connect;
5
5
  constructor(connect: HellenaConnect);
6
- summary(stockId: string): Promise<RatingSummaryDTO>;
6
+ summary(stockId: string, params?: {
7
+ page?: number;
8
+ limit?: number;
9
+ }): Promise<RatingSummaryDTO>;
10
+ findMany(params: {
11
+ stockId: string;
12
+ page?: number;
13
+ limit?: number;
14
+ }): Promise<PaginatedRatingsDTO>;
7
15
  findOne(params: {
8
16
  stockId: string;
9
17
  customerId: string;
@@ -11,5 +19,6 @@ export declare class RatingService {
11
19
  create(data: AddRatingDTO): Promise<RatingDTO>;
12
20
  delete(id: string): Promise<{
13
21
  success: boolean;
22
+ id?: string;
14
23
  }>;
15
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellena-sdk/hellena",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Official JavaScript SDK for the Hellena API",
5
5
  "license": "ISC",
6
6
  "author": "",