@viu/emporix-sdk 2.6.0 → 2.7.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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @viu/emporix-sdk
2
2
 
3
+ ## 2.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#96](https://github.com/viuteam/emporix-sdk/pull/96) [`da1113a`](https://github.com/viuteam/emporix-sdk/commit/da1113a07f70dceb9f1cb732b28462ccb3671f4a) Thanks [@amnael1](https://github.com/amnael1)! - Fix and extend the Category service for catalogue + hierarchy browsing. Several
8
+ methods targeted routes that don't exist on the deployed category service
9
+ (verified against a live tenant):
10
+ - **`categories.productsIn(...)`** requested a non-existent
11
+ `/categories/{id}/products` route (always 404). It now resolves products via
12
+ category **assignments** (`/categories/{id}/assignments` → keep `PRODUCT`
13
+ refs → `/products/search`), preserving its `PaginatedItems<Product>` contract;
14
+ categories with no products return an empty page instead of throwing.
15
+ - **`categories.tree()`** pointed at a non-existent `/categories/{...}Tree`
16
+ route. It now reads `/category-trees` and returns the catalogue's **root
17
+ categories** (`Promise<Category[]>`) for top-level navigation. (Return type
18
+ changed from the previous nested-node shape; the `rootId` argument is removed.)
19
+ - **New `categories.subcategories(categoryId)`** (+ React `useSubcategories`):
20
+ a category's direct child categories, resolved from `CATEGORY` assignment refs
21
+ (mirrors `productsIn`). Returns `[]` when there are none.
22
+
23
+ React `useCategoryTree()` now returns `Category[]` (root categories) and takes no
24
+ `rootId`.
25
+
3
26
  ## 2.6.0
4
27
 
5
28
  ### Minor Changes
package/dist/category.cjs CHANGED
@@ -43,26 +43,67 @@ var CategoryService = class {
43
43
  const pageSize = params.pageSize ?? 50;
44
44
  return iterateAll((pageNumber) => this.list({ pageNumber, pageSize }, auth));
45
45
  }
46
- /** Fetches the category tree, optionally rooted at `rootId`. */
47
- async tree(rootId, auth = ANON) {
46
+ /**
47
+ * The catalogue's **root categories** — the published category trees
48
+ * (`GET /category-trees`). Use these for top-level storefront navigation;
49
+ * drill into a node's children with {@link subcategories}.
50
+ */
51
+ async tree(auth = ANON) {
48
52
  return this.ctx.http.request({
49
53
  method: "GET",
50
- path: `/category/${this.ctx.tenant}/categories/tree`,
51
- query: rootId ? { rootId } : {},
54
+ path: `/category/${this.ctx.tenant}/category-trees`,
55
+ auth
56
+ });
57
+ }
58
+ /**
59
+ * Direct child categories of a category (for hierarchy drill-down). Mirrors
60
+ * {@link productsIn}: reads the category's **assignments** and keeps the
61
+ * `CATEGORY` references, resolving them to full categories. Returns an empty
62
+ * array when the category has no child categories.
63
+ */
64
+ async subcategories(categoryId, params = {}, auth = ANON) {
65
+ const pageNumber = params.pageNumber ?? 1;
66
+ const pageSize = params.pageSize ?? 50;
67
+ const assignments = await this.ctx.http.request({
68
+ method: "GET",
69
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
70
+ query: { pageNumber, pageSize },
52
71
  auth
53
72
  });
73
+ const categoryIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "CATEGORY" ? a.ref.id : void 0).filter((id) => Boolean(id));
74
+ if (categoryIds.length === 0) return [];
75
+ return this.searchByIds(categoryIds, {}, auth);
54
76
  }
