@minipim/sdk 0.4.1 → 0.6.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/README.md CHANGED
@@ -130,6 +130,43 @@ const all = await collectAll<Product>(pim, '/v1/products');
130
130
 
131
131
  Endpoints that return a **plain array** instead of the envelope (`/v1/categories` without `?limit=`, `/v1/attributes`, `/v1/products/{id}/variants`) are handled too (v0.3.0+): the array is treated as the one-and-only page, so `collectAll` works uniformly across every list endpoint.
132
132
 
133
+ ## Listing by category, and by price (v0.5.0+)
134
+
135
+ Two things storefronts almost always need, and previously had to do in memory.
136
+
137
+ **Category subtrees.** `categoryId` on its own is **self-only** — it matches products filed directly against that category. Catalogs commonly assign products to leaf categories, so a parent category can legitimately return an empty page. Add `includeDescendants` for the whole subtree:
138
+
139
+ ```ts
140
+ // Everything anywhere under "Backdrops", in ONE paginated query.
141
+ const { data } = await pim.GET('/v1/products', {
142
+ query: { categoryId, includeDescendants: true, limit: 50 },
143
+ });
144
+ ```
145
+
146
+ Don't fetch `/v1/categories`, resolve descendants yourself and issue one request per id — this is a single round trip and it paginates as one result set.
147
+
148
+ **Sorting and filtering by price.** There is no `sortBy: 'price'`, because a catalog's price attribute code is its own data (`price`, `msrp`, `list_price`, …). Name it:
149
+
150
+ ```ts
151
+ // Cheapest first
152
+ await pim.GET('/v1/products', {
153
+ query: { sortBy: 'attribute', sortAttribute: 'price', sortDir: 'asc' },
154
+ });
155
+
156
+ // $10.00–$50.00 — money bounds are INTEGER CENTS
157
+ await pim.GET('/v1/products', {
158
+ query: { filterAttribute: 'price', filterMin: 1000, filterMax: 5000 },
159
+ });
160
+ ```
161
+
162
+ - Works on `money`, `number` and `decimal` attributes. `measurement` is refused — its values carry a unit, so ordering raw amounts would rank 5 g above 2 kg.
163
+ - For `money`, bounds and ordering use `amount_cents`. **`filterMin: 1000` is $10.00.** No currency conversion — mixed-currency catalogs compare by number.
164
+ - The value read is the one at the **default scope** (no locale, no channel). Products with no value sort **last in both directions** and are excluded by either bound: no price, not a price of zero.
165
+ - An unknown code, or one of a non-orderable type, is a **422 naming the problem**. It never degrades to name ordering, so you can't get a plausible page that isn't sorted the way you asked.
166
+ - `sortAttribute` and `filterAttribute` are independent; set both for "cheapest first, within a budget".
167
+
168
+ Needs API **0.9.0+**. Check `GET /healthz`.
169
+
133
170
  ## Attribute helpers
134
171
 
135
172
  Attribute values are `unknown` and keyed by `(locale, channel)`. List responses return the raw `{ code: [{ locale, channel, value }] }` shape (only product *detail* with `?locale=&channel=` returns a flat `resolvedAttributes`). The SDK ships the flatten + coercion helpers so you don't reimplement them:
package/dist/index.cjs CHANGED
@@ -80,9 +80,7 @@ async function* paginate(client, path, opts = {}) {
80
80
  params: { query: { ...opts.query ?? {}, limit: pageSize, offset } }
81
81
  });
82
82
  if (error || !data) {
83
- throw new Error(
84
- `paginate ${path} failed at offset ${offset} (HTTP ${response?.status})`
85
- );
83
+ throw new Error(`paginate ${path} failed at offset ${offset} (HTTP ${response?.status})`);
86
84
  }
87
85
  if (Array.isArray(data)) {
88
86
  for (const item of data) yield item;
package/dist/index.d.cts CHANGED
@@ -77,9 +77,13 @@ type MinipimClient = Client<paths>;
77
77
  declare function createMinipimClient(opts: CreateMinipimClientOptions): MinipimClient;
78
78
 
79
79
  /**
80
- * Generic pagination helper. Every MiniPim list endpoint returns
81
- * `{ data, limit, offset, hasMore }`; this walks the pages so consumers
82
- * don't hand-roll the `hasMore` loop. Yields one item at a time.
80
+ * Generic pagination helper. MiniPim list endpoints return
81
+ * `{ data, limit, offset }`, and **only `/v1/products` also returns
82
+ * `hasMore`** so this walks the pages by trusting `hasMore` when it is
83
+ * present and falling back to a short-page check when it isn't. That is the
84
+ * whole reason to use this instead of a hand-rolled `while (hasMore)` loop,
85
+ * which reads exactly one page from every other endpoint and stops. Yields
86
+ * one item at a time.
83
87
  *
84
88
  * Typed loosely on purpose — openapi-fetch's per-path generics don't
85
89
  * compose into a single reusable signature without a lot of conditional-
package/dist/index.d.ts CHANGED
@@ -77,9 +77,13 @@ type MinipimClient = Client<paths>;
77
77
  declare function createMinipimClient(opts: CreateMinipimClientOptions): MinipimClient;
78
78
 
79
79
  /**
80
- * Generic pagination helper. Every MiniPim list endpoint returns
81
- * `{ data, limit, offset, hasMore }`; this walks the pages so consumers
82
- * don't hand-roll the `hasMore` loop. Yields one item at a time.
80
+ * Generic pagination helper. MiniPim list endpoints return
81
+ * `{ data, limit, offset }`, and **only `/v1/products` also returns
82
+ * `hasMore`** so this walks the pages by trusting `hasMore` when it is
83
+ * present and falling back to a short-page check when it isn't. That is the
84
+ * whole reason to use this instead of a hand-rolled `while (hasMore)` loop,
85
+ * which reads exactly one page from every other endpoint and stops. Yields
86
+ * one item at a time.
83
87
  *
84
88
  * Typed loosely on purpose — openapi-fetch's per-path generics don't
85
89
  * compose into a single reusable signature without a lot of conditional-
package/dist/index.js CHANGED
@@ -28,9 +28,7 @@ async function* paginate(client, path, opts = {}) {
28
28
  params: { query: { ...opts.query ?? {}, limit: pageSize, offset } }
29
29
  });
30
30
  if (error || !data) {
31
- throw new Error(
32
- `paginate ${path} failed at offset ${offset} (HTTP ${response?.status})`
33
- );
31
+ throw new Error(`paginate ${path} failed at offset ${offset} (HTTP ${response?.status})`);
34
32
  }
35
33
  if (Array.isArray(data)) {
36
34
  for (const item of data) yield item;