55
- /** One page of products in a category. */
77
+ /**
78
+ * One page of products in a category. The category service exposes products
79
+ * as **assignments** (`/categories/{id}/assignments`) — references, not full
80
+ * products — so this fetches a page of assignments, keeps the `PRODUCT`
81
+ * references, and resolves them to full products via `/products/search`.
82
+ * `hasNextPage` reflects the assignments page (the source of truth for
83
+ * pagination).
84
+ */
56
85
  async productsIn(categoryId, params = {}, auth = ANON) {
57
86
  const pageNumber = params.pageNumber ?? 1;
58
87
  const pageSize = params.pageSize ?? 50;
59
- const items = await this.ctx.http.request({
88
+ const assignments = await this.ctx.http.request({
60
89
  method: "GET",
61
- path: `/category/${this.ctx.tenant}/categories/${categoryId}/products`,
90
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
62
91
  query: { pageNumber, pageSize },
63
92
  auth
64
93
  });
65
- return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
94
+ const hasNextPage = assignments.length === pageSize;
95
+ const productIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "PRODUCT" ? a.ref.id : void 0).filter((id) => Boolean(id));
96
+ if (productIds.length === 0) {
97
+ return { items: [], pageNumber, pageSize, hasNextPage };
98
+ }
99
+ const items = await this.ctx.http.request({
100
+ method: "POST",
101
+ path: `/product/${this.ctx.tenant}/products/search`,
102
+ query: { pageSize: productIds.length },
103
+ auth,
104
+ body: { q: `id:(${productIds.join(",")})` }
105
+ });
106
+ return { items, pageNumber, pageSize, hasNextPage };
66
107
  }
67
108
  /**
68
109
  * Bulk fetch by id. POSTs `/categories/search` with `q="id:(id1,id2,…)"`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/context.ts","../src/services/category.ts"],"names":[],"mappings":"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","file":"category.cjs","sourcesContent":["import type { HttpClient } from \"./http\";\nimport type { TokenProvider, AuthContext } from \"./auth\";\nimport type { Logger } from \"./logger\";\n\n/** Shared dependencies every service facade receives. */\nexport interface ClientContext {\n tenant: string;\n http: HttpClient;\n tokenProvider: TokenProvider;\n logger: Logger;\n}\n\n/**\n * A cursor-paged collection — `pageNumber`/`pageSize` indexing with a\n * `hasNextPage` signal driven by the source page being full. Used by all\n * paginated services and hooks across the SDK.\n */\nexport interface PaginatedItems<T> {\n items: T[];\n pageNumber: number;\n pageSize: number;\n hasNextPage: boolean;\n}\n\n/** Default `AuthContext` applied by a service when the caller passes none. */\nexport type DefaultAuth = AuthContext | undefined;\n\n/**\n * Async-iterates every item across pages of a `PaginatedItems<T>` source.\n * Stops when the source reports `hasNextPage: false`.\n *\n * @param fetchPage - given a 1-based page number, returns the page.\n * @param start - first page to fetch (default `1`).\n */\nexport async function* iterateAll<T>(\n fetchPage: (pageNumber: number) => Promise<PaginatedItems<T>>,\n start = 1,\n): AsyncIterable<T> {\n let p = start;\n for (;;) {\n const page = await fetchPage(p);\n for (const it of page.items) yield it;\n if (!page.hasNextPage) return;\n p += 1;\n }\n}\n\n","import type { ClientContext, PaginatedItems } from \"../core/context\";\nimport { iterateAll } from \"../core/context\";\nimport type { AuthContext } from \"../core/auth\";\nimport type { Product } from \"./product\";\nimport type { Category as GeneratedCategory, CategoryTree } from \"../generated/category\";\n\nconst ANON: AuthContext = { kind: \"anonymous\" };\n\n/** A category as returned by the Category service (all generated fields). */\nexport type Category = GeneratedCategory;\n\n/** The category tree as returned by the Category service. */\nexport type CategoryNode = CategoryTree;\n\n/** Category reads. Default auth: anonymous. */\nexport class CategoryService {\n constructor(private readonly ctx: ClientContext) {}\n\n /** Fetches one category by id. */\n async get(categoryId: string, auth: AuthContext = ANON): Promise<Category> {\n return this.ctx.http.request<Category>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}`,\n auth,\n });\n }\n\n /** One page of categories. */\n async list(\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Category>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const items = await this.ctx.http.request<Category[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories`,\n query: { pageNumber, pageSize },\n auth,\n });\n return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };\n }\n\n /** Async-iterates every category across pages. */\n listAll(params: { pageSize?: number } = {}, auth: AuthContext = ANON): AsyncIterable<Category> {\n const pageSize = params.pageSize ?? 50;\n return iterateAll<Category>((pageNumber) => this.list({ pageNumber, pageSize }, auth));\n }\n\n /** Fetches the category tree, optionally rooted at `rootId`. */\n async tree(rootId?: string, auth: AuthContext = ANON): Promise<CategoryNode> {\n return this.ctx.http.request<CategoryNode>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/tree`,\n query: rootId ? { rootId } : {},\n auth,\n });\n }\n\n /** One page of products in a category. */\n async productsIn(\n categoryId: string,\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Product>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const items = await this.ctx.http.request<Product[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}/products`,\n query: { pageNumber, pageSize },\n auth,\n });\n return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };\n }\n\n /**\n * Bulk fetch by id. POSTs `/categories/search` with `q=\"id:(id1,id2,…)\"`,\n * chunking when the list is larger than `options.chunkSize` (default\n * 100). An empty list short-circuits with no HTTP call. **Order is not\n * guaranteed** across chunks — re-index by `id` if order matters.\n */\n async searchByIds(\n ids: string[],\n options: { chunkSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<Category[]> {\n if (ids.length === 0) return [];\n const chunkSize = options.chunkSize ?? 100;\n const chunks: string[][] = [];\n for (let i = 0; i < ids.length; i += chunkSize) {\n chunks.push(ids.slice(i, i + chunkSize));\n }\n const pages = await Promise.all(\n chunks.map((chunk) =>\n this.ctx.http.request<Category[]>({\n method: \"POST\",\n path: `/category/${this.ctx.tenant}/categories/search`,\n query: { pageSize: chunk.length },\n auth,\n body: { q: `id:(${chunk.join(\",\")})` },\n }),\n ),\n );\n return pages.flat();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/core/context.ts","../src/services/category.ts"],"names":[],"mappings":";;;AAkCA,gBAAuB,UAAA,CACrB,SAAA,EACA,KAAA,GAAQ,CAAA,EACU;AAClB,EAAA,IAAI,CAAA,GAAI,KAAA;AACR,EAAA,WAAS;AACP,IAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,CAAC,CAAA;AAC9B,IAAA,KAAA,MAAW,EAAA,IAAM,IAAA,CAAK,KAAA,EAAO,MAAM,EAAA;AACnC,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACvB,IAAA,CAAA,IAAK,CAAA;AAAA,EACP;AACF;;;ACvCA,IAAM,IAAA,GAAoB,EAAE,IAAA,EAAM,WAAA,EAAY;AASvC,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,GAAA,EAAoB;AAApB,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAAA,EAAqB;AAAA,EAArB,GAAA;AAAA;AAAA,EAG7B,MAAM,GAAA,CAAI,UAAA,EAAoB,IAAA,GAAoB,IAAA,EAAyB;AACzE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,OAAA,CAAkB;AAAA,MACrC,MAAA,EAAQ,KAAA;AAAA,MACR,MAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,eAAe,UAAU,CAAA,CAAA;AAAA,MAC3D;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,IAAA,CACJ,MAAA,GAAqD,EAAC,EACtD,OAAoB,IAAA,EACe;AACnC,IAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,EAAA;AACpC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,OAAA,CAAoB;AAAA,MACpD,MAAA,EAAQ,KAAA;AAAA,MACR,IAAA,EAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,WAAA,CAAA;AAAA,MAClC,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAS;AAAA,MAC9B;AAAA,KACD,CAAA;AACD,IAAA,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,UAAU,WAAA,EAAa,KAAA,CAAM,WAAW,QAAA,EAAS;AAAA,EAC/E;AAAA;AAAA,EAGA,OAAA,CAAQ,MAAA,GAAgC,EAAC,EAAG,OAAoB,IAAA,EAA+B;AAC7F,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,EAAA;AACpC,IAAA,OAAO,UAAA,CAAqB,CAAC,UAAA,KAAe,IAAA,CAAK,IAAA,CAAK,EAAE,UAAA,EAAY,QAAA,EAAS,EAAG,IAAI,CAAC,CAAA;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAA,CAAK,IAAA,GAAoB,IAAA,EAA2B;AACxD,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,OAAA,CAAoB;AAAA,MACvC,MAAA,EAAQ,KAAA;AAAA,MACR,IAAA,EAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,eAAA,CAAA;AAAA,MAClC;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAA,CACJ,UAAA,EACA,SAAqD,EAAC,EACtD,OAAoB,IAAA,EACC;AACrB,IAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,EAAA;AACpC,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,OAAA,CAAyD;AAAA,MAC/F,MAAA,EAAQ,KAAA;AAAA,MACR,MAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,eAAe,UAAU,CAAA,YAAA,CAAA;AAAA,MAC3D,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAS;AAAA,MAC9B;AAAA,KACD,CAAA;AACD,IAAA,MAAM,WAAA,GAAc,YACjB,GAAA,CAAI,CAAC,MAAO,CAAA,CAAE,GAAA,EAAK,MAAM,WAAA,EAAY,KAAM,aAAa,CAAA,CAAE,GAAA,CAAI,KAAK,MAAU,CAAA,CAC7E,OAAO,CAAC,EAAA,KAAqB,OAAA,CAAQ,EAAE,CAAC,CAAA;AAC3C,IAAA,IAAI,WAAA,CAAY,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AACtC,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,WAAA,EAAa,IAAI,IAAI,CAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,UAAA,CACJ,UAAA,EACA,SAAqD,EAAC,EACtD,OAAoB,IAAA,EACc;AAClC,IAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,EAAA;AACpC,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,OAAA,CAAyD;AAAA,MAC/F,MAAA,EAAQ,KAAA;AAAA,MACR,MAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,eAAe,UAAU,CAAA,YAAA,CAAA;AAAA,MAC3D,KAAA,EAAO,EAAE,UAAA,EAAY,QAAA,EAAS;AAAA,MAC9B;AAAA,KACD,CAAA;AACD,IAAA,MAAM,WAAA,GAAc,YAAY,MAAA,KAAW,QAAA;AAC3C,IAAA,MAAM,UAAA,GAAa,YAChB,GAAA,CAAI,CAAC,MAAO,CAAA,CAAE,GAAA,EAAK,MAAM,WAAA,EAAY,KAAM,YAAY,CAAA,CAAE,GAAA,CAAI,KAAK,MAAU,CAAA,CAC5E,OAAO,CAAC,EAAA,KAAqB,OAAA,CAAQ,EAAE,CAAC,CAAA;AAC3C,IAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,MAAA,OAAO,EAAE,KAAA,EAAO,EAAC,EAAG,UAAA,EAAY,UAAU,WAAA,EAAY;AAAA,IACxD;AACA,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,OAAA,CAAmB;AAAA,MACnD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,SAAA,EAAY,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,gBAAA,CAAA;AAAA,MACjC,KAAA,EAAO,EAAE,QAAA,EAAU,UAAA,CAAW,MAAA,EAAO;AAAA,MACrC,IAAA;AAAA,MACA,IAAA,EAAM,EAAE,CAAA,EAAG,CAAA,IAAA,EAAO,WAAW,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAI,KAC3C,CAAA;AACD,IAAA,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,WAAA,EAAY;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAA,CACJ,GAAA,EACA,UAAkC,EAAC,EACnC,OAAoB,IAAA,EACC;AACrB,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAC9B,IAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,GAAA;AACvC,IAAA,MAAM,SAAqB,EAAC;AAC5B,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,SAAA,EAAW;AAC9C,MAAA,MAAA,CAAO,KAAK,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,SAAS,CAAC,CAAA;AAAA,IACzC;AACA,IAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,GAAA;AAAA,MAC1B,MAAA,CAAO,GAAA;AAAA,QAAI,CAAC,KAAA,KACV,IAAA,CAAK,GAAA,CAAI,KAAK,OAAA,CAAoB;AAAA,UAChC,MAAA,EAAQ,MAAA;AAAA,UACR,IAAA,EAAM,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,kBAAA,CAAA;AAAA,UAClC,KAAA,EAAO,EAAE,QAAA,EAAU,KAAA,CAAM,MAAA,EAAO;AAAA,UAChC,IAAA;AAAA,UACA,IAAA,EAAM,EAAE,CAAA,EAAG,CAAA,IAAA,EAAO,MAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAI,SACtC;AAAA;AACH,KACF;AACA,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB;AACF","file":"category.cjs","sourcesContent":["import type { HttpClient } from \"./http\";\nimport type { TokenProvider, AuthContext } from \"./auth\";\nimport type { Logger } from \"./logger\";\n\n/** Shared dependencies every service facade receives. */\nexport interface ClientContext {\n tenant: string;\n http: HttpClient;\n tokenProvider: TokenProvider;\n logger: Logger;\n}\n\n/**\n * A cursor-paged collection — `pageNumber`/`pageSize` indexing with a\n * `hasNextPage` signal driven by the source page being full. Used by all\n * paginated services and hooks across the SDK.\n */\nexport interface PaginatedItems<T> {\n items: T[];\n pageNumber: number;\n pageSize: number;\n hasNextPage: boolean;\n}\n\n/** Default `AuthContext` applied by a service when the caller passes none. */\nexport type DefaultAuth = AuthContext | undefined;\n\n/**\n * Async-iterates every item across pages of a `PaginatedItems<T>` source.\n * Stops when the source reports `hasNextPage: false`.\n *\n * @param fetchPage - given a 1-based page number, returns the page.\n * @param start - first page to fetch (default `1`).\n */\nexport async function* iterateAll<T>(\n fetchPage: (pageNumber: number) => Promise<PaginatedItems<T>>,\n start = 1,\n): AsyncIterable<T> {\n let p = start;\n for (;;) {\n const page = await fetchPage(p);\n for (const it of page.items) yield it;\n if (!page.hasNextPage) return;\n p += 1;\n }\n}\n\n","import type { ClientContext, PaginatedItems } from \"../core/context\";\nimport { iterateAll } from \"../core/context\";\nimport type { AuthContext } from \"../core/auth\";\nimport type { Product } from \"./product\";\nimport type { Category as GeneratedCategory, CategoryTree } from \"../generated/category\";\n\nconst ANON: AuthContext = { kind: \"anonymous\" };\n\n/** A category as returned by the Category service (all generated fields). */\nexport type Category = GeneratedCategory;\n\n/** The category tree as returned by the Category service. */\nexport type CategoryNode = CategoryTree;\n\n/** Category reads. Default auth: anonymous. */\nexport class CategoryService {\n constructor(private readonly ctx: ClientContext) {}\n\n /** Fetches one category by id. */\n async get(categoryId: string, auth: AuthContext = ANON): Promise<Category> {\n return this.ctx.http.request<Category>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}`,\n auth,\n });\n }\n\n /** One page of categories. */\n async list(\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Category>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const items = await this.ctx.http.request<Category[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories`,\n query: { pageNumber, pageSize },\n auth,\n });\n return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };\n }\n\n /** Async-iterates every category across pages. */\n listAll(params: { pageSize?: number } = {}, auth: AuthContext = ANON): AsyncIterable<Category> {\n const pageSize = params.pageSize ?? 50;\n return iterateAll<Category>((pageNumber) => this.list({ pageNumber, pageSize }, auth));\n }\n\n /**\n * The catalogue's **root categories** — the published category trees\n * (`GET /category-trees`). Use these for top-level storefront navigation;\n * drill into a node's children with {@link subcategories}.\n */\n async tree(auth: AuthContext = ANON): Promise<Category[]> {\n return this.ctx.http.request<Category[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/category-trees`,\n auth,\n });\n }\n\n /**\n * Direct child categories of a category (for hierarchy drill-down). Mirrors\n * {@link productsIn}: reads the category's **assignments** and keeps the\n * `CATEGORY` references, resolving them to full categories. Returns an empty\n * array when the category has no child categories.\n */\n async subcategories(\n categoryId: string,\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<Category[]> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const assignments = await this.ctx.http.request<Array<{ ref?: { id?: string; type?: string } }>>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,\n query: { pageNumber, pageSize },\n auth,\n });\n const categoryIds = assignments\n .map((a) => (a.ref?.type?.toUpperCase() === \"CATEGORY\" ? a.ref.id : undefined))\n .filter((id): id is string => Boolean(id));\n if (categoryIds.length === 0) return [];\n return this.searchByIds(categoryIds, {}, auth);\n }\n\n /**\n * One page of products in a category. The category service exposes products\n * as **assignments** (`/categories/{id}/assignments`) — references, not full\n * products — so this fetches a page of assignments, keeps the `PRODUCT`\n * references, and resolves them to full products via `/products/search`.\n * `hasNextPage` reflects the assignments page (the source of truth for\n * pagination).\n */\n async productsIn(\n categoryId: string,\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Product>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const assignments = await this.ctx.http.request<Array<{ ref?: { id?: string; type?: string } }>>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,\n query: { pageNumber, pageSize },\n auth,\n });\n const hasNextPage = assignments.length === pageSize;\n const productIds = assignments\n .map((a) => (a.ref?.type?.toUpperCase() === \"PRODUCT\" ? a.ref.id : undefined))\n .filter((id): id is string => Boolean(id));\n if (productIds.length === 0) {\n return { items: [], pageNumber, pageSize, hasNextPage };\n }\n const items = await this.ctx.http.request<Product[]>({\n method: \"POST\",\n path: `/product/${this.ctx.tenant}/products/search`,\n query: { pageSize: productIds.length },\n auth,\n body: { q: `id:(${productIds.join(\",\")})` },\n });\n return { items, pageNumber, pageSize, hasNextPage };\n }\n\n /**\n * Bulk fetch by id. POSTs `/categories/search` with `q=\"id:(id1,id2,…)\"`,\n * chunking when the list is larger than `options.chunkSize` (default\n * 100). An empty list short-circuits with no HTTP call. **Order is not\n * guaranteed** across chunks — re-index by `id` if order matters.\n */\n async searchByIds(\n ids: string[],\n options: { chunkSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<Category[]> {\n if (ids.length === 0) return [];\n const chunkSize = options.chunkSize ?? 100;\n const chunks: string[][] = [];\n for (let i = 0; i < ids.length; i += chunkSize) {\n chunks.push(ids.slice(i, i + chunkSize));\n }\n const pages = await Promise.all(\n chunks.map((chunk) =>\n this.ctx.http.request<Category[]>({\n method: \"POST\",\n path: `/category/${this.ctx.tenant}/categories/search`,\n query: { pageSize: chunk.length },\n auth,\n body: { q: `id:(${chunk.join(\",\")})` },\n }),\n ),\n );\n return pages.flat();\n }\n}\n"]}
@@ -292,9 +292,30 @@ declare class CategoryService {
292
292
  listAll(params?: {
293
293
  pageSize?: number;
294
294
  }, auth?: AuthContext): AsyncIterable<Category>;
295
- /** Fetches the category tree, optionally rooted at `rootId`. */
296
- tree(rootId?: string, auth?: AuthContext): Promise<CategoryNode>;
297
- /** One page of products in a category. */
295
+ /**
296
+ * The catalogue's **root categories** — the published category trees
297
+ * (`GET /category-trees`). Use these for top-level storefront navigation;
298
+ * drill into a node's children with {@link subcategories}.
299
+ */
300
+ tree(auth?: AuthContext): Promise<Category[]>;
301
+ /**
302
+ * Direct child categories of a category (for hierarchy drill-down). Mirrors
303
+ * {@link productsIn}: reads the category's **assignments** and keeps the
304
+ * `CATEGORY` references, resolving them to full categories. Returns an empty
305
+ * array when the category has no child categories.
306
+ */
307
+ subcategories(categoryId: string, params?: {
308
+ pageNumber?: number;
309
+ pageSize?: number;
310
+ }, auth?: AuthContext): Promise<Category[]>;
311
+ /**
312
+ * One page of products in a category. The category service exposes products
313
+ * as **assignments** (`/categories/{id}/assignments`) — references, not full
314
+ * products — so this fetches a page of assignments, keeps the `PRODUCT`
315
+ * references, and resolves them to full products via `/products/search`.
316
+ * `hasNextPage` reflects the assignments page (the source of truth for
317
+ * pagination).
318
+ */
298
319
  productsIn(categoryId: string, params?: {
299
320
  pageNumber?: number;
300
321
  pageSize?: number;
@@ -292,9 +292,30 @@ declare class CategoryService {
292
292
  listAll(params?: {
293
293
  pageSize?: number;
294
294
  }, auth?: AuthContext): AsyncIterable<Category>;
295
- /** Fetches the category tree, optionally rooted at `rootId`. */
296
- tree(rootId?: string, auth?: AuthContext): Promise<CategoryNode>;
297
- /** One page of products in a category. */
295
+ /**
296
+ * The catalogue's **root categories** — the published category trees
297
+ * (`GET /category-trees`). Use these for top-level storefront navigation;
298
+ * drill into a node's children with {@link subcategories}.
299
+ */
300
+ tree(auth?: AuthContext): Promise<Category[]>;
301
+ /**
302
+ * Direct child categories of a category (for hierarchy drill-down). Mirrors
303
+ * {@link productsIn}: reads the category's **assignments** and keeps the
304
+ * `CATEGORY` references, resolving them to full categories. Returns an empty
305
+ * array when the category has no child categories.
306
+ */
307
+ subcategories(categoryId: string, params?: {
308
+ pageNumber?: number;
309
+ pageSize?: number;
310
+ }, auth?: AuthContext): Promise<Category[]>;
311
+ /**
312
+ * One page of products in a category. The category service exposes products
313
+ * as **assignments** (`/categories/{id}/assignments`) — references, not full
314
+ * products — so this fetches a page of assignments, keeps the `PRODUCT`
315
+ * references, and resolves them to full products via `/products/search`.
316
+ * `hasNextPage` reflects the assignments page (the source of truth for
317
+ * pagination).
318
+ */
298
319
  productsIn(categoryId: string, params?: {
299
320
  pageNumber?: number;
300
321
  pageSize?: number;
package/dist/category.js CHANGED
@@ -1,4 +1,4 @@
1
- export { CategoryService } from './chunk-4BJUCCKJ.js';
1
+ export { CategoryService } from './chunk-AUVJ5V47.js';
2
2
  import './chunk-GWJ2U2CP.js';
3
3
  //# sourceMappingURL=category.js.map
4
4
  //# sourceMappingURL=category.js.map
@@ -32,26 +32,67 @@ var CategoryService = class {
32
32
  const pageSize = params.pageSize ?? 50;
33
33
  return iterateAll((pageNumber) => this.list({ pageNumber, pageSize }, auth));
34
34
  }
35
- /** Fetches the category tree, optionally rooted at `rootId`. */
36
- async tree(rootId, auth = ANON) {
35
+ /**
36
+ * The catalogue's **root categories** — the published category trees
37
+ * (`GET /category-trees`). Use these for top-level storefront navigation;
38
+ * drill into a node's children with {@link subcategories}.
39
+ */
40
+ async tree(auth = ANON) {
37
41
  return this.ctx.http.request({
38
42
  method: "GET",
39
- path: `/category/${this.ctx.tenant}/categories/tree`,
40
- query: rootId ? { rootId } : {},
43
+ path: `/category/${this.ctx.tenant}/category-trees`,
44
+ auth
45
+ });
46
+ }
47
+ /**
48
+ * Direct child categories of a category (for hierarchy drill-down). Mirrors
49
+ * {@link productsIn}: reads the category's **assignments** and keeps the
50
+ * `CATEGORY` references, resolving them to full categories. Returns an empty
51
+ * array when the category has no child categories.
52
+ */
53
+ async subcategories(categoryId, params = {}, auth = ANON) {
54
+ const pageNumber = params.pageNumber ?? 1;
55
+ const pageSize = params.pageSize ?? 50;
56
+ const assignments = await this.ctx.http.request({
57
+ method: "GET",
58
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
59
+ query: { pageNumber, pageSize },
41
60
  auth
42
61
  });
62
+ const categoryIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "CATEGORY" ? a.ref.id : void 0).filter((id) => Boolean(id));
63
+ if (categoryIds.length === 0) return [];
64
+ return this.searchByIds(categoryIds, {}, auth);
43
65
  }
44
- /** One page of products in a category. */
66
+ /**
67
+ * One page of products in a category. The category service exposes products
68
+ * as **assignments** (`/categories/{id}/assignments`) — references, not full
69
+ * products — so this fetches a page of assignments, keeps the `PRODUCT`
70
+ * references, and resolves them to full products via `/products/search`.
71
+ * `hasNextPage` reflects the assignments page (the source of truth for
72
+ * pagination).
73
+ */
45
74
  async productsIn(categoryId, params = {}, auth = ANON) {
46
75
  const pageNumber = params.pageNumber ?? 1;
47
76
  const pageSize = params.pageSize ?? 50;
48
- const items = await this.ctx.http.request({
77
+ const assignments = await this.ctx.http.request({
49
78
  method: "GET",
50
- path: `/category/${this.ctx.tenant}/categories/${categoryId}/products`,
79
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
51
80
  query: { pageNumber, pageSize },
52
81
  auth
53
82
  });
54
- return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
83
+ const hasNextPage = assignments.length === pageSize;
84
+ const productIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "PRODUCT" ? a.ref.id : void 0).filter((id) => Boolean(id));
85
+ if (productIds.length === 0) {
86
+ return { items: [], pageNumber, pageSize, hasNextPage };
87
+ }
88
+ const items = await this.ctx.http.request({
89
+ method: "POST",
90
+ path: `/product/${this.ctx.tenant}/products/search`,
91
+ query: { pageSize: productIds.length },
92
+ auth,
93
+ body: { q: `id:(${productIds.join(",")})` }
94
+ });
95
+ return { items, pageNumber, pageSize, hasNextPage };
55
96
  }
56
97
  /**
57
98
  * Bulk fetch by id. POSTs `/categories/search` with `q="id:(id1,id2,…)"`,
@@ -82,5 +123,5 @@ var CategoryService = class {
82
123
  };
83
124
 
84
125
  export { CategoryService };
85
- //# sourceMappingURL=chunk-4BJUCCKJ.js.map
86
- //# sourceMappingURL=chunk-4BJUCCKJ.js.map
126
+ //# sourceMappingURL=chunk-AUVJ5V47.js.map
127
+ //# sourceMappingURL=chunk-AUVJ5V47.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/category.ts"],"names":[],"mappings":"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","file":"chunk-AUVJ5V47.js","sourcesContent":["import type { ClientContext, PaginatedItems } from \"../core/context\";\nimport { iterateAll } from \"../core/context\";\nimport type { AuthContext } from \"../core/auth\";\nimport type { Product } from \"./product\";\nimport type { Category as GeneratedCategory, CategoryTree } from \"../generated/category\";\n\nconst ANON: AuthContext = { kind: \"anonymous\" };\n\n/** A category as returned by the Category service (all generated fields). */\nexport type Category = GeneratedCategory;\n\n/** The category tree as returned by the Category service. */\nexport type CategoryNode = CategoryTree;\n\n/** Category reads. Default auth: anonymous. */\nexport class CategoryService {\n constructor(private readonly ctx: ClientContext) {}\n\n /** Fetches one category by id. */\n async get(categoryId: string, auth: AuthContext = ANON): Promise<Category> {\n return this.ctx.http.request<Category>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}`,\n auth,\n });\n }\n\n /** One page of categories. */\n async list(\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Category>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const items = await this.ctx.http.request<Category[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories`,\n query: { pageNumber, pageSize },\n auth,\n });\n return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };\n }\n\n /** Async-iterates every category across pages. */\n listAll(params: { pageSize?: number } = {}, auth: AuthContext = ANON): AsyncIterable<Category> {\n const pageSize = params.pageSize ?? 50;\n return iterateAll<Category>((pageNumber) => this.list({ pageNumber, pageSize }, auth));\n }\n\n /**\n * The catalogue's **root categories** — the published category trees\n * (`GET /category-trees`). Use these for top-level storefront navigation;\n * drill into a node's children with {@link subcategories}.\n */\n async tree(auth: AuthContext = ANON): Promise<Category[]> {\n return this.ctx.http.request<Category[]>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/category-trees`,\n auth,\n });\n }\n\n /**\n * Direct child categories of a category (for hierarchy drill-down). Mirrors\n * {@link productsIn}: reads the category's **assignments** and keeps the\n * `CATEGORY` references, resolving them to full categories. Returns an empty\n * array when the category has no child categories.\n */\n async subcategories(\n categoryId: string,\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<Category[]> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const assignments = await this.ctx.http.request<Array<{ ref?: { id?: string; type?: string } }>>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,\n query: { pageNumber, pageSize },\n auth,\n });\n const categoryIds = assignments\n .map((a) => (a.ref?.type?.toUpperCase() === \"CATEGORY\" ? a.ref.id : undefined))\n .filter((id): id is string => Boolean(id));\n if (categoryIds.length === 0) return [];\n return this.searchByIds(categoryIds, {}, auth);\n }\n\n /**\n * One page of products in a category. The category service exposes products\n * as **assignments** (`/categories/{id}/assignments`) — references, not full\n * products — so this fetches a page of assignments, keeps the `PRODUCT`\n * references, and resolves them to full products via `/products/search`.\n * `hasNextPage` reflects the assignments page (the source of truth for\n * pagination).\n */\n async productsIn(\n categoryId: string,\n params: { pageNumber?: number; pageSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<PaginatedItems<Product>> {\n const pageNumber = params.pageNumber ?? 1;\n const pageSize = params.pageSize ?? 50;\n const assignments = await this.ctx.http.request<Array<{ ref?: { id?: string; type?: string } }>>({\n method: \"GET\",\n path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,\n query: { pageNumber, pageSize },\n auth,\n });\n const hasNextPage = assignments.length === pageSize;\n const productIds = assignments\n .map((a) => (a.ref?.type?.toUpperCase() === \"PRODUCT\" ? a.ref.id : undefined))\n .filter((id): id is string => Boolean(id));\n if (productIds.length === 0) {\n return { items: [], pageNumber, pageSize, hasNextPage };\n }\n const items = await this.ctx.http.request<Product[]>({\n method: \"POST\",\n path: `/product/${this.ctx.tenant}/products/search`,\n query: { pageSize: productIds.length },\n auth,\n body: { q: `id:(${productIds.join(\",\")})` },\n });\n return { items, pageNumber, pageSize, hasNextPage };\n }\n\n /**\n * Bulk fetch by id. POSTs `/categories/search` with `q=\"id:(id1,id2,…)\"`,\n * chunking when the list is larger than `options.chunkSize` (default\n * 100). An empty list short-circuits with no HTTP call. **Order is not\n * guaranteed** across chunks — re-index by `id` if order matters.\n */\n async searchByIds(\n ids: string[],\n options: { chunkSize?: number } = {},\n auth: AuthContext = ANON,\n ): Promise<Category[]> {\n if (ids.length === 0) return [];\n const chunkSize = options.chunkSize ?? 100;\n const chunks: string[][] = [];\n for (let i = 0; i < ids.length; i += chunkSize) {\n chunks.push(ids.slice(i, i + chunkSize));\n }\n const pages = await Promise.all(\n chunks.map((chunk) =>\n this.ctx.http.request<Category[]>({\n method: \"POST\",\n path: `/category/${this.ctx.tenant}/categories/search`,\n query: { pageSize: chunk.length },\n auth,\n body: { q: `id:(${chunk.join(\",\")})` },\n }),\n ),\n );\n return pages.flat();\n }\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1124,26 +1124,67 @@ var CategoryService = class {
1124
1124
  const pageSize = params.pageSize ?? 50;
1125
1125
  return iterateAll((pageNumber) => this.list({ pageNumber, pageSize }, auth2));
1126
1126
  }
1127
- /** Fetches the category tree, optionally rooted at `rootId`. */
1128
- async tree(rootId, auth2 = ANON2) {
1127
+ /**
1128
+ * The catalogue's **root categories** — the published category trees
1129
+ * (`GET /category-trees`). Use these for top-level storefront navigation;
1130
+ * drill into a node's children with {@link subcategories}.
1131
+ */
1132
+ async tree(auth2 = ANON2) {
1129
1133
  return this.ctx.http.request({
1130
1134
  method: "GET",
1131
- path: `/category/${this.ctx.tenant}/categories/tree`,
1132
- query: rootId ? { rootId } : {},
1135
+ path: `/category/${this.ctx.tenant}/category-trees`,
1136
+ auth: auth2
1137
+ });
1138
+ }
1139
+ /**
1140
+ * Direct child categories of a category (for hierarchy drill-down). Mirrors
1141
+ * {@link productsIn}: reads the category's **assignments** and keeps the
1142
+ * `CATEGORY` references, resolving them to full categories. Returns an empty
1143
+ * array when the category has no child categories.
1144
+ */
1145
+ async subcategories(categoryId, params = {}, auth2 = ANON2) {
1146
+ const pageNumber = params.pageNumber ?? 1;
1147
+ const pageSize = params.pageSize ?? 50;
1148
+ const assignments = await this.ctx.http.request({
1149
+ method: "GET",
1150
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
1151
+ query: { pageNumber, pageSize },
1133
1152
  auth: auth2
1134
1153
  });
1154
+ const categoryIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "CATEGORY" ? a.ref.id : void 0).filter((id) => Boolean(id));
1155
+ if (categoryIds.length === 0) return [];
1156
+ return this.searchByIds(categoryIds, {}, auth2);
1135
1157
  }
1136
- /** One page of products in a category. */
1158
+ /**
1159
+ * One page of products in a category. The category service exposes products
1160
+ * as **assignments** (`/categories/{id}/assignments`) — references, not full
1161
+ * products — so this fetches a page of assignments, keeps the `PRODUCT`
1162
+ * references, and resolves them to full products via `/products/search`.
1163
+ * `hasNextPage` reflects the assignments page (the source of truth for
1164
+ * pagination).
1165
+ */
1137
1166
  async productsIn(categoryId, params = {}, auth2 = ANON2) {
1138
1167
  const pageNumber = params.pageNumber ?? 1;
1139
1168
  const pageSize = params.pageSize ?? 50;
1140
- const items = await this.ctx.http.request({
1169
+ const assignments = await this.ctx.http.request({
1141
1170
  method: "GET",
1142
- path: `/category/${this.ctx.tenant}/categories/${categoryId}/products`,
1171
+ path: `/category/${this.ctx.tenant}/categories/${categoryId}/assignments`,
1143
1172
  query: { pageNumber, pageSize },
1144
1173
  auth: auth2
1145
1174
  });
1146
- return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
1175
+ const hasNextPage = assignments.length === pageSize;
1176
+ const productIds = assignments.map((a) => a.ref?.type?.toUpperCase() === "PRODUCT" ? a.ref.id : void 0).filter((id) => Boolean(id));
1177
+ if (productIds.length === 0) {
1178
+ return { items: [], pageNumber, pageSize, hasNextPage };
1179
+ }
1180
+ const items = await this.ctx.http.request({
1181
+ method: "POST",
1182
+ path: `/product/${this.ctx.tenant}/products/search`,
1183
+ query: { pageSize: productIds.length },
1184
+ auth: auth2,
1185
+ body: { q: `id:(${productIds.join(",")})` }
1186
+ });
1187
+ return { items, pageNumber, pageSize, hasNextPage };
1147
1188
  }
1148
1189
  /**
1149
1190
  * Bulk fetch by id. POSTs `/categories/search` with `q="id:(id1,id2,…)"`,
@@ -4973,7 +5014,7 @@ var ApprovalService = class {
4973
5014
  };
4974
5015
 
4975
5016
  // package.json
4976
- var version = "2.6.0";
5017
+ var version = "2.7.0";
4977
5018
 
4978
5019
  // src/version.ts
4979
5020
  var SDK_VERSION = version;